LXF116:Git

Материал из Linuxformat.

Перейти к: навигация, поиск
Hardcore Linux Проверь себя на крутом проекте для продвинутых пользователей

Содержание

Git: Властвуй над версиями

На что способен создатель Linux по части контроля версий ПО? Он может сделать его и проще, и сложней, считает Дэн Фрост.

Каждый, кто пробовал SVN, CVS или другие основные инструменты контроля версий для резервирования и (попыток) совместной работы, понимает, почему Линус Торвальдс сел и написал свой. Контроль версий часто сводит кодеров с ума – а Git вообще слывет системой, в которой не разобраться без ученой степени. Его запутанность вызвана его же простотой, а его главная цель – облегчить деятельность больших распределенных групп разработчиков. И если подступаться к Git хладнокровно, вы многого от него добьетесь.

Программы для контроля версий традиционно имеют центральный сервер, куда участники разработки сбрасывают контент из своих собственных рабочих окружений, обзываемых «песочницами». Эту модель используют CVS и SVN, две крупнейших открытых системы управления версиями; большая часть ПО, которое вы загружаете с SourceForge, создана в одной из них.

И модель отлично работает. Каждый пользователь берет копию проекта из центрального репозитория и работает с ней, исправляя ошибки или добавляя новые возможности. Закончив работу, он отсылает готовые изменения в центральный репозиторий вместе с сообщением для остальных, поясняющим, что было сделано.

Разобраться в этой модели легко, но она не учитывает одну важную особенность. Открытые проекты поддерживаются многими географически разрозненными разработчиками, которые трудятся над различными функциями в разное время, и нередко в порядке, не поддающемся осмыслению. «Ветвление» [branching] позволяет коду разделиться на несколько конкурирующих версий – одну для обновления пользовательского интерфейса, другую для оптимизации хранения файлов, и, возможно, третью для последней стабильной версии. Тем не менее, весьма раздражает, если ведущий разработчик, который управляет центральным хранилищем, не дает вам ветвь в репозитории для текущего проекта... Тогда берите Git.

SVN упрощает ветвление: вы можете очень быстро создавать новую версию исходников и работать над ней. Git делает проще и веселее – вы создаете ветвь, доступную только в вашем локальном репозитории, и отслеживаете десятки идей, каждую в своей ветви, перед их отправкой в центральный репозиторий.

Приступим

Если Git еще отсутствует в вашей системе, просто выполните apt-get install git или yum install git. Как только Git установится, откройте терминал и наберите git. Вы увидите следующее:

 ~ $ git
 usage: git [--version] [--exec-path[=GIT_EXEC_PATH]] [-p|--
 paginate|--no-pager] [--bare] [--git-dir=GIT_DIR] [--worktree=
 GIT_WORK_TREE] [--help] COMMAND [ARGS]
 The most commonly used git commands are:
 add Add file contents to the index
 apply Apply a patch on a git index file and a working tree
 archive Create an archive of files from a named tree
 bisect Find the change that introduced a bug by binary search
 ...и т.д.

Давайте для начала создадим очень простой проект и инициализируем для него Git. Наберите

 cd ~
 mkdir myproject && cd myproject

Теперь создайте простую структуру директорий и несколько файлов:

 mkdir public && mkdir doc
 touch public/index.php && touch doc/README

Проект у нас может быть любым, на любом языке. Следующий ход – за Git:

 git init
 git add .
 git commit -m “Setup repository”

Вы только что создали новый репозиторий в вашей рабочей директории – заметим, что он находится прямо в текущем каталоге, а не в где-то в далеком центре. Теперь можно отслеживать свой код внутри этого каталога. Итак, начнем редактирование одного из файлов. Измените public/index.php, добавив:

<?php
  echo “This is our very empty project... but at least we’ve
  started.”;
  ?>

