Итак, основная идея Git, как и любой распределенной SCM, заключается в том, что мы имеем дело с локальными коммитами в индивидуальных репозитариях разработчиков и с мехнизмами обмена коммитами между репозитариями. Главное преимущество - гибкость (можно вести локальные бранчи с локальными коммитами, не забивая основной репозитарий результатами неудачных или удачных экспериментов), обратная сторона - некоторое увеличение сложности взаимодействия по сравнению с централизованными SCM.
Далее предполагаем, что центральный и всегда доступный репозитарий все же имеется, и разработчики обмениваются коммитами не напрямую друг с другом, а с центральным репозитарием.
Устанавливаем все необходимое и заводим на сервере центральный репозитарий:
# apt-get install git-core # mkdir /home/repo/alpha.git # cd /home/repo/alpha.git # git init --bare --shared=trueРаботать с ним будем по ssh, поэтому создаем для разработчиков учетные записи и добавляем их в группу, во владение которой передаем репозитарий:
# useradd -d /var/empty/ -s /usr/bin/git-shell user1 # useradd -d /var/empty/ -s /usr/bin/git-shell user2 # groupadd alpha # usermod -G alpha user1 # usermod -G alpha user2 # chown -R root:alpha /home/repo/alpha.gitТеперь один из разработчиков может создать локальный репозитарий и сделать в нем несколько коммитов:
[user1@workstation1 ~]$ mkdir alpha [user1@workstation1 ~]$ cd alpha [user1@workstation1 alpha]$ git init [user1@workstation1 alpha]$ git config user.name 'User 1' [user1@workstation1 alpha]$ git config user.email 'user1@workstation1' [user1@workstation1 alpha]$ echo 'line 1' > file [user1@workstation1 alpha]$ git add . [user1@workstation1 alpha]$ git commit -a -m 'add line 1' [user1@workstation1 alpha]$ echo 'line 2' >> file [user1@workstation1 alpha]$ git commit -a -m 'add line 2'Каждый коммит принадлежит одному или нескольким бранчам. Для первого коммита автоматически создается бранч с именем master, в него же по умолчанию попадают следующие коммиты.
Несколько полезных команд:
- git branch - показать список бранчей, выделив текущий, создать, удалить или переименовать бранч
- git status - показать текущее состояние рабочей копии (какие новые файлы появились, а какие были удалены, что закоммитили, а что нет, и т.д.)
- git log - показать историю коммитов, каждый из которых идентифицируется с помощью хеша sha1
- git show - показать подробности последнего коммита или любого коммита по его хешу
- git diff - показать разницу между последним коммитом и рабочей копией или между коммитами
[user1@workstation1 alpha]$ git remote add origin user1@gitserver:/home/repo/alpha.gitИ отправим туда коммиты, принадлежащие локальному бранчу master - они попадут в удаленный бранч с таким же именем:
[user1@workstation1 alpha]$ git push origin masterВ дальнейшем можно будет ограничиться git push, т.к. origin - дефолтное имя удаленного репозитария, а бранч master в нем уже существует. С другой стороны, ничто не мешает явно указывать URL удаленного репозитария и имена локального и удаленного бранчей:
[user1@workstation1 alpha]$ git push user1@gitserver:/home/repo/alpha.git master:masterДля получения коммитов из центрального репозитария в локальный бранч master его нужно было бы создать с параметром --track, однако бранч уже существует, поэтому просто укажем соответствующий ему удаленный бранч в настройках:
$ cat >> .git/config << EOF > [branch "master"] > remote = origin > merge = refs/heads/master > EOFПолучить новые коммиты из центрального репозитария можно так:
[user1@workstation1 alpha]$ git fetch [user1@workstation1 alpha]$ git merge origin/masterили просто:
[user1@workstation1 alpha]$ git pullВ случае конфликтующих изменений операция merge не будет завершена коммитом - в этом случае нужно будет выполнить git commit самостоятельно после разрешения конфликта.
Разумеется новые коммиты могут появиться в центральном репозитарии только после того, как другой разработчик клонирует его, внесет туда какие-либо изменения и отправит их обратно - при этом настраивать свой репозитарий для взаимодействия с удаленным ему уже не потребуется:
[user2@workstation2 ~]$ git clone user2@gitserver:/home/repo/alpha.git [user2@workstation2 ~]$ cd alpha/ [user2@workstation2 alpha]$ git config user.name 'User 1' [user2@workstation2 alpha]$ git config user.email 'user2@workstation2' [user2@workstation2 alpha]$ echo 'line 3' >> file [user2@workstation2 alpha]$ git commit -a -m 'add line 3' [user2@workstation2 alpha]$ git pushТеперь чуть подробнее о том, ради чего все эти мучения - ведь для выполнения аналогичных операций средствами CVS или SVN потребовалось бы меньше операций. Дело в том, что до тех пор, пока мы не отгрузили коммиты в удаленный репозитарий, мы вольны распоряжаться ими как нам вздумается. Например, заведем для экспериментов новый локальный бранч и сделаем в нем еще пару коммитов:
[user1@workstation1 alpha]$ git-checkout -b experimental [user1@workstation1 alpha]$ echo 'line 4' >> file [user1@workstation1 alpha]$ git commit -a -m 'add line 4' [user1@workstation1 alpha]$ echo 'line 5' >> file [user1@workstation1 alpha]$ git commit -a -m 'add line 5'Если какие-то коммиты лучше было бы не делать, можно откатиться к любому заданному коммиту, указав его:
- явно в виде sha1 id - их покажет git log
- по имени тэга - его можно создать для коммита по его sha1 id с помощью git tag
- относительно другого коммита - например, последнему коммиту, на который указывает HEAD, предшествует HEAD^:
[user1@workstation1 alpha]$ git reset --hard HEAD^Также бывают полезны параметр --soft (откатиться, но сохранить содержимое измененных файлов для последующего редактирования) и параметр --amend команды git commit (включить содержимое старого коммита в новый).
Вернемся в бранч master, сделаем в нем еще один коммит и втянем туда результаты экспериментов:
[user1@workstation1 alpha]$ git checkout master [user1@workstation1 alpha]$ subst '/line 1/iline 0' file [user1@workstation1 alpha]$ git commit -a -m 'add line 0' [user1@workstation1 alpha]$ git merge experimentalВместо операции merge, которая создает общий коммит для бранчей, иногда бывает полезно использовать rebase - эта операция переупорядочивает коммиты для того, чтобы сохранить историю линейной. Очень полезно для изучения истории использовать gitk, gitg или qgit - эти инструменты помогут представить описанное более наглядно.
Разумеется, после того, как мы сделали git push, с историей лучше не забавляться - этим мы сильно осложним жизнь тем, кто уже основывает свои новые коммиты на ней. А вот до git push - сколько угодно :)
2 комментария:
Очень полезная статья. Именно с нее у меня началось знакомство с Git и ее возможностями. Спасибо огромное.
Спасибо за статью.
Получилось всё с первого раза.
По поводу описания команд git есть хороший документ http://diseaz.github.com/gitmagic/book.html
Но из этого документа я не понял как создавать публичный репозитарий, а ваша статья помогла.
Отправить комментарий