Подробное введение в работу с Git

Что такое Git и зачем он мне?

Git — это распределённая система контроля версий, которая позволяет сохранять все изменения, внесённые в файлы, хранящиеся в репозитории. Изменения хранятся в виде снимков, называемых коммитами, которые могут размещаться на многих серверах. Считайте это стандартным облаком для бэкапов на стероидах — вы не только можете восстановить код в случае сбоя, но и откатить код до любого из предыдущих сохранённых состояний. Также вы легко можете взаимодействовать с другими разработчиками — опять же, как несколько человек могут работать над одним файлом в Google Docs, так и разработчики могут одновременно работать над одним репозиторием и сохранять свои изменения.

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

Как работать с Git

В Git доступно множество команд, поэтому полезно разбить их по теме/причине использования. Сначала мы рассмотрим работу с Git на локальной машине, так как большинство операций происходят именно там, а затем перейдём к многопользовательскому формату.

С Git можно работать как через командную строку, так и через графический интерфейс вроде GitHub Desktop. Хотя начинающих разработчиков командная строка может отпугнуть, её всё равно лучше изучить, ведь она предоставляет больше возможностей, чем многие инструменты с интерфейсом.

Как правило, команды Git принимают вид git <команда> <аргументы>, где аргументом может быть путь к файлу. У команд также могут быть опции, которые обозначаются как --<опция> или -<однобуквенная опция>. Они позволяют более детально настроить действия команды. В этой статье команды будут представлены в общем виде, поэтому всё, что находится в <>, вам нужно будет заменить на собственные значения.

Если вы не знаете, как использовать команду, то можете открыть руководство с помощью git help <команда>, а если вам просто нужно напоминание, используйте git <команда> -h или git <команда> --help (--help и -h эквивалентны).

Подготовка Git

Установка Git

Пользователи Windows могут скачать его отсюда.

В macOS (OS X) Git поставляется как часть инструментов командной строки XCode, поэтому нужно их установить. Чтобы проверить наличие Git, откройте терминал и введите git --version для проверки версии.

Если вы пользуетесь Linux, то используйте команду sudo apt install git-all (дистрибутивы на основе Debian) или sudo dnf install git-all (на основе RPM).

Настройка конфигурационного файла

Первое, что нужно сделать после установки Git, — настроить имя пользователя и email, так как они используются для идентификации и хранятся во всех сделанных вами снимках. Эти настройки вместе со всеми остальными хранятся в конфигурационном файле.

Вы можете либо напрямую отредактировать файл .gitconfig с помощью текстового редактора, либо с помощью команды git config --global --edit, а также можете отредактировать отдельные поля, используя команду git config --global <поле> <значение> — нас интересуют поля user.name и user.email.

Также можно настроить текстовый редактор для написания сообщений коммитов, используя поле core.editor. Изначально используется системный редактор по умолчанию, например, vi для Linux/Mac. Поле commit.template позволяет указать шаблон, который будет использоваться при каждом коммите.

Есть множество других полей, однако одно из самых полезных — это alias, которое привязывает команду к псевдониму. Например, git config --global alias.st "status -s" позволяет использовать git st вместо git status -s

Команда git config --list выведет все поля и их значения из конфигурационного файла.

Создаём Git-репозиторий

Для инициализации нового репозитория .git можно использовать команду git init или, если вы хотите скопировать существующий, git clone <адрес репозитория>.

История коммитов в Git

Git хранит данные в виде набора легковесных «снимков», известных как коммиты. Они хранят состояние файловой системы в определённый момент времени, а также указатель на предыдущий(-ие) коммит(-ы). Каждый коммит содержит уникальную контрольную сумму — идентификатор, который Git использует, чтобы ссылаться на коммит. Чтобы отслеживать историю, Git хранит указатель HEAD, который указывает на первый коммит (мы следуем по цепочке коммитов в обратном порядке, чтобы попасть к предыдущим коммитам).

Мы можем ссылаться на коммит либо через его контрольную сумму, либо через его позицию относительно HEAD, например HEAD~4 ссылается на коммит, который находится 4 коммитами ранее HEAD.

