Распределенный рабочий процесс

Предположим, что Алиса начала новый проект с git репозиторием в директории /home/alice/project, и что Боб, у которого есть своя домашняя директории на той же машине, хочеть помочь с проектом.

Боб начнет работу с:

$ git clone /home/alice/project myrepo

Это создаст новую директорию "myrepo" содержащую копию репозитория Алисы. Клон эквивалентен в основании оригиналу проекта, и обладает своей собственной копией истории оригинального проекта.

Затем Боб вносит некоторые изменения и выполняет коммит:

(edit files)
$ git commit -a
(repeat as necessary)

Когда он готов, он говорит Алисе выполнить pull изменений из репозитория в /home/bob/myrepo. Она совершает это выполнив:

$ cd /home/alice/project
$ git pull /home/bob/myrepo master

Это сливает изменения из ветки "master" Боба в активную ветку Алисы. Если Алиса внесла изменения в свою ветку в тоже самое время, тогда возможно ей придется вручную исправить конфликты если таковые появятся. (Заметьте аргумент "master" в команде выше в действительности не требуется, так как он будет использоваться по умолчанию.)

Команда "pull" таким образом выполняет два действия: она вытягивает изменения из удаленного репозитория, и сливает их в активную ветку.

Когда вы работаете в маленькой группе, это обычная практика работать с одим и тем же репозиторием снова и снова. Определив сокращение 'remote(удаленный)' репозитория вы можете упростить себе работу:

$ git remote add bob /home/bob/myrepo

С этим Алиса, может выполнять первую операцию одной командой "git fetch" без сливания их в свою ветку:

$ git fetch bob

В отличие от полной формы, когда Алиса извлекает изменения из удаленного репозитория Боба используя сокращение с помощью git remote, то что было вытянуто, хранится в удаленной отслеживающей ветке, в нашем случае это bob/master. Так после этого:

$ git log -p master..bob/master

покажет список всех изменений которые Боб сделал с того времени как он ответвился от ветки "master" Алисы.

После проверки этих изменений, Алиса может слить изменения в свою ветку master:

$ git merge bob/master

Этот merge может также быть выполнено с помощью 'вытягивания из ее собственной удаленной отслеживаемой ветки', слею.образом:

$ git pull . remotes/bob/master

Заметьте что команда git pull всегда сливает в активную ветку, не обращая внимания на другие аргументы в командной строке.

Позже Боб, может обновить свой репозиторий включив последние обновления Алисы, выполнив

$ git pull

Заметьте что ему не требуется указывать путь к репозиторию Алисы; когда Боб клонирует репозиторий Алисы, git хранит местоположение ее репозитория в настройках репозитория, и это расположние используется для извлечения:

$ git config --get remote.origin.url
/home/alice/project

(Полные настойки созданы командой git-clone. Их можно просмотреть с помощью "git config -l", страница справочника git config описывает значения каждого параметра.)

Git также держит чистую копию ветки "master" Алисы под именем "origin/master":

$ git branch -r
  origin/master

Ecли Боб позже решит работать с другой машины, он все еще может выполнить клонирование и вытянуть данные используя ssh протокол:

$ git clone alice.org:/home/alice/project myrepo

Кроме того, у git есть свой родной протокол, или можно использовать rsync или http; просмотрите git pull чтобы получить больше подробностей.

Git может также быть использован в режиме CVS, центрального репозитория в который различные пользователи добавляют изменения; просмотрите git push и gitcvs-migration.

Публичные git репозитории

Другой способ передать изменения в проект это попросить мантейнера проекта вытянуть изменения из вашего репозитория используя git pull. Это способ получить обновления из "main" репозитория, но он хорошо работает и в другом направлении.

Если вы и мантейнер оба имеете учетные записи на одной машине, тогда вы можете просто вытянуть изменения из репозиториев друг друга напрямую; команды которые принимают URLы репозиториев как аргумент также примут имя локальной директории:

$ git clone /path/to/repository
$ git pull /path/to/other/repository

или ssh URL:

