Вход:  Пароль:  
FreeSource: RuslanHihin/gitusermanual/Chapter3 ...
Free Source | Каталог | Изменения | НовыеКомментарии | Пользователи | Регистрация |

Глава 3. Применение Git в разработке


Оглавление документа Применение Git в разработке

1. Задать ваше имя для git 


Прежде чем что-нибудь создавать и коммитить, вы должны представиться git. Простейший способ сделать это состоит в том, чтобы убедиться, что следующие строки уже содержатся в файле с именем .gitconfig вашего домашнего каталога:

[user]
name = Your Name Comes Here
email = you@yourdomain.example.com

(См. Раздел “CONFIGURATION FILE” git-config(1) для получения дополнительных сведений о файле конфигурации.)

2. Создание нового репозитория


Создание нового репозитория с нуля очень просто:

$ mkdir project
$ cd project
$ git init

Если у вас есть некоторое первоначальное наполнение (например, тарбол):

$ tar -xzvf project.tar.gz
$ cd project
$ git init
$ git add . # Включить все ниже . в первый коммит
$ git commit

3. Как создать коммит


Создание нового коммита состоит из трех этапов:


1. Создание некоторых изменений в рабочем каталоге, используя ваш любимый редактор.
2. Указание git`у о ваших изменениях.
3. Создание коммита, используя то, что вы указали git на втором шаге.


На практике вы можете можно интерактивно повторять 1 и 2 шаги столько раз, сколько хотите; чтобы отследить то, что вы хотите включить в коммит на шаге 3, git сохраняет отпечаток структуры изменённого содержания в специальной области «индекс» (index).


В начале, содержимое индекса будет идентично тому, что уже есть в HEAD. Команда “git diff – cached” показывает разницу между HEAD и индексом, поэтому нет смысла запускать её в этой точке.


Измененить индекс просто:


Для обновления индекса изменённым содержимым файла, используйте

$ git add path/to/file

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

$ git add path/to/file

Для удаления файл из индекса и из рабочего дерева,

$ git rm path/to/file

После каждого шага можно проверить изменения :

$ git diff --cached

Команда git diff --cached всегда показывает разницу между HEAD и файлом индекса – это то, что попадает в проект, если вы сделаете коммит сейчас.

$ git diff

показывает разницу между рабочим деревом и файлом индекса. Заметьте, что “git add” всегда добавляет только текущие содержание файла индекса; дальнейшие изменения в один и тот же файл будут игнорироваться, если вы не запустите git-add ещё раз.


Когда все будет готово, просто запустите

$ git commit

и git даст приглашение для ввода сообщения о коммите и создаст новый коммит


Убедитесь, что это вы всё сделали правильно.

$ git show

Cпециальная опция -a

$ git commit -a

обновляет индекс со всеми файлами, которые вы изменили, удалили или создали и создаёт коммит в один шаг.


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

$ git diff --cached # разница между HEAD и индексом, которая
# зафиксируется, если делать коммит сейчас
$ git diff # разница между индексом и вашим рабочим каталогом которые не
# зафиксируются, если делать коммит сейчас
$ git diff HEAD # разница между HEAD и рабочим каталогом, которая будет зафиксирована
# если сделать сейчас commit -a
$ git status # краткий суммарный отчёт о состоянии индекса, рабочего каталога и HEAD.

Вы также можете использовать git-gui(1) для создания коммита, просмотра изменений в индексе и в рабочем каталоге, индивидуально выбрать кусок изменений для включения в индекс (правым кнопкой мыши на кусок diff и выбрав пункт “Stage Hunk For Commit”).

4. Создание хорошего описания коммита

Хотя это и не требуется, приветствуется стиль оформления сообщения о коммите в котором оно начинается со строки с кратким описанием изменений (менее 50 символа), а уже потом после пустуй строки подробным описанием изминений. Это позволяет превращать коммит в email – первую строку помещаем в тему письма, а остальное в его тело.

5. Игнорирование файлов


При работе с проект часто созжаются файлы, которые вы-бы не хотели отслеживать с помощью git. Это обычно файлы созданные процессом сборки и временные резервные копии файлов, созданных вашим редактором. Естественно, нет смысла отслеживать такие файлы и законно возникает вопрос – как сделать так, чтобы вызов “git add” не добавлял их. Отслеживание их быстро начинает раздражатью Из-за изменений этих файлов становятся практически бесполезны команды “git add .» и “git commit -a”, а изменения этих файлов засоряют вывод команды “git status”.


Вы можете указать git игнорировать определенные файлы, создав файл с именем .gitignore в верхнем уровне вашего рабочего каталога, например, с таким содержанием:

# Строки, начинающиеся с '#' считаются комментариев.
# Игнорировать любой файл с именем foo.txt.
foo.txt
# Игнорировать (генерируются) html файлы,
*.html *. html
# Кроме foo.html который включается в индекс вручную.
!foo.html ! foo.html
# Игнорировать файлы с расширением *.a и *.o
*.[oa]

См. gitignore (5) для детального объяснения синтаксиса. Вы также можете разместить файлы .gitignore в другие каталоги вашего рабочего каталога, и они будут распространяться на эти каталоги и их подкаталоги. Файлы .gitignore могут быть добавлены в репозиторий подобно другим файлам (просто запустив git add .gitignore, как обычно), удобно также сделать так, что-бы при клонировании репозитория другими пользователями по этим шаблонам эти файлы исключались из копирования. Если вы хотите, чтобы исключающие шаблоны влияли только в некоторых репозиториях (вместо каждого репозитория для данного проекта), вы можете поместить шаюлоны в файл вашего репозитория с именем .git/info/exclude, или в файл, задаваемый значением переменной core.excludesfile вашей конфигурации.


Некоторые git команды могут также исключатm шаблоны непосредственно в командной строке. Подробнее см. man gitignore (5) .

6. Как осуществить слияние

Вы можете объединить две разделённые ветви разработки командой git-merge(1):

$ git merge branchname

при этом сливается ветка разработки “branchname» c текущей веткой. Если есть конфликты, например, если один и тот же файл изменяется двумя различными способами в удалённой ветке и в локальной ветке, вы будете предупреждены; вывод будет выглядеть примерно так:

$ git merge next
100% (4/4) done
Auto-merged file.txt
CONFLICT (content): Merge conflict in file.txt
Automatic merge failed; fix conflicts and then commit the result.

Перевод сообщения:

# Авто-слияние file.txt
# Конфликт (содержимого): Конфликт слияния в file.txt
# Автоматическое слияние с ошибкой; устраните конфликты, а затем включите результат
# в коммит.

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


Если рассматривать результирующий коммит используя gitk, можно увидеть, что он имеет двух родителей один из которых вершина текущей ветки, а другой – вершина другой ветки.

7. Разрешение конфликтов объединений

Если слияние не произошло автоматически, git помещает индекс и рабочий катвалог в специальное состояние содержащее всю необходимую информацию чтобы помочь разрешить конфликт слияния. Файлы с конфликтами помечены в индексе специально, так, что до тех пор, пока вы решите проблему и не обновите индекс, совершить git-commit(1) не удастся:


$ git commit
file.txt: needs merge file.txt
#необходимо объединить file.txt

Кроме того, в git-status(1) будут перечислены эти файлы, как “unmerged” (необъединённые), а файлы с конфликтами будет помечены маркерами конфликта, например:


<<<<<<< HEAD:file.txt
Hello world
=======
Goodbye
>>>>>>> 77976da35a11db4580b80ae27e8d65caf5208086:file.txt

Все, что вам необходимо сделать, это отредактировать файлы для разрешения конфликтов, а затем дать команды

$ git add file.txt
$ git commit

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


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

7.1. Получение помощи при разрешения конфликтов слияния


Все изменения, которые git смог объединить автоматически уже добавлены в файл индекса, так что git-diff(1) показывает только конфликты. Используется особый синтаксис:

$ git diff
diff --cc file.txt
index 802992c,2b60207..0000000
--- a/file.txt
+++ b/file.txt
@@@ -1,1 -1,1 +1,5 @@@
++<<<<<<< HEAD:file.txt
+Hello world
++=======
+ Goodbye
++>>>>>>> 77976da35a11db4580b80ae27e8d65caf5208086:file.txt

Напомним, что комммит, который будут зафиксирован после того, как мы урегулировали конфликт будет иметь двух родителей, а не одного: один из родителей будет HEAD – вершина текущей ветки; а другой будут вершиной другой ветви, значение которой временно сохраняется в переменной MERGE_HEAD. В ходе слияния, индекс содержит три версии каждого файла.
Каждая из этих трех «стадий файла» представляет различные версии файла:

$ git show :1:file.txt # файл в общий предке обеих ветвей
$ git show :2:file.txt # Версия HEAD, но и в том числе любое
# неконфликтное изменение из MERGE_HEAD
$ git show :3:file.txt # версия с MERGE_HEAD, но и в том числе любое
# не конфликтующее изменение от HEAD.

Начиная со стадии 2 и стадии 3 версии были обновлены с неконфликтными изменениями, и остающиеся разлияия между ними являются существенной для анализа слияния, и которую можно получить командой git-diff(1) для из индекса для показа этих оставшихся конфликтов.


Команда git diff показывает различия между версией рабочего каталога file.txt и версиями стадии 2 и стадии 3.
Таким образом заменяя в каждой строке один "+" или “-", он теперь использует две колонки: первая колонка используется для различия между первым родителем и рабочий каталогом, а вторая отмечает различия между вторым родителем и рабочий каталогом. (См. “COMBINED DIFF FORMAT” раздела git-diff-files(1) для деталей формата.)


После разрешения конфликта обычным способом (но до обновления индекса), сравнения это будет выглядеть следующим образом:

$ git diff
diff --cc file.txt
index 802992c,2b60207..0000000
a/file.txt
+++ b/file.txt
@@@ -1,1 -1,1 +1,1 @@@
– Hello world
-Goodbye
++Goodbye world

Здесь видно, что наше версия решение исключить “Hello world” от первого родителя, удалить “Goodbye” от второго родителя, и добавить: “Goodbye world”, которое ранее отсутствовало в обоих предках.


В некоторых особые опции diff позволяют находить различия рабочего каталога от любого из этих этапов:

$ git diff -1 file.txt # различий с этапом 1
$ git diff --base file.txt # как выше
$ git diff -2 file.txt # различий c этапом 2
$ git diff --ours file.txt # как выше
$ git diff -3 file.txt # различий c этапом 3
$ git diff --theirs file.txt # как выше.

Командами git-log(1) и gitk[1] также обеспечивается помощь при слиянии:

$ git log --merge
$ gitk --merge

Они будут показывать все коммиты, которые существуют только в HEAD и в MERGE_HEAD, и которых касаются необъеденяемый файл.


Вы также можете использовать git-mergetool(1) которая позволяет объединить необъеденённые файлы с помощью внешних средств, таких как emacs или kdiff3.


Каждый раз, когда вы урегулировать конфликты в файле и обновляя индекс:

$ git add file.txt

различные этапы этого файла будет «коллапсировать», после чего git-diff уже не будут (по умолчанию) показывать различия для этого файла.

8. Отмена слияния

Если вы не смогли слить ветви и решили просто отказаться и отказаться, вы всегда можете вернуться к состоянию до слияния :

$ git reset --hard HEAD

Или, если вы уже зафиксировали слияние коммитом, что вы хотите его отменить,


$ git reset --hard ORIG_HEAD


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

9. Быстрое слияние вперёд

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


Однако, если текущая ветка является потомком другой и каждый коммит всегда один и всегда содержат коммит предыдущего, то можно просто выполнив команду git`ом “fast forward” (Быстрое движение вперёд) вершина текущей ветки продвинется вперед до точки вершины объединения в новую ветвь, без каких-либо новых созданий коммитов.

