Перезапись истории

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

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

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

Изменить последний коммит

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

  1. Выполните забытые изменения. Если нужно только исправить сообщение коммита, начните с п.4;
  2. Откройте панель Индексирование Git;
  3. Нажмите (Добавить все файлы в индекс) в контекстном меню поля Неиндексированные изменения;
  4. Нажмите (Дополнить (редактировать сообщение предыдущего коммита)) в контекстном меню поля Сообщение коммита. В поле появится сообщение предыдущего коммита;
  5. Отредактируйте сообщение коммита;
  6. Нажмите Фиксировать;

Вместо последнего коммита будет создан новый коммит (с новым Id), который содержит прежние и новые изменения и новое сообщение коммита.

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

Пример: Дополнить последний коммит.

Редактировать один из предыдущих коммитов

Для изменения коммита, не являющегося последним, а расположенного где-то раньше в истории, нужно обратиться к более сложным инструментам. В Git отсутствуют инструменты для переписывания истории, но вы можете использовать перебазирование, чтобы перебазировать группу коммитов туда же на HEAD, где они были изначально, вместо перемещения их в другое место.

С помощью интерактивного перебазирования можно останавливаться после каждого нужного вам коммита и изменять сообщения, добавлять файлы или делать что-то другое, что вам нужно. Для этого нужно всего лишь выбрать в панели История тот самый коммит, который вы хотите изменить, и нажать Исправить > Редактировать в контекстном меню.

Например, у вас есть история коммитов.

В некоторый момент вы понимаете, что коммит «Добавил Сотрудники, изменил ПриходТовара» оказался «недоделан». То ли вы забыли дописать номер задачи в сообщение коммита, то ли забыли сделать изменения, а может быть и то и другое вместе. Чтобы исправить этот коммит, вы выделяете его в панели История и нажимаете Исправить > Редактировать в контекстном меню.

1C:EDT создает операцию интерактивного перебазирования, в которой для вашего коммита выбрано действие Редактировать, а остальные коммиты, следующие за ним, переносятся без изменений и изменить действие для остальных коммитов вы не можете.

При этом в панели Индексирование Git находится сообщение вашего коммита, вы можете его изменить. А кроме этого вы можете выполнить забытые изменения и добавить их к этому коммиту.

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

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

О том, что это новые коммиты, вы можете судить по тому, что они имеют другие идентификаторы.

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

Изменить сообщения нескольких предыдущих коммитов

Допустим, вы имеете следующую историю коммитов.

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

В панели История выделите их родительский коммит («первый коммит») и в контекстном меню нажмите Interactive Rebase.

1C:EDT откроет панель Interactive Rebase, в которой будут содержаться все перебазируемые коммиты. Для каждого из них вы можете выбрать одно из действий, которые хотите с ними выполнить. В данном случае это будет действие Редактировать сообщение.

После того, как для каждого коммита выбрано нужное действие, можно нажать Старт.

1C:EDT начнет интерактивное перебазирование, остановится на первом коммите, который нужно изменить, и откроет диалог для изменения сообщения коммита. Допишите к сообщению номер задачи и нажмите Редактировать сообщение.

1C:EDT изменит этот коммит и остановится на следующем. Вы можете наблюдать процесс интерактивного перебазирования «в реальном времени». Для новых коммитов 1C:EDT создала новую ветку, добавила в нее первый измененный вами коммит и готова к изменению второго.

Когда интерактивное перебазирование завершится, панель Interactive Rebase очистится, а в панели История вы увидите новые коммиты с новыми сообщениями.

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

Упорядочить коммиты

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

Объединить коммиты

С помощью интерактивного перебазирования можно объединить несколько коммитов в один. При этом вы можете не вызывать собственно операцию интерактивного перебазирования, а воспользоваться более простым способом.

В панели История выделите коммиты, которые вы хотите объединить, а затем нажмите Исправить > Squash.

1C:EDT предложит вам написать новое сообщение для этого объединенного коммита. Стандартно она собирает в него все сообщения объединяемых коммитов.

Вместо такого «сборного» сообщения вы можете написать, например, что все эти изменения были выполнены в рамках одного эпика: Epic-27.

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

Удалить коммит

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

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

Из-за того, как Git создает объекты коммитов, удаление или изменение коммита влечет за собой перезапись всех последующих коммитов. Чем дальше вы вернетесь в историю ваших коммитов, тем больше коммитов потребуется переделать. Это может вызвать множество конфликтов слияния, особенно если у вас много последующих коммитов, которые зависят от удаленного.

Прервать перебазирование

Если во время интерактивного перебазирования вы поняли, что это была не очень хорошая идея, то всегда можно остановиться. Просто нажмите Прервать в панели Interactive Rebase и ваш репозиторий вернется в то состояние, в котором он был до начала перебазирования.

Отменить перебазирование

Вы можете полностью отменить операцию перебазирования и вернуть все в то состояние, которое было «до этого».

Например, у вас была такая история.

Вы объединили три коммита в один и история приняла другой вид.

После раздумий вы решили, что объединить все в один коммит — это была не очень хорошая идея и хотите вернуть все обратно.

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

  1. В панели История нажмите (Показать меню)ПоказатьДополнительные ссылки в командной панели. После этого в истории появится ссылка ORIG_HEAD, которая указывает на тот коммит, на котором находился HEAD перед выполнением опасной операции;
  2. Чтобы отменить перебазирование нужно выполнить жесткий сброс на этот коммит — Сброс > Жестко (HEAD, индекс и рабочий каталог) в контекстном меню;
  3. 1C:EDT попросит вас подтвердить выполняемую операцию — нажмите Сброс;
  4. Ветка master станет такой же, как до перебазирования;
  5. Несмотря на то, что коммит «Epic-27», созданный во время перебазирования, остался в базе данных объектов, он не принадлежит ветке master. Чтобы дополнительно убедиться в том, что состояние веток вернулось к исходному, отключите в панели История показ дополнительных ссылок: (Показать меню)ПоказатьДополнительные ссылки.

По материалам книги Pro Git (авторы Scott Chacon и Ben Straub, издательство Apress). Книга распространяется по лицензии Creative Commons Attribution Non Commercial Share Alike 3.0 license.