$ git clone ssh://yourhost/~you/repository

Для проектов с малым количеством разработчиков, или для синхронизации нескольких частных репозиториев, это именно то что вам нужно.

Как бы так ни было, более общий способ сделать это открыть отдельный публичный репозиторий (обычно на отдельной машине) для других, из которого они могли бы вытягивать изменения. Обычно это более удобный способ, и он позволяет вам отделить личную работу от публичной ее части.

Вы продолжите делать вашу обычную работу в вашем личном репозитории, но периодически будете вставлять изменения из вашего личного репозитория в ваш публичный репозиторий, позволяя другим разработчикам вытягивать из этого репозитория. Так поток изменений, в ситуации где есть один разработчик с публичным репозиторием, выглядит так:

                        you push
  your personal repo ------------------> your public repo
    ^                                     |
    |                                     |
    | you pull                            | they pull
    |                                     |
    |                                     |
        |               they push             V
  their public repo <------------------- their repo

Внесение изменений в публичный репозиторий

Заметьте что экспорт через http или git позволяет другим мантейнерам получать ваши изменения, но у них нет доступа на запись. Для этого вам нужно обновить публичный репозиторий и включить туда последние обновления созданные в вашем частном репозитории.

Простейший способ сделать это - использовать git push и ssh; чтобы обновить удаленную ветку по имени "master" с последним состоянием вашей ветки под именем "master", выполните

$ git push ssh://yourserver.com/~you/proj.git master:master

или просто

$ git push ssh://yourserver.com/~you/proj.git master

Как и с git-fetch, git-push будет жаловаться если это не результат fast forward; просмотрите след.секцию чтобы узнать как решить эту проблему.

Заметьте что цель "push" обычно пустой репозиторий. Вы также можете выполнить push в репозиторий который имеет извлеченное рабочее дерево, но рабочее дерево не обновится выполнением push. Этот способ ведет к неопределенным результатам если ветка в которую вы выполняете push - активная извлеченная ветка!

Также как и с git-fetch, вы возможно также установите параметры конфигурации для безопасной печати; так например после

$ cat >>.git/config <<EOF
[remote "public-repo"]
    url = ssh://yourserver.com/~you/proj.git
EOF

вы должны быть способны выполнить push выше след.образом

$ git push public-repo master

Просмотрите объяснение remote..url, branch..remote, and remote..push параметры в git config для получения подробностей.

Что делать если выполнение push завершилось неудачей

Если результат выполнения push не будет fast-forward удаленной ветки, то ошибка будет выглядеть так:

error: remote 'refs/heads/master' is not an ancestor of
local  'refs/heads/master'.
Maybe you are not up-to-date and need to pull first?
error: failed to push to 'ssh://yourserver.com/~you/proj.git'

Это может случиться, например если вы:

- использовали `git-reset --hard` чтобы удалить уже опубликованные коммиты или
- использовали `git-commit --amend` чтобы заменить уже опубликованные коммиты или
- использовали `git-rebase` чтобы переопределить любой уже опубликованный коммиты.

Вы также можете заставить git-push выполнить обновление в любом случае если перед именем ветки поставите символ плюс:

$ git push ssh://yourserver.com/~you/proj.git +master

Обычно всякий раз когда голова ветки в публичном репозитории модифицируется, оно модифицируется так чтобы указывать на потомка коммита на который она указывало до этого. Принуждая выполнение push в такой ситуации, вы нарушаете это соглашение.

Тем не менее, это общая практика для разработчиков которым нужен простой способ опубликовать серию патчей, и это допустимый компромис пока другие разработчики предупреждены каким образом вы намереваетесь управлять веткой.

Также возможны такие ситуации когда push завершается неудачно в случае если другие разработчики имеют права на выполнение push в тот же репозиторий. В этом случае правильное решение - это повторить push после первого обновления вашей работы или выполнив pull или выполнив fetch с последующим rebase.; Просмотрите след. секцию и gitcvs-migration чтобы получить больше подробностей.

gitcast:c8-dist-workflow



github logo