Git: исправление ошибок и наведение порядка в коммитах
Ошибка в коммите… Как её исправить? Беспорядок в истории коммитов… Как привести всё в пристойный вид? Автор статьи, перевод которой мы публикуем сегодня, говорит, что она написана специально для тех, кто задавался такими вопросами. По его словам, изучив методики работы с Git, представленные здесь, можно значительно продвинуться по пути освоения Git.
Исправление ошибок в коммитах
Здесь мы рассмотрим несколько сценариев появления ошибок в коммитах и их исправления.
▍Сценарий №1
▍Сценарий №2
Предположим, вы хотели закоммитить шесть файлов, но, по ошибке, закоммитили лишь пять. Кажется, что исправить эту ошибку можно, просто создав новый коммит и добавив туда недостающий шестой файл.
▍Сценарий №3
К коммитам, которые делают в Git, привязаны имя автора и адрес его электронной почты. Обычно эти данные указывают, выполняя первоначальную настройку Git. В результате тот, кто использует Git, может, выполняя каждый коммит, не заботиться о сведениях об его авторе.
При этом вполне возможна ситуация, когда, при работе с некоторыми проектами, будет нужно пользоваться сведениями об авторе, например — адресом электронной почты, отличающимися от основных. Для подобного проекта нужно указать адрес электронной почты, воспользовавшись такой командой:
▍Примечание
Используйте команду amend только в своём локальном репозитории. Её применение в удалённых репозиториях может привести к огромной путанице.
Наведение порядка в истории коммитов
Предположим, вы работаете над неким фрагментом кода какого-то проекта. Вам известно, что это займёт примерно десять дней. В течение этих десяти дней другие разработчики делают коммиты в исходный репозиторий.
Рекомендуется поддерживать синхронизацию между локальным и удалённым репозиториями. Это позволяет избежать множества конфликтов, связанных со слиянием, возникающих при слишком редкой синхронизации репозиториев. Следуя этой практике, вы решаете загружать изменения из удалённого репозитория каждые два дня.
Каждый раз, когда вы загружаете код из удалённого в локальный репозиторий, в локальном репозитории создаётся новый коммит-слияние (Merge Commit). Это означает, что в вашей локальной истории коммитов будет много таких коммитов, которые могут запутать того, кто будет просматривать ваш код.

История коммитов в локальном репозитории
▍Команда git rebase
Рассмотрим команду git rebase на примере.

Коммиты в ветке Release и в ветке Feature
В результате применение команды rebase будет выглядеть так:
▍Особенности команды rebase

