Как привести в порядок историю ваших коммитов в Git

Original author: Thiago Miranda
  • Translation
  • Tutorial
Публикуем перевод статьи, которую мы нашли на hackernoon.com. Ее автор, Thiago Miranda, пишет о том, как сделать работу с Git более удобной и эффективной.



О некоторых крайне полезных командах в Git


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

1. Что такое история в Git?




Точный реестр всех коммитов, содержащих произведенные с файлами изменения. В нем вы можете отследить конкретные изменения и время их внесения или сравнить текущую версию с предыдущей. Где посмотреть историю? Введите через Git Bash команду:

git log --oneline

Если у вас слишком много коммитов, вы можете переходить от одного комментария к другому с помощью клавиш со стрелками или клавиш Page Up / Page Down — как и в любом другом файле. Чтобы выйти, нажмите горячую клавишу (q).

2. О комментариях к коммитам


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

  • Как не надо: «Исправлен index.html»
  • Как надо: «Улучшена скорость работы навигационной панели»

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

Но после пуша внезапно все перестает работать, и первое, что вы проверяете — изменения, внесенные за время разработки этой фичи. В логе Git вы находите множество коммитов с комментариями в стиле «исправлен». Вообразите, сколько времени придется потратить на то, чтобы найти нужное!

3. Всегда делайте коммиты


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

Возможно, вы думаете: зачем так много коммитов? Основная причина в том, что ваш новый функционал может вступить в конфликт с чьим-нибудь кодом, но если вы всегда коммитите небольшие изменения, найти их и поправить будет проще. Так вы сэкономите время на отслеживании десятков или сотен строк, измененных в одном и том же коммите.

4. Исправьте последний комментарий к коммиту


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

git commit -m “correct message” --amend

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

Подробности см. в официальной документации.

5. Объедините последние Х коммитов в один


Ситуация: отправив коммит к новой фиче, вы понимаете, что нужно еще одно небольшое изменение, вносите минимальные правки и снова коммитите… В итоге 5 коммитов об одном и том же. Бывало? Подобные коммиты выбиваются из общего вида вашей истории в Git, но при желании их несложно поправить, применив команду:

git reset HEAD~3

Команда HEAD~3 откатывает 3 верхних коммита, включая самый последний. В этом примере три ваших последних коммита будут стерты из лога, но изменения в коде останутся на месте. Теперь пора посмотреть, какой код нужно закоммитить, для этого вводим команду:

git stage --diff

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

Обратите внимание, что HEAD обычно относится к последнему добавленному вами коммиту. Если вы не уверены, сверьтесь с логом Git. Если ваш последний коммит был замержен (не самый распространенный случай), команда HEAD~1 сотрет все коммиты из замерженной ветки. Чтобы узнать больше, посмотрите документацию.

6. Удалите последний коммит с изменениями


Будьте осторожны, так как этот способ сотрет все изменения без возможности откатить. Обычно он используется после экспериментов с кодом, если их результат не соответствует ожиданиям. Я рекомендую сперва попробовать в репозитории-песочнице.

git reset –-hard HEAD~1

Теперь ваш последний коммит удален, как и все соответствующие изменения в коде.

7. Очистите историю своих коммитов


Самый эффективный способ очистить историю коммитов — воспользоваться командой rebase. Будьте осторожны: вы можете удалить коммит, случайно нажав не ту клавишу. Итак, давайте запустим rebase в диалоговом режиме (флаг -i) с помощью команды:

git rebase -i HEAD~5



Как только вы вошли в него, вы увидите список из 5 последних коммитов (HEAD~5) внутри терминала. Все коммиты отсортированы по дате, т. е. наверху будет самый новый (этот список открывается с помощью Vim — текстового редактора Git по умолчанию, позволяющего редактировать текстовые файлы внутри терминала). И здесь же краткая инструкция с несколькими полезными командами. В большинстве случаев вам понадобятся команды squash и reword.

Заменив команду pick командой squash, вы удалите этот коммит из лога, и все изменения в коде будут сгруппированы с последним коммитом, выделенным командой pick.

Если вы хотите откорректировать комментарий, можно заменить команду pick командой reword и переписать комментарий.

Теперь вы можете перейти к следующему окну, где нужно написать один комментарий для группы коммитов, которые вы собираетесь склеить с помощью squash. Чтобы продолжить, нажмите ESC и введите:

:wq!

Двоеточие (:) необходимо, чтобы показать, что вы хотите передать команду, (w) — чтобы записать (сохранить) изменения, (q) — чтобы выйти, а (!) — чтобы выполнить команду.

Обратите внимание, что каждая группа коммитов получит ваш комментарий. Результат можно проверить в логе Git.

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

git rebase --edit

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

:q!

Vim получит команду закрыть файл без сохранения.

8. Управляйте индексацией


Обычно следует отправлять коммиты к одному файлу или к группе связанных файлов. Но как тогда оперативно вносить изменения при индексации?