10. Исправление ошибок

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

$ git reset --hard HEAD

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


  1. Вы можете создавать новые коммит, в котором отменить всё, что вы сделали в старом коммите. Это правильный вариант, если ваши ошибки уже были преданы гласности.
  2. Ни в коем случае не делайте этого, если вы уже сделали историю гласной; git обычно не ожидает изменения истоии проекта, и не может корректно выполнять частые слияния с веткой, у которой имело изменение истории. Напрример, от удаляемого вами коммита кто-то уже мог создать отдельную ветку разработки и такая ветка не сможет быть в дальнейшем корректно слита с вашим проектом.

10.1. Исправление ошибки новым коммитом

Создание нового коммита, который отменяет ранее сделанные исправления, очень легко, просто дайте команду git-revert(1) с ссылкой на плохой коммит; например, вернуться к последниме коммиту:

$ git revert HEAD

Это позволит создать новыЙ коммит, который “откатывает” изменения HEAD. Вам будет предоставлена возможность отредактировать сообщение для совершения нового коммита.


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

$ git revert HEAD^

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


Если последние изменения пересекаются с изменениями будет восстановления, Вам будет предложено устранить конфликты вручную, как и в случае удалени конфликтов a merge .

10.2. Исправление ошибки путём переписывания истории

Если взять проблематичный коммит является последним коммитом, и вы еще не сделали его публичным, вы можете просто удалить его, используя git-reset .


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

