== Базовые операции ==

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

=== Сохранение состояния ===

Собираетесь попробовать внести некие радикальные изменения? Предварительно создайте снимок всех файлов в текущем каталоге с помощью команд

 $ git init
 $ git add .
 $ git commit -m "Моя первая резервная копия"

Теперь, если новые правки всё испортили, можно восстановить первоначальную версию:

 $ git reset --hard

Чтобы вновь сохранить состояние:

 $ git commit -a -m "Другая резервная копия"

=== Добавление, удаление, переименование ===

Приведенный выше пример отслеживает только те файлы, которые существовали при первом запуске *git add*. Если вы создали новые файлы или подкаталоги, придется сказать Git'у:

 $ git add readme.txt Documentation

Аналогично, если хотите, чтобы Git забыл о некоторых файлах:

 $ git rm ляп.h старье.c
 $ git rm -r улики/

Git удалит эти файлы, если вы не удалили их сами.

Переименование файла — это то же, что удаление старого имени и добавления нового. Для этого есть *git mv*, которая имеет тот же синтаксис, что и команда *mv*. Например:

 $ git mv bug.c feature.c

=== Расширенные отмена/возврат ===

Иногда просто хочется вернуться назад и забыть все изменения до определенного момента, потому что все они были неправильными. В таком случае

 $ git log

покажет список последних коммитов и их хеши SHA1:

----------------------------------
commit 766f9881690d240ba334153047649b8b8f11c664
Author: Bob <bob@example.com>
Date:   Tue Mar 14 01:59:26 2000 -0800

    Заменил printf() на write().

commit 82f5ea346a2e651544956a8653c0f58dc151275c
Author: Alice <alice@example.com>
Date:   Thu Jan 1 00:00:00 1970 +0000

    Начальный коммит.
----------------------------------

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

 $ git reset --hard 766f

для восстановления состояния до указанного коммита и удаления всех последующих безвозвратно.

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

 $ git checkout 82f5

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

Эта альтернативная реальность называется «веткой» (branch, прим. пер.), и <<branch,чуть позже мы поговорим об этом подробнее>>. А сейчас просто запомните, что команда

 $ git checkout master

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

Еще раз воспользуемся аналогией с компьютерными играми:

- *git reset --hard*: загружает ранее сохраненную игру и удаляет все версии, сохраненные после только что загруженной.

- *git checkout*: загружает старую игру, но если вы продолжаете играть, состояние игры будет отличаться от более новых сохранений, которые вы сделали в первый раз. Любая игра, которую вы теперь сохраняете, попадает в отдельную ветку, представляющую альтенативную реальность, в которую вы попали. <<branch,Мы обсудим это позже>>.

Можно также восстановить только определенные файлы и подкаталоги, перечислив их имена после команды:

 $ git checkout 82f5 какой-то.файл другой.файл

Будьте внимательны: такая форма *checkout* может молча перезаписать файлы. Чтобы избежать неприятных неожиданностей, выполняйте commit перед checkout, особенно если вы только изучаете Git. Вообще, если вы не уверены в какой-либо операции, будь то команда Git или нет, выполните предварительно *git commit -a*.

Не любите копировать и вставлять хеши? Используйте

 $ git checkout :/"Моя первая р"

для перехода на коммит, чье описание начинается с приведенной строки.

Можно также запросить 5-ое с конца сохраненное состояние:

 $ git checkout master~5

=== Откаты ===

В зале суда пункты протокола могут вычеркиваться прямо во время слушания. Подобным образом и вы можете выбирать коммиты для отмены.

 $ git commit -a
 $ git revert 1b6d

отменит коммит с заданным хешем. Откат будет сохранен в виде нового коммита. Можете запустить *git log*, чтобы убедиться в этом.

=== Создание списка изменений ===

Некоторым проектам нужен http://en.wikipedia.org/wiki/Changelog[список изменений] (changelog, прим. пер.). Создайте его такой командой:

 $ git log > ChangeLog

=== Скачивание файлов ===

Получить копию проекта под управлением Git можно, набрав

 $ git clone git://сервер/путь/до/файлов

Например, чтобы получить все файлы, которые я использовал для создания этого документа,

 $ git clone git://git.or.cz/gitmagic.git

Позже мы поговорим о команде *clone* подробнее.

=== Держа руку на пульсе ===

Если вы уже загрузили копию проекта с помощью *git clone*, можете обновить ее до последней версии, используя

 $ git pull

=== Безотлагательная публикация ===

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

Чтобы сделать это с помощью Git, выполните в каталоге, где лежит ваш скрипт,

 $ git init
 $ git add .
 $ git commit -m "Первый релиз"

Затем скажите вашим пользователям запустить

 $ git clone ваш.компьютер:/путь/до/скрипта

чтобы загрузить ваш скрипт. Здесь подразумевается, что у них есть доступ по ssh. Если нет, запустите *git daemon* и скажите пользователям запустить эту команду вместо вышеприведенной:

 $ git clone git://ваш.компьютер/путь/до/скрипта

С этих пор всякий раз, когда ваш скрипт готов к релизу, выполняйте

 $ git commit -a -m "Следующий релиз"

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

 $ git pull

Ваши пользователи никогда не наткнутся на версию скрипта, которую вы не хотите им показывать.

=== Что я сделал? ===

Выясните, какие изменения вы сделали со времени последнего коммита:

 $ git diff

Или со вчерашнего дня:

 $ git diff "@{yesterday}"

Или между определенной версией и версией, сделанной 2 коммита назад:

 $ git diff 1b6d "master~2"

В каждом случае на выходе будет патч, который может быть применен с помощью *git apply*. Попробуйте также:

 $ git whatchanged --since="2 weeks ago"

Часто вместо этого я использую для просмотра истории http://sourceforge.net/projects/qgit[qgit], из-за приятного интерфейса, или http://jonas.nitro.dk/tig[tig] с текстовым интерфейсом, который хорошо работает через медленное соединение. Как вариант, установите веб-сервер, введите *git instaweb* и запустите любой веб-браузер.

=== Упражнение ===

Пусть A, B, C, D — четыре последовательных коммита, где В отличается от A лишь несколькими удаленными файлами. Мы хотим вернуть эти файлы в D. Как мы можем это сделать?

Существует как минимум три решения. Предположим, что мы находимся на D.

  1. Разница между A и B — удаленные файлы. Мы можем создать патч, отражающий эти изменения, и применить его:

   $ git diff B A | git apply

  2. Поскольку в коммите A мы сохранили файлы, то можем восстановить их:

   $ git checkout A foo.c bar.h

  3. Мы можем рассматривать переход от A к B как изменения, которые хотим отменить:

   $ git revert B

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