我的一个队友错误地将一些提交推到了我们的主要开发部门。我们是一个小型的,并置的团队。我们的远程存储库托管在内部服务器上。
这是我们提交日志的顶部(所有这些提交都已被推送):
$ 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
da8b496
是我们想要保留在develop
分支中的最后一次提交,因此我们需要还原最后的5次提交。我们从8c29252
创建了一个新分支,以继续在“功能分支”中工作。
我在this answer和this post from Linus的指导下尝试了很多事情,并最终完成了您在下面的终端历史记录中所看到的内容。但我不确定我最终做的是“正确的方式”。我发现的信息很复杂;我无法辨别这个特定问题的“最佳解决方案”。
我选择的方法(请参阅下面的详细信息)是否可以在不损害我们历史的情况下还原这5个提交的好方法?有没有更简单或“更正确”的方法来完成同样的事情?
除此之外,我还考虑从da8b496
(git checkout -b new-develop da8b496
)创建一个新分支并放弃我们当前的develop
分支,但这感觉不对。
首先,我为提交a78b993
和8c29252
创建了一个新分支,因为这些提交包含我们想要保留的工作,并最终合并回我们的主开发分支。
$ git checkout -b new-feature-brach 8c29252
然后我开始在我们的开发分支中恢复有问题的提交。
我首先尝试了这个,但它没有用(可能是因为某些提交是合并的):
$ 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
所以......我手动恢复了每次提交;一个接一个地:
$ 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)
完成所有还原后提交日志:
$ 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
恢复后的图表:
$ 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
对我来说似乎是正确的。最后,我删除了一些我不想保留的备份文件:
$ git clean -fd
(list of affected files here)
当前状态是干净的:
$ 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
然后我把所有东西推回遥控器:
git push origin develop
答案 0 :(得分:9)
即使您的历史记录发生了变化,您也可以创建分支,让您返回并进行实验。 Git means never having to say, “you should have.”如果你想要更好地融入现实,那就去吧。否则,扔掉它。
下面的示例将创建新的分支,只留下存储库中的所有其他内容。
首先在你开始冒险的时候创建一个划痕分支。
$ git checkout -b tmp-revert faada93
通过指定提交范围,git revert
将撤消多次提交。
$ git revert da8b496..faada93
请考虑以下图表来自Git Internals — Git Objects,第二版Pro Git中由Scott Chacon和Ben Straub撰写的第10.2节。最顶层的提交(“第三次提交”)具有以1a410e
开始的SHA1哈希。在此历史记录的上下文中,1a410e^{tree}
将解析为3c4e9c
,即树对象立即转到第三个提交的右侧。
来自Pro Git的图151,第2版。
研究此模型以了解git如何跟踪内容。创建一个新的第四个提交,其树与第二个提交(即0155eb
)相同,将添加一个新的提交对象,该对象将共享或“指向”现有的树和blob而不是而不是添加新的重复对象。
继续阅读以了解如何使用git commit-tree
执行此低级拼接。
首先创建另一个临时分支来处理。
$ git checkout -b tmp-ctree faada93
此时,您希望创建一个新的提交,其树(即已提交的代码)与da8b496
的树相同,即您要保留的最后一次提交。这个树可以在git中直接寻址:da8b496^{tree}
。
git commit-tree
是“管道”,是git中的低级命令 - 而不是“瓷器”。使用它可能会感到尴尬或不熟悉,但在这种情况下,它可以精确控制您想要的结果
创建一个新的未附加提交,其树与da8b496
的树相同,其父(-p
)是当前分支的提示,在您的情况下为faada93
。请注意,git commit-tree
会读取标准输入上新提交的提交消息,下面的命令将使用echo
命令提供该消息。
$ echo Revert back to da8b496 | \ git commit-tree da8b496^{tree} -p $(git rev-parse tmp-ctree) new-commit-sha1
上面的斜体部分不是命令的一部分。它表示git commit-tree
输出新创建的提交的SHA1哈希值。知道新提交的SHA1,您可以将分支移动到那一点,例如,
$ git merge new-commit-sha1
在上面的命令中,将 new-commit-sha1 替换为git commit-tree
的输出。 (你可以做同样的git reset --hard new-commit-sha1
,但硬重置是一个很好的工具,可以最好地避免随意使用。)
您可以将上述所有内容转换为单个复合命令。
$ git merge --ff-only $(echo Revert back to da8b496 | \ git commit-tree da8b496^{tree} -p $(git rev-parse tmp-ctree))
--ff-only
切换到git merge
是为了防止意外。你的意图是让新提交成为当前分支头的快进或后代 - 实际上是它的直接孩子!
为了删除上面的临时分支,切换到另一个并且开火,麦克马纳斯先生。你的其他分支就像你离开时一样。
$ git checkout develop $ git branch -D tmp-revert tmp-ctree
两者应该相同,您可以使用
进行验证$ git diff tmp-revert tmp-ctree
要保留一个,请将其合并到develop
分支。
$ git checkout develop $ git merge --ff-only tmp-ctree $ git push origin develop
答案 1 :(得分:7)
您有一个小型的共处团队,因此沟通不是问题。使提交历史记录看起来应该看起来:
git branch -f develop dab4896
git branch newfeature 8c29252
git push -f origin develop newfeature
并让每个人都重新获取。你已经完成了。
这种错误是重写的原因之一。
答案 2 :(得分:3)
我可以建议将此视为与此答案重复:Make the current git branch a master branch
[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
答案 3 :(得分:0)
你要做的事情非常危险。
确实你可以恢复并删除你已经推送到repo的提交,但是如果有人已经撤消你的更改并且他有你要删除的commitId,那么repo会变得“不稳定”而且git不会因为你删除了现在从历史记录中删除的提交,所以能够处理pull和push。
仅执行此操作(还原和删除提交),并且仅当没有人提取此提交时。