Файловая система Git

Git отслеживает файлы в трёх основных разделах:

  • рабочая директория (файловая система вашего компьютера);
  • область подготовленных файлов (staging area, хранит содержание следующего коммита);
  • HEAD (последний коммит в репозитории).

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

Просмотр изменений в файловых системах

Команда git status отображает все файлы, которые различаются между тремя разделами. У файлов есть 4 состояния:

  1. Неотслеживаемый (untracked) — находится в рабочей директории, но нет ни одной версии в HEAD или в области подготовленных файлов (Git не знает о файле).
  2. Изменён (modified) — в рабочей директории есть более новая версия по сравнению с хранящейся в HEAD или в области подготовленных файлов (изменения не находятся в следующем коммите).
  3. Подготовлен (staged) — в рабочей директории и области подготовленных файлов есть более новая версия по сравнению с хранящейся в HEAD (готов к коммиту).
  4. Без изменений — одна версия файла во всех разделах, т. е. в последнем коммите содержится актуальная версия.

Примечание Файл может быть одновременно в состоянии «изменён» и «подготовлен», если версия в рабочей директории новее, чем в области подготовленных файлов, которая в свою очередь новее версии в HEAD.

Мы можем использовать опцию -s для команды git status, чтобы получить более компактный вывод (по строке на файл). Если файл не отслеживается, то будет выведено ??; если он был изменён, то его имя будет красным, а если подготовлен — зелёным.

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

  • git diff — сравнение рабочей директории с областью подготовленных файлов;
  • git diff --staged — сравнение области подготовленных файлов с HEAD.

Если использовать аргумент <файл/папка>, то diff покажет изменения только для указанных файлов/папок, например git diff src/.

Обновление файловых систем

Команда git add <файл/папка> обновляет область подготовленных файлов версиями файлов/папок из рабочей директории.

Команда git commit обновляет HEAD новым коммитом, который делает снимки файлов в области подготовленных файлов.

Действие команды git reset <коммит> состоит из трёх потенциальных шагов:

  1. Переместить указатель HEAD на <коммит> (например, при откате коммита в рабочей директории и области подготовленных файлов будут более новые версии файлов, чем в HEAD). Также указатель HEAD ветки будет перемещён на этот коммит.
  2. Обновить область подготовленных файлов содержимым коммита. В таком случае только в рабочей директории будут новейшие версии файлов.
  3. Обновить рабочую директорию содержимым области подготовленных файлов. С этим нужно быть осторожнее, поскольку в итоге будут уничтожены изменения файлов.

По умолчанию команда git reset выполняет только шаги 1 и 2, однако её поведение можно изменить с помощью опций --soft (только 1 шаг) и --hard (все шаги).

Если передать путь к файлу/папке, то команда будет выполнена только для них, например git reset --soft HEAD~1 src/.

Команда git checkout HEAD <файл> приводит к тому же результату, что и git reset --hard HEAD <файл> — перезаписывает версию файла в области подготовленных файлов и в рабочей директорией версией из HEAD, то есть отменяет изменения после последнего коммита.

С другой стороны, git checkout <файл> (уже без HEAD) перезаписывает версию файла в рабочей директории версией в области подготовленных файлов, то есть отменяет изменения с момента последней подготовленной версии.

Наконец, git rm <файл> отменяет отслеживание файла и удаляет его из рабочей директории, опция --cached позволит сохранить файл.

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

Зачастую нам не нужно, чтобы Git отслеживал все файлы в репозитории, потому что в их число могут входить:

  • файлы с чувствительной информацией вроде паролей;
  • большие бинарные файлы;
  • файлы сборок, которые генерируются после каждой компиляции;
  • файлы, специфичные для ОС/IDE, например, .DS_Store для macOS или .iml для IntelliJ IDEA — нам нужно, чтобы репозиторий как можно меньше зависел от системы.

