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


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, который исправит эту проблему.


Если вы хотите сделать это шаг за шагом, проще выбрать коммиты после измененного, чем экспортировать их как патч.
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 и снова подталкиваете их, вашим соавторам придется повторно объединить свою работу, и все станет беспорядочно, когда вы попытаетесь перетащите их работу обратно в свою.

    [...]

Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.