Скажем, у вас есть 3 файла, и нужно закоммитить только 2 из них. В этом случае можно попробовать следующую команду:

git add .

Теперь удалите из индексации тот файл, который вам не нужен:

git reset -- Readme.txt

И проверьте результат:

git status

Добавьте все файлы из какого-либо расширения, например CSS:

git add *.css

Добавили все по ошибке? Тогда очистите индексацию, воспользовавшись командой:

git reset --

Если вам нужны более сложные операции, можно добавить файлы в индексацию с помощью диалогового режима:

git add -i

Сначала выберите опцию, введя соответствующий номер, например (3), чтобы откатить свои действия.

Выбрав опцию, можно ввести список файлов, которые вы хотите убрать из индексации, один за другим.

Когда завершите, нажмите (Enter).

Добавление файлов происходит по той же схеме. С помощью опции (4) добавьте неотслеживаемый файл.

Чтобы выйти, введите (q) в меню опций.

9. Вывод


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

Хотите узнать больше о парном программировании и начать работать удаленно? Загляните на Microverse.org.
Plarium
Разработчик мобильных и браузерных игр

Comments 14

    +5
    Будьте осторожны, так как этот способ сотрет все изменения без возможности откатить.
    git reset –-hard HEAD~1


    Теперь ваш последний коммит удален, как и все соответствующие изменения в коде.

    Типичный пример "сначала разберитесь, потом пишите". Никуда коммит удален не будет, все, что произойдет — это текущая ветка станет указывать на предшествующий коммит. А сам коммит останется в репозитории и будет там до сборки мусора.


    Делаем git reflog, смотрим на SHA нужного коммита, git reset --hard <sha> — и все как было. Собственно, даже reflog делать не обязательно, иногда можно просто вверх по консольному экрану помотать.

      +2
      Тоже зацепил этот момент. Такими советами можно и жизнь начинающим разработчикам подпортить. Гит ничего не удаляет никогда, что им зафиксировано. Вот не зафиксированные изменения с помощью reset можно потерять, это да.
        +1
        Вот не зафиксированные изменения с помощью reset можно потерять, это да.
        И вот ровно о них — в этом совете и предупреждают. Тем более, что как раз в предыдущем совете речь шла про reset без --hard.
          0
          git reset –-hard HEAD~1

          Теперь ваш последний коммит удален, как и все соответствующие изменения в коде.

          Речь идет как раз о удалении коммита и вместе с ним соответствующие изменения.

          git reset HEAD~1 — откатит текущую ветку на предыдущий коммит, при этом оставит файлы как есть
          –-hard — приведет файлы в соответствие к текущему коммиту
        +2
        Никуда коммит удален не будет, все, что произойдет — это текущая ветка станет указывать на предшествующий коммит. А сам коммит останется в репозитории и будет там до сборки мусора.
        Ну вообще-то там речь идёт про все изменения, а не все изменения в коммите.

        Делаем git reflog, смотрим на SHA нужного коммита, git reset --hard <sha> — и все как было.
        Вот всё-всё-всё прям? Со всеми изменениями, которые вы никуда не залили? Где такую магическую версию git'а берут и как она работает?
        +5
        Объедините последние Х коммитов в один
        git reset HEAD~3

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


        А для тех кто не хочет с vi/vim иметь дело надо было предложить editor в .gitconfig поменять

          0
          не обязательно и в .gitconfig, можно временно:
          EDITOR=nano git rebase -i HEAD~3
          +4

          Самый полезный совет на самом такой: если не уверены, к чему приведёт малознакомая команда типа reset или rebase, не применяйте её сразу в своей главной рабочей ветке или даже репозитории. Обязательно сначала сделайте копию, и только потом экспериментируйте. Потому что с непривычки где-нибудь да ошибётесь. Но цена ошибки будет небольшой, если она была сделана в ветке, которую не жалко грохнуть.

            +2

            ! — чтобы выполнить команду? Да ладно! Чтобы выполнить, нажимают Enter. А "!" ставят, чтобы не было вопроса "вы уверены?".

              0
                0
                git log --pretty=format:"%h %ad | %s%d [%an]" --graph --date=short
                  0
                  У меня настроен alias на
                  git l
                  когда ещё и цветами выделяются разные вещи.
                  l = log --graph --pretty=format:'%C(yellow)%h%C(cyan)%d%Creset %s %C(white)- %an, %ar%Creset'
                  

                  0
                  Делаю это все в студии мышкой, да командная строка это круто, но когда удобно то все остальное отпадает
                    +1
                    Тема не раскрыта/ Чтобы держать историю коммитов в красоте надо иметь четкую стратегию комментариев к коммитав и стратегию работы с ветками в процессе разработки/ а тут так просто набор команд по работе с коммитами

                    Only users with full accounts can post comments. Log in, please.