Reverting a series of pushed merges and commits in Git (without rewriting history)
我的一个队友错误地把一些承诺推到了我们的主要开发部门。我们是一个小型的、并置的团队。我们的远程存储库托管在一个内部服务器上。
下面是提交日志的顶部(所有这些提交都已推送):
1 2 3 4 5 6 7 | $ git log develop -6 --pretty=oneline --abbrev-commit faada93 Merge branch 'develop' of <our_repo_path>.git 244d174 Support classes again a97a877 Pruned all unused references (again). 8c29252 Merge branch 'develop' of <our_repo_path>.git a78b993 Support models & methods - product types & categories da8b496 Resolved JIRA issue PPF-182 |
我尝试了很多事情,在这个答案和Linus的这篇文章的指导下,最终做了你可以在我下面的终端历史中看到的事情。但我不确定我最终所做的是否是"正确的方式"。我发现的信息很复杂;我无法为这个特定的问题找到"最佳解决方案"。
问题我选择的方法(见下面的详细信息)是否是在不损害我们历史的情况下恢复这5项承诺的一个好方法?有没有一种更容易或"更正确"的方法来完成相同的事情?
除此之外,我考虑从
首先,我为承诺
1 | $ git checkout -b new-feature-brach 8c29252 |
号
然后我开始恢复我们开发部门的违规行为。
我首先尝试了这个方法,但没有成功(可能是因为一些提交被合并):
1 2 3 4 | $ git revert a78b993..HEAD error: a cherry-pick or revert is already in progress hint: try"git cherry-pick (--continue | --quit | --abort)" fatal: revert failed |
所以…我手动恢复了每个提交;一个接一个:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 | $ git revert -m 1 faada93 [develop 40965a5] Revert"Merge branch 'develop' of <our_repo_path>.git" 8 files changed, 167 insertions(+), 3 deletions(-) $ git revert 244d174 [develop 3cebd68] Revert"Support classes again" 45 files changed, 557 insertions(+), 1572 deletions(-) (list of affected files) $ git revert a97a877 error: could not revert a97a877... Pruned all unused references (again). hint: after resolving the conflicts, mark the corrected paths hint: with 'git add <paths>' or 'git rm <paths>' hint: and commit the result with 'git commit' $ git mergetool Merging: exampleFile1.cs exampleFile2.cs Deleted merge conflict for 'exampleFile1.cs': {local}: deleted {remote}: modified file Use (m)odified or (d)eleted file, or (a)bort? m Deleted merge conflict for 'exampleFile2.cs': {local}: deleted {remote}: modified file Use (m)odified or (d)eleted file, or (a)bort? m $ git commit -m"Adding files to be reverted along with the next commit." [develop 15bc02b] Adding files to be able to revert the next commit in line. 2 files changed, 239 insertions(+) (list of affected files here) $ git revert -m 1 8c29252 # On branch develop # Your branch is ahead of 'origin/develop' by 3 commits. # (use"git push" to publish your local commits) # # Untracked files: # (use"git add <file>..." to include in what will be committed) # # exampleFile1.cs.orig # exampleFile2.cs.orig nothing added to commit but untracked files present (use"git add" to track) $ git revert a78b993 [develop 841e77c] Revert"Support models & methods - product types & categories" 2 files changed, 239 deletions(-) (list of affected files here) |
。
完成所有还原后提交日志:
1 2 3 4 5 6 7 8 9 10 11 | $ git log develop -10 --pretty=oneline --abbrev-commit 841e77c Revert"Support models & methods - product types & categories" 15bc02b Adding files to be able to revert the next commit in line. 3cebd68 Revert"Support classes again" 40965a5 Revert"Merge branch 'develop' of <our_repo_path>.git" faada93 Merge branch 'develop' of <our_repo_path>.git 244d174 Support classes again a97a877 Pruned all unused references (again). 8c29252 Merge branch 'develop' of <our_repo_path>.git a78b993 Support models & methods - product types & categories da8b496 Resolved JIRA issue PPF-182 |
恢复后图形:
1 2 3 4 5 6 7 8 9 10 11 | $ git log --graph --oneline -8 develop * 841e77c Revert"Support models & methods - product types & categories" * 15bc02b Adding files to be able to revert the next commit in line. * 3cebd68 Revert"Support classes again" * 40965a5 Revert"Merge branch 'develop' of <our_repo_path>.git" * faada93 Merge branch 'develop' of <our_repo_path>.git |\ | * a97a877 Pruned all unused references (again). | * 8c29252 Merge branch 'develop' of <our_repo_path>.git | |\ | | * da8b496 Resolved JIRA issue PPF-182 |
。
在我看来是正确的。最后,我删除了一些不想保留的备份文件:
1 2 | $ git clean -fd (list of affected files here) |
。
当前状态为清除:
1 2 3 4 5 6 | $ git status # On branch develop # Your branch is ahead of 'origin/develop' by 4 commits. # (use"git push" to publish your local commits) # nothing to commit, working directory clean |
然后我把所有东西都推回到遥控器上:
1 | git push origin develop |
。
即使您的历史已经改变了,您也可以创建一些分支,让您返回并进行实验。Git的意思是不必说,"你应该这样做。"如果你集中在一个你更喜欢的现实上,那就去做吧。否则,扔掉它。
下面的示例将创建新的分支,使您的存储库中的其他内容保持独立。
备选方案1:Git还原首先在你开始冒险的地方创建一个划痕分支。
1 | $ git checkout -b tmp-revert faada93 |
通过指定提交范围,
1 | $ git revert da8b496..faada93 |
号备选方案2:Git提交树
下面的图表来自Git内部-Git对象,由Scott Chacon和Ben Straub编写的第二版Pro Git第10.2节。最上面的commit("第三个commit")有一个以
。图151摘自《出版自由》,第2版。
研究此模型以了解Git如何跟踪内容。创建一个新的第四个提交,其树与第二个提交的树相同(即,
继续阅读了解如何使用
首先创建另一个要处理的临时分支。
1 | $ git checkout -b tmp-ctree faada93 |
此时,您希望创建一个新的提交,其中它的树(即提交的代码)与您希望保留的最后一个提交
创建一个新的独立提交,其树与
1 2 3 | $ echo Revert back to da8b496 | \ git commit-tree da8b496^{tree} -p $(git rev-parse tmp-ctree) new-commit-sha1 |
。
上面的斜体部分不是命令的一部分。它表示
1 | $ git merge new-commit-sha1 |
在上面的命令中,将new-commit-sha1替换为
您可以将上述所有内容都滚动到一个复合命令中。
1 2 | $ git merge --ff-only $(echo Revert back to da8b496 | \ git commit-tree da8b496^{tree} -p $(git rev-parse tmp-ctree)) |
。
要删除上面的临时分支,请切换到另一个分支,然后开火,McManus先生。你的其他分支将和你离开它们时一样。
1 2 | $ git checkout develop $ git branch -D tmp-revert tmp-ctree |
。
这两个应该是相同的,你可以用
1 | $ git diff tmp-revert tmp-ctree |
要保留一个,请将其合并到您的
1 2 3 | $ git checkout develop $ git merge --ff-only tmp-ctree $ git push origin develop |
。
你有一个很小的团队,所以沟通不是问题。使提交历史看起来像它应该看到的那样:
1 2 3 | git branch -f develop dab4896 git branch newfeature 8c29252 git push -f origin develop newfeature |
让所有人重修一遍。你完了。
这种错误是重写的原因之一。
我可以建议这可以被视为这个答案的副本:使当前的git分支成为一个主分支
Jefromi的最佳解决方案是:
1 2 3 4 5 | [git branch better_branch <last good commit>] git checkout better_branch git merge --strategy=ours master # keep the content of this branch, but record a merge git checkout master git merge better_branch # fast-forward master up to the merge |
你想做的事风险很大。
实际上,您可以恢复和删除已经推送到回购的提交,但是如果有人已经拉走了您的更改,并且他拥有您要删除的提交ID,那么回购可能会变得"不稳定",并且Git将无法处理拉入和推送,因为您删除了现在已从历史记录中删除的提交。
仅当还没有人执行此提交时才执行此操作(还原和删除提交)。