0

我的提交历史如下所示:

A - B - C - D - E
     \     /
      X - Y

分支ABCDEmaster,分支XY是其他分支(例如test),并且D是合并提交。HEAD现在是在E。我需要在使用, onlyA的假设下将我的工作目录返回到 的状态。据我所知,在这种情况下,这可以通过两种方式完成:git reset --hard <SHA1(A)>git revert

第一种方式:

git revert --no-commit <SHA1(E)>
git revert -m 1 --no-commit <SHA1(D)>
git revert --no-commit <SHA1(C)>
git revert --no-commit <SHA1(B)>
git commit -m "Reverted to state A"

第二种方式:

git revert --no-commit <SHA1(E)>
git revert -m 2 --no-commit <SHA1(D)>
git revert --no-commit <SHA1(Y)>
git revert --no-commit <SHA1(X)>
git revert --no-commit <SHA1(B)>
git commit -m "Reverted to state A"

一个绊脚石是git revert -m。在这个例子中,我假设1允许沿着分支继续恢复链master,并且2- 沿着分支test

问题是:我怎么知道哪个数字代表哪个分支?

4

3 回答 3

2

另一种方法是简单地清空工作树,然后在提交时插入工作树A

# assumes you're in the top level
$ git rm -rf .
$ git checkout sha-or-other-specifier-for-A -- .
$ git commit -m 'revert to state A'

这里的想法是git rm -rf完全清空工作树和索引/暂存区,然后git checkout <rev> -- .完全重新填充工作树和索引/暂存区,但从指定的修订版获取树和文件,而不是从最新版本中获取。

一旦这两个完成,一个新的提交将写入与 commit 中相同的树和文件A

于 2014-01-22T23:19:34.447 回答
1

在这种情况下,我不会在 git 上绞尽脑汁,而是这样做:

git diff <sha(A)> HEAD | git apply -R
git commit -a -m "undoing everything since A"

当然,在提交之前检查所有内容。另外,在提交之后,验证:现在 A 和 HEAD 有什么区别?理想情况下,什么都没有:

git diff <sha(A)> HEAD
于 2014-01-22T22:32:27.327 回答
0

您可以检查合并提交以查看它的父母是谁:

git show <SHA1(D)>

父母将按照您可以参考的顺序列出。此信息也打印在 的输出中git log。使用它来推断当你这样做时意味着哪些提交git revert -m

编辑:您似乎正在使用公共存储库并寻找更改已发布分支的方法,这与更改工作副本的状态完全不同。Git 有一种方法可以恢复,而不必在此过程中找出合并的每个父级。一次完成所有操作:

git revert <SHA1(B)>..

更新:我正在阅读一些旧的东西,并意识到我给出的这个答案是完全不正确的。如果您执行上述操作,您将不会获得状态 A,而是会获得您不想要的 Frankenstein:

A - C' - D' - E'
 \     /
  X - Y

那 ^ 相当于你得到的,这根本不是你想要的。实际上只有一种方法可以做到这一点并完全保留您的历史记录:

git revert HEAD              # reverts E, labeled as E' below
git revert -m 1 <SHA1(D)>    # reverts D, labeled as D' below
git revert HEAD              # reverts C, labeled as C' below
git revert HEAD              # reverts B, labeled as B' below

这将使您的历史看起来像这样:

A - B - C - D - E - E' - D'{C} - C' - B'
     \     /
      X - Y

这种方法将为您提供您想要的并保留所有历史记录。@Kaz 和 @torek 的方法更有效,更简洁,如果您不想重新引入XY那么我推荐其中一种解决方案;但是,如果您关心的话,它们可能会使重新引入X并进入您的主分支变得更加困难。Y还原每个部分可以重新引入X并且无需再次重写/C&P 代码,如果并且是大的更改,或者如果您痴迷于保持尽可能准确的历史记录(我倾向于那样)Y,这是一个有吸引力的选择。XY

要重新引入Xand Y,您应该这样做:

git revert D'

这可能会产生合并冲突,特别是如果您不还原B'and C',但这可能比重新手动执行X更好Y。Linux Torvalds对这个场景写了一个非常详尽的解释,可能对你有一些帮助。

于 2014-01-22T22:23:37.747 回答