如何撤销多个Git提交?

1612

我有一个Git仓库,看起来像这样:

A <- B <- C <- D <- HEAD

我希望将分支的头指向A,也就是说,我想让B、C、D和HEAD消失,并且我想让head成为A的同义词。

听起来我可以尝试revert(不适用,因为我已经在中间推送了更改),或者回滚。但是如何回滚多个提交?我一次一个还是一起回滚?顺序重要吗?


5
如果您只是想重置远程仓库,可以使用任何方法进行覆盖!但我们可以使用前四个提交之前的代码:git push -f HEAD~4:master(假设远程分支是master)。是的,您可以像这样推送任何提交。 - u0b34a0f6ae
38
如果有人提交了错误的代码,你可以使用 git revert 命令撤销这些更改。请注意,这不会删除错误代码,而是创建一个新的提交来撤销它们。 - Jakub Narębski
3
使用 git show HEAD~4 命令确保你正在将正确的提交推送到远程仓库。 - Mâtt Frëëman
2
可能是如何在Git中撤消最后一次提交?的重复问题。 - Jim Fell
8
"顺序重要吗?" 如果提交的内容涉及相同文件中的相同行,则是的。那么您应该从最近的提交开始还原,然后逐步回退。 - avandeursen
请注意,git revert将在history中保留介入的工作。使用git checkoutgit reset --hard来清除历史记录:请参见答案https://dev59.com/8HM_5IYBdhLWcg3wPAjU#38317763。 - WestCoastProjects
18个回答

7
在我看来,一种非常简单和清晰的方法可能是:

返回A

git checkout -f A

将point master的头指向当前状态

git symbolic-ref HEAD refs/heads/master

保存

git commit

2
你能解释一下为什么要给负评吗? - nulll
2
这个很好用。给这个有用的答案点踩有什么意义呢?或者有人能解释一下最佳实践是什么吗? - Levent Divilioglu
这和 git checkout master; git reset --hard A 是一样的吗?如果不是,你能否解释一下它的作用? - M.M

7

这些方法都对我无效,所以我需要撤销三次提交(也就是最近的三次提交),于是我执行了以下操作:

git revert HEAD
git revert HEAD~2
git revert HEAD~4
git rebase -i HEAD~3 # pick, squash, squash

运作得非常好 :)


4
只有在您的更改尚未推送时,这才是可行的选择。 - kboom

5

这里提供的方法可能不如其他方法优雅,但我一直使用get reset --hard HEAD~N来撤销多个提交,其中N是您要回退的提交数。

如果不确定确切的提交数,只需多次运行git reset --hard HEAD^(回退一个提交),直到达到所需的状态即可。


3

我发现自己需要撤销一系列的提交,然后再次撤销它们,以帮助团队提交一个清晰的拉取请求,而不必强制推送到他们的目标分支(该分支是直接提交的)。


注:该段文字描述了作者为了帮助团队提交一个清晰的拉取请求而需要进行撤销一系列提交的操作。
# checkout the branch that should be targeted
git checkout $branch_target

# revert the commits in $branch_target to some $count where
#   $count is the number of commits to revert
#   cut is used to slice just the commit hash field from each line of output
#   xargs runs the command once for each line of input, reversing the commits!
git log --oneline -n $count | cut -d' ' -f1 | xargs git revert

# check out the branch which should be the source of the pull request
git checkout -b $branch_for_pull

# revert the revert commits
# $count is that same number of commits being reverted (again)
git log --oneline -n $count | cut -d' ' -f1 | xargs git revert

# push branches up and go off to create PR in whatever web UI
git push --set-upstream origin $branch_for_pull  # it's new!
git checkout $branch_target
git push  # if this branch wasn't pushed, just fix the issue locally instead..

因为这会按相反的顺序回滚所有从HEADgit log -n $count的提交,所以它可以很好且干净地处理任意数量的提交。

在此状态下查看$branch_target的视图

% git log --oneline origin/$branch_target
ffff006 (origin/$branch_target, $branch_target) Revert "first commit"
ffff005 Revert "second commit"
ffff004 Revert "third commit"
ffff003 third commit
ffff002 second commit
ffff001 first commit

查看此状态下的$branch_for_pull分支

% git log --oneline origin/$branch_for_pull
ffff009 (origin/$branch_for_pull, $branch_for_pull) Revert "Revert "third commit""
ffff008 Revert "Revert "second commit""
ffff007 Revert "Revert "first commit""
ffff006 (origin/$branch_target, $branch_target) Revert "first commit"
ffff005 Revert "second commit"
ffff004 Revert "third commit"
ffff003 third commit
ffff002 second commit
ffff001 first commit

如果意图是创建N个具有变更集的分支,但它们都提交到了同一个分支,您仍然可以将它们全部还原回基础提交,然后只还原所需的还原操作,因为变更集应按逻辑顺序排序(尝试快速说5次)。使用类似HEAD~7..HEAD~5的语法可能有助于描述范围以精确地拆分还原还原分支。在这里,当还原最后7次提交(git log -n 7)时,恢复其中5个到一个分支(git log -n 5),并在另一个分支中恢复2个及其上面的两个(git log HEAD~12..HEAD~10)(假设新的PR分支是基于"之前"的分支或将"之前"的分支非压缩合并到原始目标分支的结果)。

1
这比所有的--hard命令都要好,如果你正在还原一个提交,那么它应该被记录在历史中。 - Basit Anwer

1
如果您:
1. 有一个合并的提交, 2. 无法还原, 3. 并且不介意压缩您要还原的历史记录,
那么您可以:
git reset --soft HEAD~(number of commits you'd like to revert)
git commit -m "The stuff you didn't like."
git log
# copy the hash of your last commit
git revert <hash of your last (squashed) commit>

当您想要推送更改时,请记得使用-f标志,因为您已修改了历史记录。

git push <your fork> <your branch> -f

1

我真的希望避免硬重置,这就是我想出来的方法。

A -> B -> C -> D -> HEAD

回到A(即向后4步)的方法是:

git pull                  # Get latest changes
git reset --soft HEAD~4   # Set back 4 steps
git stash                 # Stash the reset
git pull                  # Go back to head
git stash pop             # Pop the reset 
git commit -m "Revert"    # Commit the changes

0
其他方法是我们可以克隆分支,然后运行以下命令。
git reset --hard commitID
git push -f branchname

-9
如果您想暂时还原某个功能的提交,则可以使用以下一系列命令。 这里是它的工作原理
git log --pretty=oneline | grep 'feature_name' | cut -d ' ' -f1 | xargs -n1 git revert --no-edit

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接