Дополнительно
В заключительной части нашего руководства мы поделимся некоторыми дополнительными приемами, которые могут оказаться полезными.
1. Отслеживание изменений, сделанных в коммитах
Каждый коммит имеет уникальный идентификатор, представляющий собой строку из букв и цифр. Чтобы увидеть список всех коммитов с их идентификаторами, воспользуемся командой log:
$ git log commit ba25c0ff30e1b2f0259157b42b9f8f5d174d80d7 Author: Tutorialzine Date: Mon May 30 17:15:28 2016 +0300 New feature complete commit b10cc1238e355c02a044ef9f9860811ff605c9b4 Author: Tutorialzine Date: Mon May 30 16:30:04 2016 +0300 Added content to hello.txt commit 09bd8cc171d7084e78e4d118a2346b7487dca059 Author: Tutorialzine Date: Sat May 28 17:52:14 2016 +0300 Initial commit
Как видно, идентификаторы имеют значительную длину, но для работы достаточно использовать только первые несколько символов. Для просмотра изменений, внесенных в коммит, мы можем использовать команду show [commit]
$ git show b10cc123 commit b10cc1238e355c02a044ef9f9860811ff605c9b4 Author: Tutorialzine Date: Mon May 30 16:30:04 2016 +0300 Added content to hello.txt diff --git a/hello.txt b/hello.txt index e69de29..b546a21 100644 --- a/hello.txt +++ b/hello.txt @@ -0,0 +1 @@ +Nice weather today, isn't it?
Для того чтобы сравнить изменения между двумя коммитами, нам пригодится команда diff (с указанием диапазона между коммитами):
$ git diff 09bd8cc..ba25c0ff diff --git a/feature.txt b/feature.txt new file mode 100644 index 0000000..e69de29 diff --git a/hello.txt b/hello.txt index e69de29..b546a21 100644 --- a/hello.txt +++ b/hello.txt @@ -0,0 +1 @@ +Nice weather today, isn't it?
В приведенном примере мы сравнили первый и последний коммиты, чтобы выяснить, какие изменения были добавлены со временем. Обычно проще работать с графическими инструментами управления версиями, поскольку они предоставляют удобный интерфейс для ознакомления с изменениями.
2. Возвращение файла к предыдущему состоянию
Git позволяет вернуть файл к состоянию в момент определенного коммита. Для этого достаточно использовать команду checkout
, которую мы ранее
применяли для переключения веток. Но мы также можем применять ее для работы с коммитами — такое использование команды достаточно характерно для Git,
так как одна команда может выполнять разные задачи. В следующем примере мы вернем файл hello.txt к его первоначальному виду, используя идентификатор
первого коммита и его путь:
$ git checkout 09bd8cc1 hello.txt
3. Исправление коммита
Если вы допустили ошибку в комментарии или забыли добавить файл и обнаружили это сразу после коммита, нет необходимости беспокоиться.
Команда commit --amend
быстренько решит эту проблему. Она переносит изменения последнего коммита в область подготовленных файлов и позволяет
создать новый коммит, исправив при этом комментарий или добавив недостающие файлы. Однако для более сложных случаев, например, если правки вносятся не
в последний коммит или уже были отправлены на сервер, мы воспользуемся командой revert
. Она создает коммит, аннулирующий изменения, внесенные
в указанный коммит. Использование алиаса HEAD
позволяет обратиться к самому последнему коммиту:
$ git revert HEAD
Для остальных коммитов используйте их идентификаторы:
$ git revert b10cc123
Исправление старых коммитов может вызвать конфликты. Это происходит, если файл был изменен новыми коммитами, и Git не может найти строки для отката к предыдущему состоянию, поскольку они были удалены или изменены.
4. Разрешение конфликтов при слиянии
Конфликты могут возникать регулярно, например, при слиянии ветвей или отправке изменений в общую ветку. Иногда конфликты решаются автоматически, но чаще
всего их необходимо разрешать вручную, выбирая, какой код стоит сохранить, а какой — удалить. Рассмотрим пример, где мы объединим две ветки под именами
john_branch
и tim_branch
, где каждая из веток вносит изменения в одну и ту же функцию, отображающую элементы массива.
Джон предпочитает использовать цикл:
// Use a for loop to console.log contents.
for(var i=0; i<arr.length; i++) {
console.log(arr[i]);
}
Тим, в свою очередь, использует forEach
:
// Use forEach to console.log contents.
arr.forEach(function(item) {
console.log(item);
});
Оба разработчика коммитят свои версии кода в свои ветки. Когда они пытаются объединить изменения, они сталкиваются с конфликтом:
$ git merge tim_branch Auto-merging print_array.js CONFLICT (content): Merge conflict in print_array.js Automatic merge failed; fix conflicts and then commit the result.
Git не смог разрешить конфликт автоматически, и теперь это задача для разработчиков. Конфликтующие строки отмечены в файле:
<<<<<<< HEAD // Use a for loop to console.log contents. for(var i=0; i <arr.length; i++) { console.log(arr[i]); } ======= // Use forEach to console.log contents. arr.forEach(function(item) { console.log(item); }); >>>>>>> Tim's commit.
Верхняя часть отмеченного фрагмента (до разделителя =======) показывает версию (HEAD)
, а нижняя часть — конфликтующую. Это позволяет увидеть
различия и определить, какую строку оставить. Или же, если необходимо, написать собственный вариант, который разрешит конфликт. В данном случае мы выберем
третий путь и напишем что-то новое, убрав ненужные разделители. После этого сообщим Git, что работа завершена.
// Not using for loop or forEach. // Use Array.toString() to console.log contents. console.log(arr.toString());
Когда всё готово, останется лишь закоммитить изменения, чтобы завершить объединение:
$ git add -A $ git commit -m "Array printing conflict resolved."
Как видим, этот процесс может быть довольно сложным и затруднительным, особенно в рамках больших проектов. Поэтому многие разработчики предпочитают графические
утилиты для упрощения работы с конфликтами. Чтобы запустить такой инструмент, достаточно ввести команду git mergetool
.
5. Настройка .gitignore
В большинстве проектов существуют файлы или каталоги, которые мы не хотим (и зачастую не должны) добавлять в репозиторий. Мы можем гарантировать их
исключение из git add -A
, используя файл .gitignore.
- Создайте в корне проекта файл с именем
.gitignore
. - Список файлов и папок, которые должны игнорироваться, укажите в нем, пронумеровав их по одной строке.
- Как и любой другой файл проекта, .gitignore необходимо добавить в систему контроля версий, закоммитить и отправить на сервер.
Вот несколько примеров файлов, которые часто игнорируются:
- Логи
- Файлы, генерируемые системой сборки
- Папки node_modules в проектах на Node.js
- Папки, создаваемые IDE, такие как Netbeans или IntelliJ
- Различные личные заметки разработчиков.
Пример файла .gitignore, содержащего перечисленные выше элементы, может выглядеть так:
*.log build/ node_modules/ .idea/ my_notes.txt
Слэш в конце некоторых строк указывает на директорию и свидетельствует о том, что игнорируется всё её содержимое на всех уровнях. Звёздочка, как обычно, служит шаблоном.
Заключение
На этом мы завершаем наше руководство. Мы постарались собрать и изложить наиболее важную информацию максимально кратко и чётко.
Git — это
обширный инструмент со множеством функций и возможностей. Для желающих углубиться в изучение Git мы рекомендуем следующие ресурсы: