Typo-Korrekturen2
[gitmagic.git] / ru / grandmaster.txt
blobf1f02a687e6b91b1ef37c3e7b6a3ac13783c9674
1 == Гроссмейстерство Git ==
3 Теперь вы уже должны уметь ориентироваться в страницах *git help* и понимать почти всё. Однако точный выбор команды, необходимой для решения конкретной проблемы, может быть утомительным. Возможно, я сберегу вам немного времени: ниже приведены рецепты, пригодившиеся мне в прошлом.
5 === Релизы исходников ===
7 В моих проектах Git управляет в точности теми файлами, которые я собираюсь архивировать и пускать в релиз. Чтобы создать тарбол с исходниками, я выполняю:
9  $ git archive --format=tar --prefix=proj-1.2.3/ HEAD
11 === Коммит изменений ===
13 В некоторых проектах может быть трудоемко оповещать Git о каждом добавлении, удалении и переименовании файла. Вместо этого вы можете выполнить команды
15  $ git add .
16  $ git add -u
18 Git просмотрит файлы в текущем каталоге и сам позаботится о деталях. Вместо второй команды add, выполните *git commit -a*, если вы собираетесь сразу сделать коммит. Смотрите *git help ignore*, чтобы узнать как указать файлы, которые должны игнорироваться.
20 Вы можете выполнить все это одним махом:
22  $ git ls-files -d -m -o -z | xargs -0 git update-index --add --remove
24 Опции *-z* и *-0* предотвращают неверную обработку файловых имен, содержащих специальные символы. Поскольку эта команда добавляет игнорируемые файлы, вы возможно захотите использовать опции -x или -X.
26 === Мой коммит слишком велик ===
28 Вы пренебрегали коммитами слишком долго? Яростно писали код и вспомнили об управлении исходниками только сейчас? Внесли ряд несвязанных изменений, потому что это ваш стиль?
30 Нет поводов для беспокойства. Выполните
32  $ git add -p
34 Для каждой сделанной вами правки Git покажет измененный участок кода и спросит, должно ли это изменение попасть в следующий коммит. Отвечайте «y» (да) или «n» (нет). У вас есть и другие варианты, например отложить выбор; введите «?» чтобы узнать больше.
36 Когда закончите, выполните
38  $ git commit
40 для внесения именно тех правок, что вы выбрали («буферизованных» изменений). Убедитесь, что вы не указали опцию *-a*, иначе Git закоммитит все правки.
42 Что делать, если вы изменили множество файлов во многих местах? Проверка каждого отдельного изменения становится удручающей рутиной. В этом случае используйте *git add -i*. Ее интерфейс не так прост, но более гибок. В несколько нажатий кнопок можно добавить или убрать из буфера несколько файлов одновременно, либо просмотреть и выбрать изменения лишь в отдельных файлах. Как вариант, запустите *git commit \--interactive*, которая автоматически сделает коммит когда вы закончите.
44 === Индекс — буферная зона Git ===
46 До сих пор мы избегали знаменитого «индекса» Git, но теперь мы должны рассмотреть его, для пояснения вышесказанного. Индекс это временный буфер. Git редко перемещает данные непосредственно между вашим проектом и его историей. Вместо этого Git сначала записывает данные в индекс, а уж затем копирует их из индекса по месту назначения.
48 Например, *commit -a* на самом деле двухэтапный процесс. Сначала слепок текущего состояния каждого из отслеживаемых файлов помещается в индекс. Затем слепок, находящийся в индексе, записывается в историю. Коммит без опции *-a* выполняет только второй шаг, и имеет смысл только после выполнения команд, изменяющих индекс, таких как *git add*.
50 Обычно мы можем не обращать внимания на индекс и делать вид, что взаимодействуем напрямую с историей. Но в данном случае мы хотим более тонкого контроля, поэтому управляем индексом. Мы помещаем слепок некоторых (но не всех) наших изменений в индекс, после чего окончательно записываем этот аккуратно сформированный слепок.
52 === Не теряй «головы» ===
54 Тег HEAD (англ. «голова», прим. пер.) — как курсор, который обычно указывает на последний коммит, продвигаясь с каждым новым коммитом. Некоторые команды Git позволяют перемещать этот курсор. Например,
56  $ git reset HEAD~3
58 переместит HEAD на три коммита назад. Теперь все команды Git будут работать так, как будто вы не делали последних трех коммитов, хотя файлы останутся в текущем состоянии. В справке описано несколько способов использования этого приема.
60 Но как вернуться назад в будущее? Ведь предыдущие коммиты о нем ничего не знают.
62 Если у вас есть SHA1 изначальной «головы», то:
64  $ git reset 1b6d
66 Но допустим, вы его не записывали. Не беспокойтесь: для комнад такого рода Git сохраняет оригинальную «голову» как тег под названием ORIG_HEAD, и вы можете вернуться надежно и безопасно:
68  $ git reset ORIG_HEAD
70 === Охота за «головами» ===
72 Предположим ORIG_HEAD недостаточно. К примеру, вы только что осознали, что допустили громадную ошибку, и вам нужно вернуться к древнему коммиту в давно забытой ветке.
74 По умолчанию Git хранит коммиты не меньше двух недель, даже если вы приказали уничтожить содержащую их ветку. Проблема в нахождении соответствующего хеша. Вы можете просмотреть все значения хешей в .git/objects и методом проб и ошибок найти нужный. Но есть путь значительно легче.
76 Git записывает каждый подсчитанный им хеш коммита в .git/logs. В подкатлоге refs содержится полная история активности на всех ветках, а файл HEAD содержит каждое значение хеша, которое когда-либо принимал HEAD. Последнее можно использовать чтобы найти хеши коммитов на случайно обрубленных ветках.
78 Команда reflog предоставляет удобный интерфейс работы с этими журналами. Используйте
80  $ git reflog
82 Вместо копирования хешей из reflog, попробуйте
84  $ git checkout "@{10 minutes ago}" # 10 минут назад, прим. пер.
86 Или сделайте чекаут пятого с конца из посещенных коммитов с помощью
88  $ git checkout "@{5}"
90 Смотрите раздел «Specifying Revisions» в *git help rev-parse* для дополнительной информации.
92 Вы можете захотеть удлинить отсрочку для коммитов, обреченных на удаление. Например,
94  $ git config gc.pruneexpire "30 days"
96 означает, что удаляемые коммиты будут окончательно исчезать только по прошествии 30 дней и после запуска *git gc*.
98 Также вы можете захотеть отключить автоматический вызов *git gc*:
100  $ git config gc.auto 0
102 В этом случае коммиты будут удаляться только когда вы будете запускать *git gc* вручную.
104 === Git как основа ===
106 Дизайн Git, в истинном духе UNIX, позволяет легко использовать его как низкоуровневый компонент других программ: графических и веб-интерфейсов; альтернативных интерфейсов командной строки; инструментов управления патчами; средств импорта или конвертации, и так далее. Многие команды Git на самом деле — скрипты, стоящие на плечах гигантов. Небольшой доработкой вы можете переделать Git на свой вкус.
108 Простейший трюк — использование алиасов Git для сокращения часто используемых команд:
110  $ git config --global alias.co checkout
111  $ git config --global --get-regexp alias       # отображает текущие алиасы
112  alias.co checkout
113  $ git co foo # то-же, что и «git checkout foo»
115 Другой пример: можно выводить текущую ветку в приглашении  командной строки или заголовке окна терминала. Запуск
117  $ git symbolic-ref HEAD
119 выводит название текущей ветки. На практике  вы скорее всего захотите убрать «refs/heads/» и сообщения об ошибках:
121  $ git symbolic-ref HEAD 2> /dev/null | cut -b 12-
123 Подкаталог +contrib+ это целая сокровищница инструментов, построенных на Git. Со временем некоторые из них могут становиться официальными командами. В Debian и Ubuntu этот каталог находится в +/usr/share/doc/git-core/contrib+.
125 Один популярный инструмент из этого каталога — +workdir/git-new-workdir+. Этот скрипт создает с помощью символических ссылок новый рабочий каталог, имеющий общую историю с оригинальным хранилищем:
127  $ git-new-workdir существующее/хранилище новый/каталог
129 Новый каталог и файлы в нем можно воспринимать как клон, с той разницей, что два дерева автоматически остаются синхронизированными ввиду общей истории. Нет необходимости в merge, push и pull.
131 === Рискованные трюки ===
133 Нынешний Git делает случайное уничтожение данных очень сложным.
134 Но если вы знаете, что делаете, вы можете обойти защиту для распространенных команд.
136 *Checkout*: Наличие незакоммиченных изменений прерывает выполнение checkout. Чтобы перейти к нужному коммиту, даже уничтожив свои изменения, используйте «принуждающий» (force, прим. пер.) флаг *-f*:
138  $ git checkout -f HEAD^
140 С другой стороны, если вы укажете checkout конкретные пути, проверки на безопасность не будет: указанные файлы молча перезапишутся. Будьте осторожны при таком использовании checkout.
142 *Reset*: сброс также прерывается при наличии незакоммиченных изменений. Чтобы заставить его сработать, запустите
144  $ git reset --hard 1b6d
146 *Branch*: Удаление ветки прервётся, если оно привело бы к потере изменений. Для принудительного удаления введите
148  $ git branch -D мертвая_ветка # вместо -d
150 Аналогично, попытка перезаписи ветки путем перемещения будет прервана, если может привести к потере данных. Для принудительного перемещений ветки введите
152  $ git branch -M источник цель # вместо -m
154 В отличии от checkout и reset, эти две команды дают отсрочку в удалении данных. Изменения остаются в каталоге .git и могут быть возвращены восстановлением нужного хеша из .git/logs (смотрите выше раздел «Охота за „головами“»). По умолчанию они будут храниться по крайней мере две недели.
156 *Clean*: Некоторые команды могут не сработать из опасений повредить неотслеживаемые файлы. Если вы уверены, что все неотслеживаемые файлы и каталоги не нужны, то безжалостно удаляйте их командой
158  $ git clean -f -d
160 В следующий раз эта досадная команда сработает!
162 === Предотвращаем плохие коммиты ===
164 Глупые ошибки загрязняют мои хранилища. Самое ужасное это проблема недостающих файлов, вызванная забытым *git add*.
166 Примеры менее серьезных проступков: завершающие пробелы и неразрешённые конфликты слияния. Несмотря на безвредность, я не хотел бы, чтобы это появлялось в публичных записях.
168 Если бы я только поставил защиту от дурака, используя _хук_, который бы предупреждал меня об этих проблемах:
170  $ cd .git/hooks
171  $ cp pre-commit.sample pre-commit # В старых версиях Git: chmod +x pre-commit
173 Теперь Git отменит коммит, если обнаружит лишние пробелы или неразрешенные конфликты.
175 Для этого руководства я в конце концов добавил следующее в начало хука *pre-commit*, чтобы защититься от своей рассеянности:
177 if git ls-files -o | grep '\.txt$'; then
178  echo ПРЕРВАНО! Неотслеживаемые .txt файлы.
179  exit 1
182 Хуки поддерживаются несколькими различными операциями Git, смотрите *git help hooks*. Мы использовали пример хука *post-update* раньше, при обсуждении использования Git через http. Он запускался при каждом перемещении «головы». Пример скрипта *post-update* обновляет файлы, которые нужны Git для связи через не считающиеся с ним средства сообщения, такие как HTTP.