$ git commit --amend

который заменит старый коммит новым путём включения ваших изменений, и давая вам возможность изменить вначале старое сообщение коммита.
Опять же, вы никогда не должны делать это с коммитом который уже был объединён в другую ветвь, в этом случае лучше использовать git-revert(1).
Кроме того, можно заменить более старые коммиты в истории, но это более сложная тема и мы оставим её его для другой главы.

10.3. Извлечение старой версии файла

В процессе отмены предыдущих плохие изменений, вы можете обнаружить, что было-бы полезно проверить более старую версию файла командой git-checkout(1). Мы использовали уже git checkout раньще, что-бы сменить текущую ветку, но эта команда работает совершенно по-другому, если в качестве аргумента получает путь до файла :

$ git checkout HEAD^ path/to/file

заменяет содержимое указанного файла, и из коммита HEAD^, а также обновляет соответственно индекс. Команда не меняет текущую ветвь. Если вы просто хотите взглянуть на старую версию файла без изменения рабочего каталога, вы можете сделать git-show(1):

$ git show HEAD^:path/to/file

который будут отображён с учетом версии файла.

10.4. Временный отказ от проделанной работы

Допустим вы находитесь в середине работы над чем-то сложным, и обнаруживаете не очевидную, но тривиальную ошибку. Вы хотите её исправить, прежде чем продолжать работу дальше. Вы можете применить git-stash(1) для сохранения текущего состояние вашей работы, и после устранения ошибки (или, по желанию после перехода на другие ветки и возврата обратно), даёте команду восстановления для продолжения вашей прерванной работы.