...а затем наберите git status . Появится сообщение, что файл был изменен, но не зафиксирован [commited; в разговоре часто используют термин «закомиттен», – прим. пер.]. В отличие от SVN, вы должны явно попросить Git включить выполненные изменения в фиксацию, хотя опция -a переопределяет это поведение. Здесь мы воспользуемся git add:

 git add public/index.php
 git commit -m “Added simple message to index file”
    Чтобы увидеть результат, исследуем журнал с помощью git log:
 $ git log
 commit f5737c51c4b645617fa3017389e873628eec0edc
 Author: Dan Frost <user@example.com>
 Date: Thu Nov 20 19:51:00 2008 +0000
 Added simple message to index file
 commit 03f5c27f3bf3ef72c5c92618a323a814eb76767b
 Author: Dan Frost <dan@3ev.com>
 Date: Thu Nov 20 19:41:28 2008 +0000
 Started repo

Пусть покажет SHA1

Интерфейс Gitk дает графическое представление ветвей и слияний, а также фиксирует, что произошло между ними.

Ну и что это за шеренги цифр, длинные до нелепости? Да номера версий. А почему номер версии не может быть простым – например 1, 2 или 3? Может-то может, но только если вы автородиночка: нумерация 1, 2, 3 и так далее просто не работает, если у вас больше одного репозитория. Моя версия 2535 будет вашей 102, а у кого-то третьего – вообще 8745.

Git жертвует прелестями простых целых чисел в нумерации версий во имя могучего SHA1. Этот криптографический хэш позволяет Git определять любую часть – файлы, фиксации, деревья и так далее – каждого репозитория (не только вашего) однозначно и хранить их в базе данных объектов. Команда git show позволяет изучить объект базы данных, например:

 git show 03f5c27f3bf3ef72c5c92618a323a814eb76767b

Она покажет вам именно то, что соответствует данному SHA1. Практически любой отчет использует SHA1 – например, git log, как мы видели выше.

Выберите любой хэш SHA1 из этого сообщения и используйте его с командой git show, чтобы узнать, чему он соответствуют. Набирать полный SHA1 бывает довольно мучительно, поэтому Git допускает его сокращение – главное, чтобы оно было однозначным:

$ git show c3e59317

Теперь вы должны иметь возможность снова редактировать, создавать новые файлы и добавлять их в Git. Основных команд git add, git commit и git log достаточно для того, чтобы даже особо неохочие до версий кодеры извлекли пользу из Git.

Но что изменилось?

Журнал Git можно просмотреть с помощью команды git log, выдающей простой перечень всех сделанных изменений. Но она умеет гораздо больше – например, создает заплаты (patch):

git log -p
git log --pretty=raw

Обнаружив, что к коду версии, с которой вы работали до этого, кто-то приложил руки, можете использовать git diff для поиска изменений:

$ git diff f5737c51c4b645617fa3017389e873628eec0edc
diff --git a/public/index.php b/public/index.php
index da4d4c6..95fdaa6 100644
--- a/public/index.php
+++ b/public/index.php
@@ -1,3 +1,4 @@
<?php
echo “This is our very empty project... but at least we’ve
started.”;
?>
+Added this

Существует также сокращение для определения различий с предыдущей версией, с версией до нее, и так далее:

git diff HEAD

показывает разницу между текущей рабочей директории и HEAD, а git diff HEAD^ показывает ее между текущей директорией и версией до последней фиксации. Вы можете сравнивать конкретные ревизии с предпоследней версией, выполнив:

 git diff 06c831d0a30833e0a037f0f1a4b11fd7e1ef226f HEAD^

Зачастую вы отлично представляете, когда произошли неприятные вам изменения, поэтому Git предлагает два способа ссылки на время, оба из которых вполне «человекочитаемы»:

 git diff “@{90 minutes ago}”
 git diff “@{2008-10-01 17:30:00}”

Наконец, очень полезна команда whatchanged, показывающая – вы удивитесь – что изменилось в конкретном файле:

 git whatchanged public/index.php


Ваша личная «копилка»

Озарила новая идея? Попробовали ее, и теперь надо вернуться к реальной работе? Положите идею в «копилку».

/www/gitarticle/working1(master) $ git stash
Saved “WIP on master: a6d6f31... merge other styling in”
HEAD is now at a6d6f31... merge other styling in

