将已推送的分支还原到特定提交

6
我将一个包含不时变化并且不稳定的开发分支(dev branch)合并到我们存储已发布稳定代码的主分支(master branch)中。我想将主分支恢复到之前的状态,就好像从未合并过dev分支一样(并在将来合并dev分支时,现在要舍弃的所有更改都将再次合并)。目前主分支的状态如下图所示,我希望它在HEAD处有“professional-1.1.2”提交/标签。 status of the master branch 我尝试过:
$ git revert -n professional-1.1.2..HEAD
fatal: Commit 9167e846a387c793edbc089c7ab6bd9eb8260456 is a merge but no -m option was given.
$ git revert -n -m 1 professional-1.1.2..HEAD
fatal: Mainline was specified but commit 380169097f35d07466640bc0db1b639278cd25fa is not a merge.
$ git revert -n -m 2 professional-1.1.2..HEAD
fatal: Mainline was specified but commit 380169097f35d07466640bc0db1b639278cd25fa is not a merge.

经过一番调查,我认为更好的选择是执行 git reset --hard professional-1.1.2git push --force 作为对 Git:如何忽略快速转发并将 origin [branch] 恢复到早期提交? 或者 撤销 push 的 Git 提交 的答案。其他开发人员也在同一办公室,他们不应该向主分支提交任何内容(我也不应该,但是......是的,我们没有每个分支的权限),因此告诉他们并执行必要的操作并不是什么大问题。

所以最终问题是:git revert something 还是 git reset --hard <TAG> && git push --force?如果使用 git revert,应该使用哪个命令行?


2
Jefromi在https://dev59.com/mnA65IYBdhLWcg3w7TWZ中给出的答案可能会对您有所帮助。 - vpatil
1
@vpatil,在我的情况下最好使用git reset --hard而不是git revert - Carlos Campderrós
1
是的,我认为重置会创建一个新的提交,取消上一次提交。我强烈建议使用重置。 - vpatil
1
@CarlosCampderrós唯一的规则是您不应该在公共存储库中覆盖历史记录。如果这是您的私人存储库,您可以随心所欲。但是在公共存储库中,如果您重写历史记录,您将破坏已经下载了您正在重写部分的所有人的存储库。 - Šimon Tóth
@Let_Me_Be 是的,我知道。我真的不喜欢这样做,但最终我认为对于我的当前情况来说,这是最好的选择,因为环境是受控制的,没有人应该对主分支中的代码进行任何更改。 - Carlos Campderrós
3个回答

6

-m number选项指定了您想还原到哪个父提交(因为合并操作有多个父提交)。

因此,如果您执行了git checkout master; git merge devel;,则应该使用git revert -m 1 HEADgit revert -m 1 SHA_OF_MERGE_COMMIT


2
@CarlosCampderrós 你认为合并提交是什么?是的,这将撤销合并,也就是说:它将删除您合并到分支中的所有更改。 - Šimon Tóth
我刚才回滚的语法不对(所以当我第一次尝试时它没起作用(正如你在问题中看到的那样)),而且我在使用你的答案时选择了错误的父分支。现在...如果两个月后我再次合并开发分支,那么所有我要回滚的提交记录都将被合并吗?还是只有自从我现在要回滚的合并以来的更改会被合并? - Carlos Campderrós
1
合并不关心提交。合并将合并两个(或多个)HEAD。历史记录中的内容完全无关紧要。只有HEAD上的当前状态是相关的。 - Šimon Tóth
@Let_Me_Be:实际上,这取决于使用哪种合并策略——git的基本三路合并策略考虑了两个父提交和一个共同祖先——历史记录中用作共同祖先的提交对合并结果有很大影响。 - Mark Longair
@Let_Me_Be:我没有看到任何迹象表明OP打算在开发的后期做出比git merge develop更微妙的操作。 - Mark Longair
显示剩余2条评论

6

如果您只想使master分支的状态与professional-1.1.2完全相同,同时又要避免重写历史记录和强制推送,那么您可以在master分支上创建一个新的提交,该提交代表与professional-1.1.2相同的项目状态。您可以按照以下步骤进行操作:

# Check that "git status" is clean, since the steps that follow will throw
# way uncommitted changes:
git status

# Set the index (staging area) to be as it was at professional-1.1.2:
git read-tree professional-1.1.2

# Create a commit based on that index:
git commit -m "Reverting to the state at professional-1.1.2"

# Your working tree will still be as it was when you started, so
# you'll want to reset that to the new commit:
git reset --hard

作为替代方案,您可以按照 Charles Bailey的此答案 中建议的步骤进行操作,这 accomplishes 相同的事情,但我认为它稍微有点令人困惑(尽管我建议的步骤涉及“plumbing”命令 git read-tree)。


使用这个(使用状态为professional-1.1.2创建一个新的提交并推送),这样做是否允许将来合并dev分支,再次带来我现在正在“还原”的更改? - Carlos Campderrós
如果我建议引入的提交以对象名称f414f31结束,我认为您可以通过在git merge dev之前执行git revert f414f31来使未来的合并工作。 (我认为原则与撤消已撤消的合并相同。) - Mark Longair
阅读完http://code.google.com/p/git-core/source/browse/Documentation/howto/revert-a-faulty-merge.txt之后,我认为你是正确的@MarkLongair。这更加复杂和容易出错(因为在执行`git merge dev之前,我们可能会忘记撤销还原操作)。由于仓库是私有的且环境受控制,我想我会选择使用git reset --hardgit push --force`。 - Carlos Campderrós
@CarlosCampderrós:没错 - 我不确定这个分支的公开程度。只要你与可能从该分支拉取代码的任何人交流,并向他们解释如何处理重写的历史记录,采取其他方法就没问题了... - Mark Longair

2

如果你是一个胆大的人(恢复上游rebase可能对所有其他提交者都是必要的)

git checkout yourbranch
git reset HEAD <commit-hash>
git push origin yourbranch -f

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