Для игнорирования используется файл .gitignore. Чтобы отметить файлы, которые мы хотим игнорировать, можно использовать шаблоны поиска (считайте их упрощёнными регулярными выражениями):

  • /___ — позволяет избежать рекурсивности — соответствует файлам только в текущей директории;
  • __/ — соответствует всем файлам в указанной директории;
  • *___ — соответствует всем файлам с указанным окончанием;
  • ! — игнорирование файлов, попадающих под указанный шаблон;
  • [__] — соответствует любому символу из указанных в квадратных скобках;
  • ? — соответствует любому символу;
  • /**/ — соответствует вложенным директориям, например a/**/d соответствует a/d, a/b/d, a/b/c/d и т. д.

Примеры файлов .gitignore.

Мы даже можем использовать шаблоны поиска при указании файла/папки в других командах. Например, git add src/*.css добавит все файлы .css в папке src.

Коммиты

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

Команда git commit откроет текстовый редактор для ввода сообщения коммита. Также эта команда принимает несколько распространённых аргументов:

  • -m позволяет написать сообщение вместе с командой, не открывая редактор. Например git commit -m "Пофиксил баг";
  • -a переносит все отслеживаемые файлы в область подготовленных файлов и включает их в коммит (позволяет пропустить git add перед коммитом);
  • --amend заменяет последний коммит новым изменённым коммитом, что бывает полезно, если вы неправильно набрали сообщение последнего коммита или забыли включить в него какие-то файлы.

Несколько советов, к которым стоит прислушаться:

  • Коммитьте часто: вы не сможете откатить изменения, если откатывать не к чему.
  • Одно изменение — один коммит: не помещайте все не связанные между собой изменения в один коммит, разделите их, чтобы было проще откатиться.
  • Формат сообщений: заголовок должен быть в повелительном наклонении, меньше 50 символов в длину и должен логически дополнять фразу this commit will ___(this commit will fix bugs — этот коммит исправит баги). Сообщение должно пояснять, почему был сделан коммит, а сам коммит показывает, что изменилось. Здесь подробно расписано, как писать сообщения для коммитов.
  • (Опционально) Не коммитьте незначительные изменения: в большом репозитории множество небольших коммитов могут засорить историю. Хорошим тоном считается делать такие коммиты при разработке, а при добавлении в большой репозиторий объединять их в один коммит.

Просмотр изменений в истории

Для просмотра истории предыдущих коммитов в обратном хронологическом порядке можно использовать команду git log. Ей можно передать разные опции:

  • -p показывает изменения в каждом коммите;
  • --stat показывает сокращённую статистику для коммитов, например изменённые файлы и количество добавленных/удалённых строк в каждом их них;
  • -n показывает n последних коммитов;
  • --since=___ и --until=___ позволяет отфильтровать коммиты по промежутку времени, например --since="2019-01-01" покажет коммиты с 1 января 2019 года;
  • --pretty позволяет указать формат логов (например, --pretty=oneline), также можно использовать --pretty=format для большей кастомизации, например --pretty=format:"%h %s";
  • --grep и -S фильтруют коммиты с сообщениями/изменениями кода, которые содержат указанную строку, например, git log -S имя_функции позволяет посмотреть добавление/удаление функции;
  • --no-merges пропускает коммиты со слиянием веток;
  • ветка1..ветка2 позволяет посмотреть, какие коммиты из ветки 2 не находятся в ветке 1 (полезно при слиянии веток). Например, git log master..test покажет, каких коммитов из ветки test нет в master (о ветках поговорим чуть позже).
  • --left-right ветка1...ветка2 показывает коммиты, которые есть либо в ветке 1, либо в ветке 2, но не в обеих; знак < обозначает коммиты из ветка1, а > — из ветка2. Обратите внимание: используется три точки, а не две;
  • -L принимает аргумент начало,конец:файл или :функция:файл и показывает историю изменений переданного набора строк или функции в файле.

Другой полезной командой является git blame <файл>, которая для каждой строки файла показывает автора и контрольную сумму последнего коммита, который изменил эту строку. -L <начало>, <конец> позволяет ограничить эту команду заданными строками. Это можно использовать, например, для выяснения того, какой коммит привёл к определённому багу (чтобы можно было его откатить).

Наконец, есть команда git grep, которая ищет по всем файлам в истории коммитов (а не только в рабочей директории, как grep) по заданному регулярному выражению. Опция -n отображает соответствующий номер строки в файле для каждого совпадения, а --count показывает количество совпадений для каждого файла.

Примечание Не путайте git grep с git log --grep! Первый ищет по файлам среди коммитов, а последний смотрит на сообщения логов.

Удалённые серверы

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

Команда git remote -v выводит список удалённых репозиториев, которые мы отслеживаем, и имена, которые мы им присвоили.

При использовании команды git clone <url репозитория> мы не только загружаем себе копию репозитория, но и неявно отслеживаем удалённый сервер, который находится по указанному адресу и которому присваивается имя origin.

Наиболее употребляемые команды:

  • git remote add <имя> <url> — добавляет удалённый репозиторий с заданным именем;
  • git remote remove <имя> — удаляет удалённый репозиторий с заданным именем;
  • git remote rename <старое имя> <новое имя> — переименовывает удалённый репозиторий;
  • git remote set-url <имя> <url> — присваивает репозиторию с именем новый адрес;
  • git remote show <имя> — показывает информацию о репозитории.

Следующие команды работают с удалёнными ветками:

  • git fetch <имя> <ветка> — получает данные из ветки заданного репозитория, но не сливает изменения;
  • git pull <имя> <ветка> — сливает данные из ветки заданного репозитория;
  • git push <имя> <ветка> — отправляет изменения в ветку заданного репозитория. Если локальная ветка уже отслеживает удалённую, то можно использовать просто git push или git pull.

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

Ветвление

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

Это ведёт нас ключевой особенности Git — ветвлению, возможности работать над разными версиями проекта. Это значит, что вместо одного списка с упорядоченными коммитами история будет расходиться в определённых точках (что делает её похожей на дерево). Каждая ветвь в Git содержит легковесный указатель HEAD на последний коммит в этой ветке, что позволяет без лишних затрат создать много веток. Совет: называйте ветку в соответствии с разрабатываемой в ней функциональностью. Ветка по умолчанию называется master.

Итак, у нас есть общий указатель HEAD и HEAD для каждой ветки. Таким образом, переключение между ветками предполагает только перемещение HEAD в HEAD соответствующей ветки.

Стандартные команды:

  • git branch <имя ветки> — создаёт новую ветку с HEAD, указывающим на HEAD. Если не передать аргумент <имя ветки>, то команда выведет список всех локальных веток;
  • git checkout <имя ветки> — переключается на эту ветку. Можно передать опцию -b, чтобы создать новую ветку перед переключением;
  • git branch -d <имя ветки> — удаляет ветку.

Как наш локальный репозиторий, так и удалённый, могут иметь множество ветвей, поэтому когда вы отслеживаете удалённый репозиторий, на самом деле отслеживается удалённая ветка (git clone привязывает вашу ветку master к ветке origin/master удалённого репозитория).

Привязывание к удалённой ветке:

  • git branch -u <имя удалённого репозитория>/<удалённая ветка> — привязывает текущую ветку к указанной удалённой ветке;
  • git checkout --track <имя удалённого репозитория>/<удалённая ветка> — аналог предыдущей команды;
  • git checkout -b <ветка> <имя удалённого репозитория>/<удалённая ветка> — создаёт новую локальную ветку и начинает отслеживать удалённую;
  • git branch --vv — показывает локальные и отслеживаемые удалённые ветки;
  • git checkout <удалённая ветка> — создаёт локальную ветку с таким же именем, как у удалённой, и начинает её отслеживать.

В общем, git checkout связан с изменением места, на которое указывает HEAD ветки, что похоже на то, как git reset перемещает общий HEAD.

Прятки и чистка

Есть одна тонкость — при переключении веток Git требует, чтобы рабочее состояние было чистым, то есть все изменения в отслеживаемых файлах должны быть зафиксированы.

Прим. перев. Это не совсем так. При некоторых обстоятельствах Git может автоматически перенести незафиксированное изменение в другую ветку.

Однако порой у вас есть незавершённые изменения, которые нельзя фиксировать. В такой ситуации их можно сохранить и «спрятать» с помощью команды git stash. Чтобы вернуть изменения, используйте git stash apply.

Возможно, вместо этого вы захотите стереть все внесённые изменения. В таком случае используйте команду git clean. Опция -d также удалит неотслеживаемые файлы. Совет: добавьте опцию -n, чтобы увидеть, что произойдёт при запуске git clean без непосредственного использования.

Совмещение веток

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

Слияние

Оно включает в себя создание нового коммита, который основан на общем коммите-предке двух ветвей и указывает на оба HEAD в качестве предыдущих коммитов. Для слияния мы переходим на основную ветку и используем команду git merge <тематическая ветка>.

Если обе ветви меняют одну и ту же часть файла, то возникает конфликт слияния — ситуация, в которой Git не знает, какую версию файла сохранить, поэтому разрешать конфликт нужно собственноручно. Чтобы увидеть конфликтующие файлы, используйте git status.

После открытия таких файлов вы увидите похожие маркеры разрешения конфликта:

 <<<<<<< HEAD:index.html
 Everything above the ==== is the version in master. 
 =======
 Everything below the ==== is the version in the test branch. 
 >>>>>>> test:index.html

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

Перемещение

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

Для перемещения используется команда git rebase <основная ветка> <тематическая ветка>, которая воспроизводит изменения тематической ветки на основной; HEAD тематической ветки указывает на последний воспроизведённый коммит.

Перемещение vs. слияние

После слияния лог с историей может выглядеть довольно беспорядочно. С другой стороны, перемещение позволяет переписать историю в нормальной, последовательной форме.

Так зачем нужно слияние, если можно всё время пользоваться перемещением? К сожалению, перемещение не панацея от запутанных логов, так как перемещённые коммиты на самом деле отличаются от оригинальных, хотя и имеют одного и того же автора, сообщение и изменения.

Представим сценарий:

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

Поэтому вот совет:

Перемещайте изменения только на вашей приватной локальной ветке — не перемещайте коммиты, от которых зависит ещё кто-то.

Откат коммитов — revert и reset

Похожие дебаты по поводу того, что лучше использовать, возникают, когда вы хотите откатить коммит. Команда git revert <коммит> создаёт новый коммит, отменяющий изменения, но сохраняющий историю, в то время как git reset <коммит> перемещает указатель HEAD, предоставляя более чистую историю (словно бы этого коммита никогда и не было). Важно отметить, что это также означает, что вы больше не сможете вернуться обратно к этим изменениям, например, если вы всё-таки решите, что отмена коммита была лишней. Чище — не значит лучше!

Резюмируем

На этом этапе у вас есть почти всё необходимое для работы с Git. Ниже будет представлено несколько (опциональных) продвинутых советов для большего контроля над коммитами и историей. Кроме того, далее мы вскользь затронем GitHub — одну из наиболее известных платформ, работающих с Git, которая может вам пригодиться.

GitHub

GitHub — это платформа, которая хранит Git-репозитории на своих множественных серверах. Как пользователь GitHub вы можете хранить свои удалённые репозитории на их серверах, а также вносить вклад в другие open-source репозитории. GitHub дополняет использование Git некоторыми новыми возможностями.

Например, вы можете сделать форк удалённого репозитория, то есть создать свою копию репозитория на севере GitHub. Это полезно в тех случаях, когда у вас нет прав на создание ветки в оригинальном репозитории. Когда вы воспользуетесь командой git clone, ваш локальный репозиторий будет отслеживать удалённый форк как origin, а оригинальный репозиторий как upstream.

После этого вам может понадобиться слить тематическую ветку вашего удалённого репозитория в основную ветку оригинального. Для этого вы можете создать новый Pull Request — запрос на внесение изменений, где GitHub проверяет наличие конфликтов прежде чем повзолить вам провести слияние. Зачастую существуют и другие проверки перед слиянием, например просмотр и одобрение кода или даже запуск тестов. В запросе можно обсудить код, а все коммиты, которые вы отправляете в удалённую тематическую ветку, будут автоматически добавлены в запрос, даже если он был создан до этих коммитов.

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

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

  • status — показывает для каждого файла краткое описание того, что (не)подготовлено;
  • update — подготавливает отслеживаемые файлы;
  • revert — убрать один или несколько файлов из подготовленной области;
  • add untracked — подготавливает неотслеживаемый файл;
  • patch — подготавливает только часть файла (полезно, когда вы, например, изменили несколько функций, но хотите разбить изменения на несколько коммитов). После выбора файла вам будут показаны его фрагменты и представлены возможные команды: Stage this hunk [y,n,q,a,d,j,J,g,/,e,?]?. Можно ввести ?, чтобы узнать, что делает каждая команда;
  • diff — показывает список подготовленных файлов и позволяет посмотреть изменения для каждого из них;
  • quit — выходит из интерактивной консоли;
  • help — показывает краткое описание каждой команды.

Символ * рядом с файлом означает, что команда изменит его статус (подготовлен/неподготовлен в зависимости от того, происходит ли обновление или откат). Если нажать Enter, не введя ничего ни в одном из под-меню команды, то все файлы перейдут в (не)подготовленное состояние.

Обратите внимание, что создание патчей (подготовка только части файла) доступно не только в интерактивной консоли, но и через команду git add -p.

Продвинутое использование: правим историю

Для большего контроля над историей коммитов локальной ветки можно использовать команду git rebase -i HEAD~n, которая откроет интерактивную консоль для перемещения набора последних n коммитов, перечисленных в порядке от старых к новым (то есть в том порядке, в котором они будут перемещены). Таким образом вы можете «редактировать историю», однако помните, что оригинальные коммиты нельзя изменить, только переместить.

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

Измененяем сообщение коммита/разбиваем коммиты

Для указания коммита, который вы хотите изменить, используется команда edit. Затем, когда Git будет проводить перемещение, он остановится на этом коммите. После этого вы можете использовать git commit --amend, чтобы изменить сообщение или подготовить забытые файлы. Если вы хотите разделить коммит, после остановки введите git reset HEAD^ (в результате HEAD будет перемещён на один коммит назад и все изменённые в этом коммите файлы перейдут в статус неподготовленных). Затем вы сможете зафиксировать файлы в отдельных коммитах обычным образом.

После завершения редактирования введите git rebase --continue.

Перезапись нескольких коммитов

Иногда вам может потребоваться перезаписать несколько коммитов — в таких случаях можно использовать git filter-branch. Например, чтобы удалить случайно зафиксированный файл, можно ввести git filter-branch --tree-filter 'git rm -f <имя файла>' HEAD. Однако учтите, что при этом вся история перемещается.

Объединение нескольких коммитов

Во время работы над новой функцией в проекте вы можете постепенно фиксировать даже малейшие изменения в тематической ветке. Однако из-за этого история засоряется такими небольшими коммитами, что может противоречить правилам проекта. Это можно исправить, объединив несколько коммитов в один большой. Для этого сначала используйте команду pick для выбора первого коммита, а затем squash для последующих. Git применит все изменения в одном коммите и попросит отредактировать сообщение общего коммита.

 

Переносим отдельный коммит

Кроме слияния/перемещения всех коммитов в тематической ветке, вас может интересовать только определённый коммит. Допустим, у вас есть локальная ветка drafts, где вы работаете над несколькими потенциальными статьями, но хотите опубликовать только одну из них. Для этого можно использовать команду git cherry-pick. Чтобы получить определённые коммиты, из которых мы хотим выбирать, можно использовать git log <основная ветка>..<тематическая>.

Обратите внимание, что таким образом создаётся новый коммит, который только повторяет diff выбранного коммита (то есть разницу между этим коммитом и предыдущим), но не его состояние.

Заключение

Вот мы и рассмотрели основные концепции Git. Вы можете использовать эту статью в качестве краткого справочника, а можете почитать книгу «Pro Git», которая гораздо больше (~450 страниц) и описывает Git более глубоко.

Хотите копнуть глубже в Git, но вам мало (или наоборот, много) одной большой книги? Тогда вам стоит взглянуть на наш план изучения.

Перевод статьи «The Ultimate Beginner Git Cheatsheet»