Merge branch 'multiplayer-es' of https://github.com/irtusb/gitmagic
[gitmagic/gitmagic.git] / ru / grandmaster.txt
blob21f630e6b2d7a1ecae771f232c966be00a596fdf
1 == Гроссмейстерство Git ==\r
2 \r
3 Эта претенциозно названная глава является собранием приемов работы с Git, которые я не смог отнести к другим главам.\r
4 \r
5 === Релизы исходников ===\r
6 \r
7 В моих проектах Git управляет только теми файлами, которые я собираюсь архивировать и пускать в релиз.
8 Чтобы создать тарбол с исходниками, я выполняю:\r
9 \r
10  $ git archive --format=tar --prefix=proj-1.2.3/ HEAD\r
12 === Сохранение изменений ===\r
14 Вручную сообщать Git о том, что вы добавили, удалили или переименовали файлы, может стать непростой задачей
15  в некоторых проектах. Вместо этого вы можете выполнить команды:\r
17  $ git add .\r
18  $ git add -u\r
20 Git просмотрит файлы в текущем каталоге и обработает изменения сам. Вместо второй команды add, выполните *git commit -a*, если вы хотите также сделать коммит с изменениями. В *git help ignore* можно посмотреть, как указать, какие файлы должны игнорироваться.\r
22 Вы можете выполнить все это в один прием:\r
24  $ git ls-files -d -m -o -z | xargs -0 git update-index --add --remove\r
26 Опции *-z* и *-0* предотвращают побочные эффекты от файловых имен, содержащих специальные символы. Поскольку эта команда добавляет игнорируемые файлы, вы можете использовать опции `-x` или `-X`.\r
28 === Слишком большой коммит ===\r
30 Вы пренебрегали коммитами слишком долго? Яростно писали код и вспомнили о контроле исходников только сейчас? Внесли ряд несвязанных изменений, потому что это ваш стиль?\r
32 Никаких проблем. Выполните:\r
34  $ git add -p\r
36 Для каждого внесенного изменения Git покажет измененный участок кода и спросит, должно ли это изменение пройти в следующем коммите. Отвечаем "y" или "n". Если вы хотите сделать что-то другое, например отложить выбор, введите "?" чтобы получить дополнительную информацию.\r
38 Как только все будет готово, выполните:\r
40  $ git commit\r
42 для коммита именно тех изменений, которые вы выбрали ('staged' изменения). Убедитесь, что вы не указали опцию *-a*, в противном случае Git добавит в коммит все изменения.\r
44 Что делать, если вы изменили множество файлов во многих местах? Просмотр каждого отдельного изменения - удручающая задача. В этом случае используйте *git add -i*, чей интерфейс менее прост, но более гибок. При помощи нескольких нажатий кнопок можно добавить на этап или убрать с этапа несколько файлов одновременно, либо просмотреть и выделить изменения в отдельных файлах. Как вариант, запустите *git commit \--interactive*, который автоматически сделает коммит после того, как вы закончите.\r
46 ==== Этапные изменения ====\r
48 До сих пор мы избегали такой известной части Git, как  'index', но теперь мы должны разобраться с ней, чтобы пояснить вышесказанное. Индекс представляет собой временную область. Git редко перемещает данные непосредственно между вашим проектом и его историей. Вместо этого, Git сначала записывает данные в индекс, а уж затем копирует данные из индекса по месту назначения.\r
50 Например, *commit -a* это на самом деле двухэтапный процесс. Сначала снапшот текущего состояния отслеживаемых файлов помещается в индекс. Затем снапшот, находящийся в индексе, записывается в историю. Коммит без опции *-a* выполняет только второй этап, и имеет смысл только после выполнения команд, которые изменяют индекс, например *git add*.\r
52 Обычно мы можем не обращать внимания на индекс и считать, что взаимодействуем с историей напрямую. Но в такого рода сложных случаях нам нужен усиленный контроль над тем, что записывается в историю, и мы вынуждены работать с индексом. Мы помещаем снапшот только части наших изменений в индекс, а потом записываем этот аккуратно сформированный снапшот.\r
54 === Не теряй HEAD ===\r
56 Тег HEAD - как курсор. В нормальном состоянии он указывает на последний коммит, продвигаясь вместе с каждым новым коммитом. Есть команды Git, которые позволяют перемещать этот тег. Например:\r
58  $ git reset HEAD~3\r
60 переместит HEAD на три коммита назад. Теперь все команды Git будут работать так, как будто вы не делали последних трех коммитов, хотя файлы останутся в текущем состоянии. В справке описаны некоторые методы использования этого эффекта.\r
62 Но как вернуться назад в будущее? Ведь предыдущие коммиты о нем ничего не знают.\r
64 Если у вас есть SHA1 оригинального HEAD, то:\r
66  $ git reset SHA1\r
68 Но предположим, что вы никогда его не записывали. Тут тоже беспокоиться не стоит. Для комнад такого рода Git сохраняет оригинальный HEAD как тег под названием ORIG_HEAD, и вы можете вернуться безопасно и без проблем:\r
70  $ git reset ORIG_HEAD\r
72 === Охота за HEAD'ами ===\r
74 Предположим ORIG_HEAD недостаточно. Предположим, что вы только что осознали, что допустили громадную ошибку, и вам нужно вернуться в очень старый коммит давно забытой ветки.\r
76 По умолчанию Git хранит коммиты по крайней мере в течении двух недель, даже если вы сказали ему уничтожить ветку с ними. Проблема в нахождении подходящего хеша.\r
78 Вы можете просмотреть хеши в `.git/objects` и методом проб и ошибок найти нужный. Но есть путь значительно легче.\r
80 Git записывает все хеши коммитов в `.git/logs`. В папке `refs` содержится история активности на всех ветках, а файл `HEAD` содержит каждое значение хеша, которое когда-либо принимал HEAD. Второе можно использовать чтобы найти хеши коммитов на случайно обрубленных ветках.\r
82 Команда reflog предоставляет удобный интерфейс работы с этими логами. Используйте:\r
84  $ git reflog\r
86 Вместа копипейста хешей из reflog, попробуйте:\r
88  $ git checkout "@{10 minutes ago}"\r
90 Или сделайте чекаут пятого из последних посещенных коммитов с помощью:\r
92  $ git checkout "@{5}"\r
94 Смотрите секцию "Specifying Revisions" *git help rev-parse*, если вам нужна дополнительная информация.\r
95 Вам может потребоваться установить более долгий период сохранения удаляемых коммитов.\r
97 Например, выполнение:\r
99  $ git config gc.pruneexpire "30 days"\r
101 означает, что в удаленные коммиты будут окончательно потеряны только после того, как пройдут 30 дней с момента удаления, и будет запущена *git gc*.\r
103 Также вам может потребоваться отключить автоматическое выполнение *git gc*:\r
105  $ git config gc.auto 0\r
107 После этого коммиты будут удаляться только когда вы будете запускать *git gc* самостоятельно.\r
109 === Git как основа ===\r
111 Дизайн Git'a, разработанный в UNIX стиле, позволяет использовать Git как низкоуровневый компонент других программ: GUI, веб-интерфейсов, альтернативных командных строк, инструментов управления патчами, импортирования, преобразования, и т.д. На самом деле, многие команды Git - сами по себе скрипты, стоящие на плечах гигантов.\r
112 Немного поигравшись с Git, вы можете заставить его удовлетворять многие ваши потребности.\r
114 Простейший трюк - использование алиасов Git для выполнения часто\r
116  используемых команд:\r
118  $ git config --global alias.co checkout\r
119  $ git config --global --get-regexp alias       # отображает текущие алиасы\r
120  alias.co checkout\r
121  $ git co foo                                   # то-же, что 'git checkout foo'\r
123 Также можно выводить текущую ветку в командную строку или название окна терминала.\r
125 Запуск\r
127  $ git symbolic-ref HEAD\r
129 выводит название текущей ветки. Для практического использования вы
130 скорее всего захотите убрать "refs/heads/" и сообщения об ошибках:\r
132  $ git symbolic-ref HEAD 2> /dev/null | cut -b 12-\r
134 Папка `contrib` это целая сокровищница инструментов, построенных на Git.\r
135 Со временем некоторые из них могут становиться официальными командами. Под Debian и Ubuntu эта папка находится в `/usr/share/doc/git-core/contrib`.\r
137 `workdir/git-new-workdir` - один из популярных и часто используемых инструментов. С помощью хитрых симлинков этот скрипт создает новую рабочую папку, которая будет иметь общую историю с оригинальным репозиторием:\r
139  $ git-new-workdir an/existing/repo new/directory\r
141 Можно думать о новой папке и о файлах в ней, как о клоне, за исключением того, что так как история общая,
142 два дерева автоматически синхронизуются. Нет необходимости в *merge*, *push* и *pull*.\r
144 === Опасные трюки ===\r
146 Случайно уничтожить данные очень сложно с сегодняшними версиями Git.\r
147 Но если вы знаете, что делаете, вы можете обойти защиту для общих команд.\r
149 *Checkout*: Незакоммиченные изменения не дают сделать чекаут. Чтобы все-таки сделать чекаут нужного коммита, уничтожив свои изменения, используется флаг *-f*: \r
151  $ git checkout -f COMMIT\r
153 С другой стороны, если вы укажете отдельный путь для чекаута, то проверки на безопасность произведены не будут, и по указанные путям все будет переписываться без каких-либо сообщений. Будьте осторожны, если вы используете чекаут таким образом.\r
155 *Reset*: Ресет также нельзя провести, если есть незакоммиченные изменения. Чтобы обойти это, запустите:\r
157  $ git reset --hard [COMMIT]\r
159 *Branch*: Удаление ветки не проходит, если приводит к потере изменений. Для принудительного удаления используйте:\r
161  $ git branch -D BRANCH # вместо -d\r
163 Аналогично, попытка перезаписи ветки путем перемещения не пройдет, если какие-то данные будут потеряны. Чтобы принудительно переместить ветку, введите:\r
165  $ git branch -M [SOURCE] TARGET #вместо -m\r
167 В отличии от чекаута и ресета, эти две команды задерживают удаление данных. Изменения остаются в папке .git и могут быть восстановлены с помощью нужного хеша из `.git/logs`(смотрите параграф "Охота за HEAD'ами" выше).\r
169 По умолчанию они будут храниться по крайней мере две недели.\r
171 *Clean*: Некоторые команды не будут выполняться, если они могут повредить неотслеживаемые файлы. Если вы уверены, что все неотслеживаемые файлы и папки вам не нужны, то безжалостно удаляйте их командой:\r
173  $ git clean -f -d\r
175 В следующий раз эта надоедливая команда выполнится!\r
177 === Улучшаем свой публичный образ ===\r
179 История многих моих проектов полна глупых ошибок. Самое ужасное это кучи недостающих файлов, которые появляются, когда забываешь выполнить *git add*. К счастью, я пока не терял важных файлов из-за того, что пропускал их, потому что я редко удаляю оригинальные рабочие папки. Обычно я замечаю ошибку несколько коммитов спустя, так что единственный вред это отсутствующая история и осознание своей вины.\r
181 Также я регулярно совершаю(и коммичу) меньшее зло - завершающие пробелы. Несмотря на безвредность, я не хотел бы, чтобы это появлялось в публичных записях.\r
183 И наконец, я беспокоюсь о неразрешенных конфликтах, хотя пока они не приносили вреда. Обычно я замечаю их во время билда, но в некоторых случаях могу проглядеть.\r
184 Если бы я только поставил защиту от дурака, используя хук, который бы предупреждал меня об этих проблемах...\r
186  $ cd .git/hooks\r
187  $ cp pre-commit.sample pre-commit # В старых версиях Git: chmod +x pre-commit\r
189 Теперь Git отменяет коммит, если обнаружены ненужные пробелы или неразрешенные конфликты.\r
190 Для этого руководства я в конце концов добавил следующее в начало *pre-commit* хука, чтобы защититься от своей рассеянности:\r
192 if git ls-files -o | grep '\.txt$'; then\r
193  echo FAIL! Неотслеживаемые .txt файлы.\r
194  exit 1\r
195 fi\r
197 Несколько операций Git поддерживают хуки, смотрите *git help hooks*. Вы можете добавить хуки, которые будут сообщать о грамматических ошибках в комментариях к коммиту, добавлять новые файлы, делать отступы перед параграфами, добавлять записи на веб-страничку, проигрывать звуки, в общем, делать что угодно...\r
199 Мы встречались с *post-update* хуком раньше, когда обсуждали Git через http. Этот хук обновлял несколько файлов, которые необходимы для ненативнох видов коммуникации с Git.