Ветка Feature и три шага работы команды rebase
Шаг 1
Шаг 2
Шаг 3
▍Примечание
В случае использования команды merge вы получите коммит-слияние. В случае использования rebase никаких дополнительных коммитов у вас не будет.
Итоги
Изучив представленные в этом материале концепции, вы улучшили свои навыки владения Git и приблизились к уровню Git-эксперта. Надеемся, то, что вы тут узнали, вам пригодится. Но мир Git огромен, поэтому, освоив что-то новое, не останавливайтесь на достигнутом и двигайтесь дальше.
Уважаемые читатели! Сталкивались ли вы с беспорядком в Git-коммитах?
Переписывание истории
Введение
В данном обучающем материале описаны различные способы перезаписи и изменения истории в Git. В Git используются несколько способов регистрации изменений. Мы обсудим плюсы и минусы различных способов и покажем примеры работы с ними. В данном обучающем материале описаны некоторые типовые причины перезаписи состояний кода и разъясняется, как избегать ошибок при таких операциях.
Основная задача Git — гарантировать, что вы не потеряете внесенные изменений. Но эта система также предназначена для предоставления вам полного контроля над процессом разработки. В числе прочего вы сами определяете то, как выглядит история вашего проекта. Такая свобода создает и вероятность потери коммитов. Git предоставляет команды для перезаписи истории, но предупреждает, что использование таких команд может привести к потере данных.
Изменение комментария к последнему коммиту Git
Допустим, при выполнении коммита вы допустили ошибку в комментарии к нему. Выполнение этой команды в отсутствие проиндексированных файлов позволяет отредактировать комментарий к предыдущему коммиту без изменения состояния кода.
Изменение файлов после коммита
Не используйте amend для публичных коммитов
Измененные коммиты по сути являются новыми коммитами. При этом предыдущий коммит не останется в текущей ветке. Последствия этой операции аналогичны сбросу (reset) публичного состояния кода. Не изменяйте коммит, после которого уже начали работу другие разработчики. Эта ситуация только запутает разработчиков, и разрешить ее будет непросто.
Обзор
Изменение старых или нескольких коммитов
Для изменения старых или нескольких коммитов используйте команду git rebase для объединения нескольких коммитов в новый базовый коммит. В стандартном режиме команда git rebase позволяет в буквальном смысле перезаписать историю: она автоматически применяет коммиты в текущей рабочей ветке к указателю head переданной ветки. Поскольку новые коммиты заменяют старые, команду git rebase запрещено применять к коммитам, которые стали доступны публично. Иначе история проекта исчезнет.
Изменение файлов после коммита
Несколько комментариев
Каждый стандартный коммит в Git будет содержать комментарий, поясняющий, что было изменено в коммите. Комментарии дают наглядное представление об истории проекта. Во время операции rebase можно выполнить несколько команд для изменения комментариев к коммитам.
Склеивайте коммиты для поддержания чистой истории
Команда склеивания ( s ) позволяет в полной мере понять смысл rebase. Склеивание позволяет указать коммиты, которые нужно объединить в предыдущие коммиты. Таким образом создается «чистая история». Во время перемещения Git будет исполнять указанную команду rebase для каждого коммита. В случае склеенных коммитов Git откроет выбранный текстовый редактор и предложит объединить комментарии к указанным коммитам. Этот процесс можно показать следующим образом:
Обратите внимание, что идентификаторы коммитов, измененных с помощью команды rebase, отличаются от идентификаторов каждого из начальных коммитов. Коммиты с маркером pick получат новый идентификатор, если предыдущие коммиты были переписаны.
Современные решения для хостинга Git (например, Bitbucket) предлагают возможности «автосклеивания» при слиянии. Эти возможности позволяют автоматически выполнять rebase и склеивать коммиты ветки при использовании интерфейса решений для хостинга. Дополнительную информацию см. в разделе «Склеивание коммитов при слиянии ветки Git в Bitbucket».
Обзор
Команда git rebase позволяет изменять историю, а интерактивное выполнение rebase «подчищает» за вами следы. Теперь вы можете совершать и исправлять ошибки, оттачивая свою работу и сохраняя чистую, линейную историю проекта.
Страховка: git reflog
Справочные журналы (reflog) — это механизм, который используется в Git для регистрации обновлений, применяемых к концам веток и другим ссылкам на коммиты. Reflog позволяет вернуться к коммитам, даже если на них нет ссылок из какой-либо ветки или метки. После перезаписи истории reflog содержит информацию о старом состоянии веток и позволяет при необходимости вернуться к этому состоянию. Каждый раз при обновлении конца ветки любым способом (переключение веток, загрузка новых изменений, перезапись истории или просто добавление новых коммитов) в reflog добавляется новая запись. В данном разделе мы рассматриваем команду git reflog и стандартные примеры ее использования.
Использование
Отображается reflog локального репозитория.
Отображается reflog с относительными датами (например, 2 недели назад).
Пример
В приведенной выше команде reflog показан переход из главной ветки в ветку 2.2 и обратно. Отсюда можно выполнить жесткий сброс к старому коммиту. Последнее действие указано в верхней строчке с пометкой HEAD@ <0>.
Если вы случайно переместитесь назад, reflog будет содержать главный коммит, указывающий на (0254ea7) до случайного удаления вами 2 коммитов.
При использовании команды git reset можно вернуть главную ветку к более раннему коммиту. Это страховка на случай непреднамеренного изменения истории.
Необходимо отметить, что reflog только предоставляет страховку на тот случай, когда изменения попали в коммит в локальном репозитории, и что в нем отслеживаются только перемещения концов веток репозитория. Кроме того, записи reflog имеют определенный срок хранения. По умолчанию этот срок составляет 90 дней.
Резюме
В данной статье мы рассмотрели несколько способов изменения истории Git и отмены изменений в Git. Мы вкратце рассмотрели процесс git rebase. Вот основные заключения.
Узнайте больше об описанных командах на соответствующих страницах:
Как это отменить?! Git-команды для исправления своих ошибок
Авторизуйтесь
Как это отменить?! Git-команды для исправления своих ошибок
Если вы ошиблись в Git’е, разобраться, что происходит и как это исправить, — непростая задача. Документация Git — это кроличья нора, из которой вы вылезете только зная конкретное название команды, которая решит вашу проблему.
Рассказываем о командах, которые помогут вам выбраться из проблемных ситуаций.
Вот блин, я сделал что-то не то… У Git ведь есть машина времени?!
Так вы можете восстановить то, что случайно удалили, и откатить слияние, после которого всё сломалось. reflog используется очень часто — давайте поблагодарим того, кто предложил добавить его в Git.
Я только что сделал коммит и заметил, что нужно кое-что поправить!
Внимание Никогда не изменяйте коммиты в публичной ветке. Используйте эту команду только для коммитов в локальной ветке, иначе вам конец.
Мне нужно изменить сообщение последнего коммита!
Тупые требования к оформлению сообщений…
Я случайно закоммитил что-то в мастер, хотя должен был в новую ветку!
Команды не сработают, если вы уже закоммитили в публичную ветку. В таком случае может помочь git reset HEAD@ <какое-то-количество-коммитов-назад>вместо HEAD
Ну отлично. Я закоммитил не в ту ветку!
Я пытаюсь запустить diff, но ничего не происходит
Если вы знаете, что изменения были внесены, но diff пуст, то возможно вы индексировали изменения (через add ). Поэтому вам нужно использовать специальный флаг.
Конечно, «это не баг, а фича», но с первого взгляда это чертовски неоднозначно.
Мне нужно каким-то образом отменить коммит, который был сделан 5 коммитов назад
Помимо этого, откатить можно не целый коммит, а отдельный файл. Но следуя канону Git’а, это будут уже совсем другие команды…
Мне нужно отменить изменения в файле
Именно поэтому checkout — лучший инструмент для отката изменений в файлах.
Давай по новой, Миша, всё х**ня
Если вам нужно полностью откатиться до исходной версии (т. е. отменить все изменения), то можете попробовать сделать так.
Будьте осторожны, эти команды разрушительны и необратимы.
Эти команды Git нужны для экстренных ситуаций, но пригодиться могут не только они. Про другие команды с пояснениями писали тут:
Полезные советы для начинающих Git-разработчиков
Открыли для себя Git? Разобраться в этом не так просто, поэтому мы написали несколько советов для начинающих Git-разработчиков.
Я кое-что неправильно закоммитил. Как это исправить, если история изменений не позволяет разобраться, что происходило?
Если у вас возникали подобные вопросы, продолжайте изучение статьи. Объясняем ситуации, которые могут облегчить жизнь Git-разработчиков.
Сценарий №1
Сценарий №2
Предположим, что вы хотели отправить шесть файлов, но случайно забыли про один из них. Первое, что приходит в голову − сделать новую правильную запись.
—no-edit делает так, чтобы запись не менялась.
Сценарий №3
Всякий раз, когда вы коммитите Git, в записи упоминается имя автора и адрес его электронной почты. Как правило, они указываются при первой настройке Git.
Допустим, для конкретного проекта вы хотите использовать другие данные электронной почты. Настроить их можно с помощью команды:
А что если вы забыли настроить эти данные и уже отправили коммит? Amend может быть использован и для изменения данных автора. Вот так:
Внимание!
Используйте команду amend только в локальном, а не удаленном репозитории.
В истории коммитов бардак. Как это исправить?
Например, происходит работа над фрагментом кода. Вы знаете, что процесс займет порядка десяти дней, и в течение этого времени другие разработчики также будут передавать код удаленному репозиторию.
Это полезно, потому что позволяет синхронизировать код локального и удалённого репозиториев. Как следствие, количество проблем при отправке изменений на проверку минимизируется.
Каждый раз, когда вы перемещаете код из удаленного репозитория в локальный, создается merge commit. Если коммитов станет слишком много, то программист, изучающий внесённые изменения, может запутаться.
Тогда как привести это всё в нормальное состояние?
Здесь на помощь приходит rebase. Как это работает:
Цель − обеспечить, чтобы ветвь Feature получила последний код из ветви Release.
Rebase по очереди добавляет коммиты и проверяет их на несоответствия. Кажется странным? Вот что происходит внутри функции:
Шаг №1
Шаг №2
Шаг №3
Полезно знать
Возможно, вас заинтересуют следующие материалы
Источник: Советы для Git-разработчиков on freeCodeCamp
Как я использую git
Основам git мне пришлось научиться на своем первом месте работы (около трех лет назад).
С тех пор я считал, что для полноценной работы нужно запомнить всего-лишь несколько команд:
В принципе, я и сейчас во многом так считаю, но со временем волей-неволей начинаешь узнавать интересные трюки.
Вообще, имеет смысл подробнее разузнать о понятиях гита. Лучше подробнее ознакомиться с концепцией коммитов, что такое ветка, что такое тег и пр.
Некоторые настройки для удобной работы
Автодополнение
Удивительно, но не у всех оно есть. Отправляемся в гугл по запросу «git_completion», скачиваем скрипт и действуем по инструкции к нему.
Выводим текущую ветку в строке bash
Для справки: за внешний вид командной строки баша отвечает переменная PS1. Have fun.
Алиасы
Редактируем сообщения к коммитам в своем любимом текстовом редакторе
Для начала небольшая страшилка, основанная на реальных событиях:
Как-то раз молодой неопытный программист хотел впервые закоммитить код, а гит открыл ему vim!
Git, как и некоторые другие утилиты (crontab, например) проверяют наличие переменной EDITOR.
/.bashrc ) можно добавить вот такую строчку:
Сменить ветку, не теряя текущих незакоммиченных правок
Иногда можно просто сменить ветку, но иногда возникают конфликты. Я знаю два варианта:
Первый вариант надежнее, второй удобнее (имхо).
Посмотреть, что я уже наредактировал
Показывает ваши изменения относительно текущего коммита + stage (важное уточнение). Замечание: в дифф не попадают новые файлы
Посмотреть, что я добавил в stage
Замечание: сюда новые файлы попадают.
Удалить лишние файлы
Т.е. файлы, которые не относятся к репозиторию
Отменить последний коммит
У меня на это дело есть alias в баше:
В общем, вся команда сводится к тому, что текущая ветка переносится на один коммит назад, а изменения, внесенные коммитом, попадают в stage
— данная команда берет предыдущий коммит от «головы» и «ресетит» гит на него. В свое оправдание могу сказать, что этому алиасу пара лет и в то время я не знал о том, что такое HEAD и тем более HEAD
Объединить несколько коммитов
Когда я работаю на своей ветке, периодически я делаю несколько коммитов, которые совсем не имеют смысла по отдельности (а делаю я это просто для того, чтобы коммитить почаще и не терять мысль), поэтому перед вливанием их в мастер имеет смысл их объединить
Это откроет текстовый редактор, в котором списком будут указаны коммиты.
Вы можете:
Вообще я после каждой фичи делаю интерактивный ребейз и смотрю, какие коммиты я хочу объединить, какие переставить для красоты, какие поправить. Это позволяет сохранять красоту в версионировании.
Добавить что-нибудь в предыдущий коммит
Еще стоит упомянуть:
3 коммита назад допустил опечатку, не хочу, чтобы это позорище кто-то увидел отдельным коммитом.
Закоммитить части файла по отдельности
Собственно, например, у меня есть код:
Мне нужно добавить фичу: выводить удвоенное n. Изи! Но пока я пишу фичу, на автомате меняю некрасивое имя функции.
Как теперь коммитить? Можно быстро вернуть старое название, закоммитить новый функционал, а потом уже переименовать, но это не всегда уместно, т.к. изменения могут быть достаточно крупными. Можно честно признать, что коммит сложный и написать сообщение в духе «добавил фичу + переименовал метод», но мы ведь стараемся делать коммиты простыми, верно?
Но у гита есть отличная команда:
Она интерактивная. Поочередно берет изменения кусками (hunk) и спрашивает, что с данным куском делать: игнорировать, добавить, изменить и добавить. Третий вариант достаточно мощный, можно по отдельности добавлять изменения даже в рамках одной строчки ( kvadrat(x) + kub(x) => square(x) + cube(x) в 2 коммита).
Заслуживают внимания
Outro
Я указал здесь всего-лишь парочку «трюков» работы с git, но их я использую на ежедневной основе.
Смысл данного поста (помимо того, чтобы ублажить свое ЧСВ и оставить заметку для себя самого) в том, чтобы еще раз подчеркнуть известную (относительно) фразу: Know your tools!.
В гите (да и в принципе во всех ваших инструментах для работы) есть множество деталей, которые могут сделать вашу жизнь проще. Например, я видел репозитории, в которых стояли валидации для коммитов: нельзя было ничего закоммитить, если не проходили тесты или тесты не покрывают изменения.