Теперь можете вернуть вашу предыдущую фиксацию, но последние изменения будут «накоплены». Чтобы получить их обратно, просто наберите

git stash apply stash@{1}

Или создайте ветку из «копилки»:

git stash branch stash@{1}

Поделитесь своей работой

Менталитет типичного программиста не таков, чтобы прятать код в сундук. Что будет, если вы решите поделиться своими элегантными разработками и версиями кода?

Есть несколько способов создать общий доступ к репозиториям Git. Git располагает собственным, весьма эффективным протоколом, который умеет работать над SSH или HTTP. Создадим доступ через SSH, поскольку его легче настроить, если у вас несколько Linux-машин.

На машине, доступом к которой вы хотите осчастливить общество, создайте каталог, содержащий общий репозиторий:

mkdir /var/git/project.git
cd /var/git/project.git
git init --bare

Как видите, добавилась опция --bare. Вернувшись к ранее созданному репозиторию и набрав ls -a, вы заметите директорию .git. Это и есть репозиторий Git – аналогичный тому, что был создан в нашей рабочей директории ранее. Все фиксации и изменения сохраняются здесь.

Создавая пустой репозиторий, мы на самом деле создаем репозиторий Git без рабочей директории – то есть каталог .git. Сравнив содержание нашего вновь созданного пустого репозитория и директории .git, созданной ранее, вы найдете очень мало различий.

Заготовив репозиторий для совместного использования, вернитесь к своей локальной машине в вашу рабочую директорию. Начните с добавления вновь созданного пустого репозитория в качестве удаленного (remote):

git remote add sharing-server ssh://www.example.com/var/
git/project.git
git push sharing-server master

Первая команда добавляет URL сервера под именем sharing-server, а вторая помещает на него основную ветвь вашего кода. Чтобы в любое время узнать, какие удаленные серверы вы настраивали, выполните

git remote

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

mkdir ~/my-sandbox/ && cd ~/my-sandbox/
git clone ssh://myserver.com/var/git/myapp.git

Вы получите полную копию приложения для редактирования или развертывания. Как и с svn checkout, каждый ваш коллега или почитатель вашего программного продукта может добыть код с помощью этого метода. В отличие от SVN, если вы зафиксировали изменения в вашей рабочей версии, они не отобразятся в «удаленной» версии, пока вы не поместите их туда снова с использованием git push sharing-server master. Хотя вы и совместно работающий с вами человек можете отслеживать детальные изменения в коде, ваши изменения не публикуются автоматически – это распределяемый контроль версий.

Ваш коллега может поместить изменения в этот репозиторий через git push, после чего вы можете забрать их назад с помощью

git pull sharing-server master.

Это похоже на фиксацию и правку в SVN, но можно отслеживать изменения локально, прежде чем сделать их доступными всем. И можно иметь собственные ветви...

Ветви

Прежде чем создавать ветви, вставьте в ваш .bash_profile следующую небольшую, но полезную добавку (спасибо simplisticcomplexity.com), чтобы всегда видеть, с какой ветвью вы работаете:

parse_git_branch() {
git branch 2> /dev/null | sed -e ‘/^[^*]/d’ -e ‘s/* \(.*\)/(\1)/’
}
PS1=”\w\$(parse_git_branch) $ “

Создать ветвь в Git очень просто – следующая команда сделает это на основе последней выполненной вами фиксации. Затем Git переключит вас на нее, чтобы вы могли начать работу:

git checkout -b my-new-branch

После этого вносите в нее любые изменения, не опасаясь испортить «главную» (master) ветвь. Переключение между ветвями выполняет повторная команда checkout:

git checkout master
git checkout my-new-branch
git checkout -b my-new-idea

Попробуйте это в ранее созданном клоне репозитория Git – оказывается, вы можете редактировать, перемещать, создавать и удалять файлы в ветви независимо от главной ветви, которую вы клонировали. И если вы не готовы зафиксировать свои изменения в удаленном репозитории, вернитесь к главной ветви с помощью git checkout master и продолжайте работу в основном коде, и используйте git pull для обновления исходников.

Конечно, в какой-то момент вы захотите объединить проделанные в вашей ветке изменения с главной веткой и поместить их в удаленный репозиторий. Сначала вернитесь к главной ветке, а затем объедините ветви и отправьте изменения в удаленный репозиторий:

git checkout master
git merge my-branch

После слияния могут возникнуть конфликты. Как и в случае с CVS и SVN, они отражаются в исходных файлах:

<<<<<<< HEAD:public/index.php
Hello!
=======
Hello, World!
>>>>>>> update-message:public/index.php

Первый раздел показывает содержание текущей ветви, а второй демонстрирует объединяемую. Исправив конфликт, скомандуйте git add для добавления файла в следующую фиксацию. Она скажет Git, что конфликт урегулирован.

Все объединив и согласовав, отправляйте результат на удаленный сервер:

git push

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

Множество удаленных

В примере выше создавался клон главного репозитория, но вы также можете создавать свои собственные рабочие репозитории и утягивать в них данные из нескольких удаленных репозиториев. Именно здесь магия Git кладет конкурентов на лопатки – вы можете работать с 20 коллегами, каждый со своим репозиторием, и выборочно тягать изменения из каждого. Для этого создайте локальный репозиторий и прикрепите к нему новый удаленный репозиторий:

git init
git remote add remote-server ssh://www.example.com/var/
git/project.git
git pull remote-server master

Допустима любая комбинация из удаленных серверов и ветвей. При каждом таком добавлении вы получаете копию авторских изменений, переносимых в локальный репозиторий Git. Таким образом легко определять различия и делать слияния и прочее с контентом множества авторов. Можно также взять любую ветвь и поместить ее на свой сервер:

git remote add my-server ssh://www.my-example.com/var/
git/my-fork.git
git push my-server my-branch

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

Например, я могу забрать ваши последние изменения:

git pull your-server master

...наиграться с ними, добавить функции, которые, по моему мнению, вам понравятся, а затем скомандовать

 git push my-server master

Слишком ветвисто

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

Функция show-branch дает примерный графический набросок состояния ваших ветвей.

 $ git show-branch --all
 ! [mybranch] Add nasty styling
 * [master] add some lines to index.php
 --
 + [mybranch] Add nasty styling
 + [mybranch^] Add crazy blue style
 * [master] add some lines to index.php
 +* [mybranch~2] Change message on homepage

Первый раздел – это перечень ветвей, где * обозначает текущую ветвь, а ! обозначает HEAD всех других ветвей. В этом примере все идущее после -- предваряется двумя колонками, по одной для каждой из двух ветвей (master и mybranch). + означает, что в соответствующей ветви существует фиксация, а пустое пространство означает, что ее нет. Имена в скобках могут быть использованы вместо SHA1 – например, git show mybranch~2.

Назад в прошлое

Если вы или кто-то что-то сломал или вы хотите узнать, как приложение работало раньше, можете загрузить себе конкретную ревизию. Номера ревизий довольно уродливы – вникать в SHA1 каждый раз, когда вы хотите посмотреть, что произошло, является тяжелым испытанием, поэтому вот вам несколько сокращений. Вы можете вернуться к прошедшему времени, используя человеко-читаемое условие:

 git checkout “@{10 minutes ago}”

Если вы обнаружите здесь что-то хорошее, то можете решить создать ветвь:

 git checkout -b what-might-have-been

С новой ветвью можно работать, как и с любой другой, с фиксацией, объединением с главной и другими ветвями и совместно с коллегами. Если вы хотите влить ее в готовый код, поступайте как раньше.

 git commit -m “Found some good changes here”
 git checkout master
 git merge my-new-branch

Мир следует за Git – исследуйте github.com и убедитесь что Rails, Scriptaculous и MooTools переехали туда. И легко понять, почему. Гибкость децентрализованной модели и реально необременительное ветвление слишком заманчивы, чтобы их игнорировать. LXF

Шоу Gitтеров

Посмотрите эти видео, чтобы увидеть, почему был создан Git и что он умеет делать:

Личные инструменты
  • Купить электронную версию
  • Подписаться на бумажную версию