Как изменить предыдущую фиксацию, чтобы включить пропущенный файл?

98

Я зафиксировал изменение и забыл добавить файл в набор изменений. После других коммитов я понял, что файл теперь отсутствует в HEAD^4коммите.

Как мне переписать предыдущую фиксацию, чтобы включить отсутствующий файл?

Колри
источник
вы продвигали эти 4 коммита?
mvp
@mvp нет, они есть только в моем локальном репозитории git.
kolrie

Ответы:

54

Используйте git rebase --interactive HEAD~4и установите editпараметр для коммита, который вы хотите изменить.

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

Рафал Равицки
источник
Спасибо. Так ли это, даже если я единственный пользователь удаленного репо? Разве это не позволило бы мне сделать, git push -fесли бы я был уверен, что восходящий поток не изменился?
kolrie
1
Если вы единственный пользователь удаленного репо, можно сделать принудительное нажатие.
Rafał Rawicki
7
Я думаю, что эти инструкции недостаточно подробны. При первой попытке мне сказали: «Невозможно перебазировать: ваш индекс содержит незафиксированные изменения». Я уже addотредактировал недостающие файлы, поэтому я сделал коммит, указав в сообщении «xxx». Затем я выполнил команду rebase и изменил фиксацию «xxx» с «pick» на «edit». Затем я сделал "git rebase --continue". Теперь, когда я смотрю на историю, у меня есть «xxx» как последняя фиксация, а предыдущая фиксация, в которую я хотел их добавить, не изменилась! Интересно, где была моя ошибка?
Даррен Кук
2
Сжатие последней фиксации не поместит файл в HEAD ~ 4.
Джастин
1
git add editedFiles; git commit -m "Мля"; git rebase -i HEAD ~ 5; // поскольку теперь добавлен новый коммит, поэтому нам нужно было перебазировать с 5 вместо 4. теперь переместите коммит «Blah» во вторую строку и измените его с «Pick» на «s» (сквош), что приведет к сжатию фиксации с помощью HEAD ~ 5, поскольку команды выполняются сверху вниз
zstring 06
274

Я понимаю, что люди могут гуглить и приходить сюда, чтобы найти более простой ответ: что, если бы это была последняя фиксация? (Вопрос OP предназначен для исправления 4-го коммита в истории)

В случае , если вы совершали и понимаете , что вы забыли добавить файл сразу , просто сделать:

# edited file-that-i-remember.txt
git add file-that-i-remember.txt
git commit

# realize you forgot a file
git add file-that-i-forgot.txt
git commit --amend --no-edit

Где --no-editбудет храниться то же сообщение фиксации.

Очень просто!

Д-р Беко
источник
21
Это ответ.
Адам Биттлингмайер
5
Стоит упомянуть, если коммиты не отправляются на удаленный компьютер.
Рам Патра
1
Да, здесь стоит упомянуть в комментариях: это для использования перед нажатием . Спасибо, что указали на это.
Dr Beco
2
Одно замечание: коммиты до и после --amendимеют разные хэши
sonlexqt
6
Спасибо, но этого не может быть: OP просил HEAD^4. Это нормально, просто в качестве дополнения для справки. ;)
Dr Beco
11

Если вы НЕ нажимали эти 4 коммита, вы можете сделать это следующим образом:

Создайте файлы патчей для всех этих коммитов:

git format-patch -4

Перемотка назад на 4 коммита:

git reset --hard HEAD~4

Добавить отсутствующий файл:

git add missing-file

Зафиксируйте это с помощью --amend:

git commit --amend

Применить все сохраненные патчи обратно:

git am *.patch

Если вы нажали, вам НЕ следует использовать этот метод. Вместо этого просто признайте свою ошибку и создайте еще один коммит поверх HEAD, который исправит эту проблему.

mvp
источник
Если вы хотите сделать это шаг за шагом, проще выбрать коммиты после измененного, чем экспортировать их как патч.
Rafał Rawicki
1
Это дело вкуса. Мне нравится git format-patch/ git amнамного лучше. Самое главное, это дает вам больше уверенности, если вы что-то напортачите - фиксация, сохраненная как патч в физическом файле, - ваша лучшая подстраховка.
mvp
Настоящая уверенность заключается в том, что при работе с репозиторием git вы никогда ничего не удалите. Старые коммиты доступны, пока вы не запустите git gc:)
Рафал Равицкий
Для нас с вами это банально и очевидно. Но для пользователя, который только начинает работать и, вероятно, ничего не понимает в git, этот факт совсем не очевиден.
mvp
2
Эти инструкции казались многословными, но были довольно простыми и легкими для выполнения. Спасибо. (Я бы просто добавить последний шаг: rm *.patch)
Darren Кук
9

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

  • Сначала запустите процесс перебазирования:

    git rebase --interactive HEAD~4
    
  • Будет представлен список коммитов, выберите коммит, который вы хотите отредактировать, изменив слово pickна editи сохраните файл.

  • Внесите необходимые изменения в свой код (не забудьте вызывать git addновые файлы)

  • После внесения всех изменений, проблема git commit --amend- это изменит фиксацию, помеченную какedit

  • Вызов git rebase --continue, который завершит процесс (если отмечено больше коммитов edit, указанные выше шаги необходимо повторить)

Важные заметки:

  • НЕ удаляйте строки, отмеченные как те, pickкоторые вы не хотите редактировать - оставьте их как есть. Удаление этих строк приведет к удалению связанных коммитов

  • GIT вынуждает вас выполнить stashперебазирование, если ваш рабочий каталог не чистый; однако вы можете git stash pop / git stash applyво время перебазирования внести поправки в эти изменения (т. е. изменения, сохраненные перед запуском процесса перебазирования) на фиксацию, помеченную какedit

  • если что-то пошло не так, и вы хотите отменить изменения, сделанные во время процесса перебазирования до его завершения (т. е. вы хотите вернуться к точке до начала перебазирования), используйте git rebase --abort- также прочтите: Как отменить интерактивное перебазирование, если --abort не ' т работать?

  • Как сказано в принятом ответе:

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

    Ответ «почему» находится в Git Book (абзац, озаглавленный « Опасности повторного базирования »):

    Не перемещайте коммиты, существующие вне вашего репозитория.

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

    Когда вы перемещаете материал, вы отказываетесь от существующих коммитов и создаете новые, похожие, но разные. Если вы куда-то отправляете коммиты, а другие снимают их и основывают работу на них, а затем вы переписываете эти коммиты с помощью git rebase и снова подталкиваете их, вашим соавторам придется повторно объединить свою работу, и все станет беспорядочно, когда вы попытаетесь перетащите их работу обратно в свою.

    [...]

Доминик
источник