Страницы

Поиск по вопросам

понедельник, 27 мая 2019 г.

Как восстановить прошлый коммит без потери существующих

Допустим когда-то давно я сделал коммит и после него прошли ещё много коммитов. Вдруг я понял, что тот давний коммит мне не был нужен, но я сделал много с того момента. Как не потерять свои наработки
Было А - B - C (коммит, который не нужен ) - D - E
Должно быть A - B - D - E
Ну и чтобы, если я одумался, легко вернуть С


Ответ

Не совсем понятно, в какой ситуации вы находитесь.
Если "давний" коммит означает, что он уже запушен на сервер, то вам вероятнее лучше оставить всё как есть.
Да, будет некоторый излишний коммит, но зато вам не придётся делать команду git rebase (что автоматически влечёт за собой git push -f: а force обычно в командах не приветствуется).
Зато в результате вы видите настоящую историю проекта как она есть и это тоже порой важная вещь.
Если же вы несмотря на давность коммита ещё не запушили его на удаленный сервер, либо вы - единственный пользователь для этого гит-репозитория (скажем, маленький pet-project), то делайте команду git rebase
Если у вас простая линейная история (без -noff) то вам нужно сделать примерно следующее.
Даёте команду
$ git rebase -i HEAD~5 pick 44e62cc A pick 95efd4a B pick ea91c6a C pick 99cd517 D pick 008df96 E
# Rebase 5c79d06..008df96 onto 5c79d06 # # Commands: # p, pick = use commit # r, reword = use commit, but edit the commit message # e, edit = use commit, but stop for amending # s, squash = use commit, but meld into previous commit # f, fixup = like "squash", but discard this commit's log message # x, exec = run command (the rest of the line) using shell # # These lines can be re-ordered; they are executed from top to bottom. # # If you remove a line here THAT COMMIT WILL BE LOST. # # However, if you remove everything, the rebase will be aborted. # # Note that empty commits are commented out "~/ansible/test/.git/rebase-merge/git-rebase-todo" 23L, 851C
(я указал коммит через HEAD~5, можете указывать SHA (id) предыдущего коммита перед тем, который вы хотите удалить)
Удаляете целиком строку pick ea91c6a C - приводите текст к виду:
pick 44e62cc A pick 95efd4a B pick 99cd517 D pick 008df96 E
После чего выходите с сохранением из редактора.
Далее всё очень сильно зависит от содержимого коммитов D и E.
В простейшем случае вы увидите сообщение о том, что rebase прошёл успешно (Successfully rebased and updated refs/heads/master.), в сложных случаях -- вам придётся вносить исправления в коммиты, которые невозможно автоматически применить к рабочему каталогу.
Простейший пример для понимания: в коммите C был создан новый файл adsf.txt, при этом в коммите D есть какая-то модификация этого файла, а применять изменения не к чему.
На каждом из коммитов, которые не могут быть автоматически применены гит будет останавливаться в состоянии Detached HEAD и будет ждать ваших корректировок. Скорректировали -- дали команду git rebase --continue и опять дальше применять коммиты, пока не дойдёте до последнего (и rebase закончится), либо опять остановитесь на одном из промежуточных.
Ещё по теме rebase я подробно описывал пошаговые действия: можете почитать тут
PS Update Вот что ещё. Я не дочитал про "если я одумался, легко вернуть С" и инструкция выше удалит коммит полностью и вы его после 30 дней (или чистки мусора git gc) уже не вернёте никак. Если хочется сохранить коммит -- то можете сделать отдельную backup-ветку перед выполнением rebase.

Комментариев нет:

Отправить комментарий