Как вернуть конкретный файл в старый коммит на git
Я думаю, что мой вопрос близок к этому, но я использую git.
Итак, скажем, у меня есть
Commit1 изменил file1.c и file2.c
Commit2 изменил file2.c, file3.c, file4.c
Commit3 изменил file1.c, file2.c и file3.c
и так далее...
Затем я хотел бы отменить только те изменения, которые Commit2 внес в file2.c, но попытаться сохранить изменения, сделанные Commit3 в этом файле...
Что ты думаешь? Есть какой-то способ сделать это?
Спасибо.
3 ответа
Вы можете попытаться вернуть Commit2 (то есть применить новый git commit, изменения которого будут противоположны изменениям, внесенным в Commit2), но без фиксации. Там есть мгновенный пункт меню в gitk
например. В этом новом коммите вы оставляете только изменения, внесенные в file2
и зафиксируйте результат.
В качестве альтернативы, вы можете просто сделать что-то вроде
git diff Commit2..Commit1 -- file2.c > revert.patch
git apply revert.patch
может быть полезно взглянуть на патч перед его применением, потому что коммиты после Commit2 могут привести к некоторым конфликтам с изменениями в file2.c
от Commit2.
В общем, чтобы отменить весь коммит, вы должны использовать git revert
(как вы, наверное, уже знаете). Ваша проблема здесь в том, что вы хотите отменить только некоторые изменения в старом коммите. Но оказывается, это легко, потому что:
git revert
имеет тот же эффект, что и применение патча в обратном порядке (git show
или жеgit diff
с конкретными идентификаторами коммитов по мере необходимости, а затемgit apply -R
получившийся патч), а затем фиксируя; а такжеgit diff
позволяет вам выбрать, какой файл (-ы) получить различий.
Итак, для обычного (с одним родителем) коммита вы можете просто:
git show <commit-id> -- <path>
чтобы получить "интересные" изменения от <commit-id>
, а затем направить (или иным образом подать) результат в git apply -R
:
git show HEAD~3 -- <path> | git apply -R
или в этом случае:
git show commit2 -- file2.c | git apply -R
Для коммита слияния, git show
будет производить комбинированный diff, который не то, что вы хотите, поэтому вы должны использовать git diff
(или же git diff-tree
) с двумя конкретными идентификаторами фиксации. Обратите внимание, что вы можете проверить различия до (или после) обратного применения, так как git apply
не делает новый коммит сам (так что вам придется делать это самостоятельно).
Ты хочешь сделать revert
?
Или просто хотите изменить это. Если это так, вы можете сделать это с
git rebase -i HEAD^^
Далее откроется редактор. В редакторе измените "выбрать" для "редактирования" на Commit2, как
pick abcdefg Commit3
pick jikdvuf Commit2
в
pick abcdefg Commit3
edit jikdvuf Commit2
Затем вы можете изменить свой коммит. Так что теперь измените файл. Вы можете захотеть сделать git checkout FILENAME
, После этого
git add FILENAME
git rebase --continue
Теперь вы успешно изменили файл на Commit2.