W – точка, где вы работали,
H — текущая HEAD,
I — точка коммита с исправлением выявленной тривиальной ошибки.


$ git stash “work in progress for foo feature”

Эта команда сохраняет все изменения “в тайнике” (stash), и возвращает рабочий каталог и индекс к HEAD. Затем вы можете исправить, тривиальную проблему и зафиксировать её решение.

... исправляем тривиальные ошибки ...
$ git commit -a -m “blorpl: typofix”

После этого вы можете вернуться к тому, что вы делали до git stash командой:

$ git stash apply

11. Обеспечение эффективной деятельности

Размер репозитории git зависит от сжатия сохранённой истории информации. Сжатие не даёт занять репозиторию слишком много места на диске и в памяти. Сжатие не выполняется автоматически. Поэтому вы должны периодически запускать git-gc(1) :

$ git gc 

для повторения сжатия архива. Это может занять очень много времени, поэтому вы, возможно, предпочтете запустить git-gc, тогда, когда это вам не будет мешать работать.

12. Обеспечение надёжности

12.1. Проверка репозитория от порчи


Команда git-fsck(1) запускает ряд логических самопроверок репозитория, и создаёт отчёт о всех имеющихся проблемах. Этот процесс может занять некоторое время. Наиболее распространенными это предупреждение о «зависших» объектах:

$ git fsck
dangling commit 7281251ddd2a61e38657c827739c57015671a6b3
dangling commit 2706a059f258c6b245f298dc4ff2ccd30ec21a63
dangling commit 13472b7c4b80851a1bc551779171dcb03655e9b5
dangling blob 218761f9d90712d37a9c5e36f406f92202db07eb
dangling commit bf093535a34a4d35731aa2bd90fe6b176302f14f
dangling commit 8e4bec7f2ddaa268bef999853c25755452100f8e
dangling tree d50bb86186bf27b681d25af89d3b5b68382e4085
dangling tree b24c2473f1fd3d91352a624795be026d64c8841f
....

Зависание объектов не проблема. В худшем случае они бесполезно занимают место на диске. Они иногда могут стать последним средством в восстановлении потерянных наработок – см. Раздел “Dangling objects” для более детальной информации.

12.2. Восстановление потерянных изменений

12.2.1. Журнал reflog

Скажем вы изменили ветвь git-reset(1) —hard а потом сообразили, что ветвь была была только ссылкой на точку в истории. К счастью, git также ведет журнал, называемый “reflog”, о всех предыдущих значений каждой ветви. Так что в этом случае вы все ещё можете найти старую историю, используя, например,

$ git log master@{1}

Эта команда выдаёт список коммитов о предыдущего версиях вершины ветки “master”. Cинтаксис может быть использован с любыми командами git, которые принимают коммит, а не только с git log. Некоторые примеры:

$ git show master@{2} # Смотрим где ветвь указывает 2,
$ git show master@{3} # 3, ... изменения назад.
$ gitk master@{yesterday} # Смотрим что изменилось вчера,
$ gitk master@{"1 week ago"} # ... неделю назад
$ git log --walk-reflogs master # смотрим содержимое reflog ветки master

Посмотреть reflog сохранённый в HEAD, можно так

$ git show HEAD@{"1 week ago"}

Команда покажет, на что указывало HEAD неделю назад, а не то, что текущая ветвь указала неделю назад. Это позволяет просматривать историю о том, с чем вы работали .
Reflogs хранятся по умолчанию в течение 30 дней, после чего он будет обрезан. См. git-reflog(1) и git-gc(1) чтобы узнать, как управлять этим обрезанием, и смотрите секцию “SPECIFYING REVISIONS” git-rev-parse(1) для изучения подробностей.


Заметьте, что reflog история сильно отличантся от обычной истории git истории.


Обычная история отражает совместное использование репозитория всех, кто работает с этим проектом, а reflog история локальна: она говорит вам лишь о том, какие ветки в локальном репозитории были изменены и в какой момент времени.

12.3. Изучение зависших объектов

В некоторых ситуациях reflog, возможно, не сможет вам помочь.
Например, предположим, вы удалили ветвь, в истории которой содержался необходимый вам релиз. Reflog также был удалён, однако, если вы еще не очищали от мусора репозиторий, то вы по-прежнему ещё можете найти потерянный вами коммит в зависших объектах, о которых вам сообщает команда git-fsck.
См. раздел “Dangling objects” для изучения деталей.

$ git fsck
dangling commit 7281251ddd2a61e38657c827739c57015671a6b3
dangling commit 2706a059f258c6b245f298dc4ff2ccd30ec21a63
dangling commit 13472b7c4b80851a1bc551779171dcb03655e9b5
...

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

$ gitk 7281251ddd --not --all

которая делает буквально то, что в ней задано: это означает, что вы хотите увидеть историю описанного зависшего коммита, исключая из неё историю существующих ныне ветвей и тегов.
Таким образом, вы получаете историю от какого-то существующего коммита до потеренного. (И заметим, что эта история может содержать не один коммит: мы ведь получали информацию только о «конце линии» которая зависла, но перед ней может находиться долгоя и сложная история коммита, которая также была отброшена).


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

$ git branch recovered-branch 7281251ddd

Другие виды зависших объектов (blobs и trees), так-же могут существовать, и эти зависшие объекты могут возникать в разных ситуациях.


Назад Содержание Далее?


 
Файлов нет. [Показать файлы/форму]
Комментариев нет. [Показать комментарии/форму]