如何签出旧提交并使其成为新提交

时间:2013-07-03 13:50:00

标签: git

我想跟进另一个关于此问题的问题:“跟进”: Checkout old commit and make it a new commit

但他们说“不要那样做!”所以看来我必须问一个新问题。 (即使是同样的问题,我认为对我来说最好的答案并没有按预期工作......

如果我有提交 A-B-C-D-E-F(想象这些都是SHA的)。 我希望将整个存储库与C完全相同,然后将其提交以创建'G',这与C完全相同。因此,当我完成时,日志是A-B-C-D-E-F-G,尽管C& G是完全相同的。

一个答案表明樱桃选择,这似乎很完美,除了它让我解决CF之间的每一次冲突。我查看了文档,无论如何我尝试了--force,然后是--patch的建议。 --patch最接近,但并非绝对。那么有没有办法让樱桃挑选只选择C版本的冲突?

另一个最接近的答案是结帐C,但我找不到将其保留在同一分支上的魔术字。我最近完成的训练说最后使用“魔术破折号”告诉git你想在当前分支上使用它,但无论我做什么,都会创建一个“(无分支)”分支。

我相信你可以告诉我,我对git(以及一般的命令行)很新,但我试图自己搞清楚。如果你可以使用你推荐的详细版本,那么它会更好地贴在我的头上,我将不胜感激。 (-a = --all-a = --annotate-a = --albuquerque?

看起来很简单,而且你可能想用git做什么 - 如果你改变主意,就回去上一次提交而不会丢失中间提交。

8 个答案:

答案 0 :(得分:5)

您是否介意生成:A-B-C-D-E-F-F'-E'-D'D'处的代码状态与C处的状态完全相同(G == D' )?在这种情况下,只需还原FED。如果您不想要中间步骤,revert但不应用,然后提交。那就是:

$ git revert -n HEAD
$ git revert -n HEAD~
$ git revert -n HEAD~2
$ git commit -m 'Revert D,E,and F'

此后,当前HEAD为G,两个提交G和C应包含相同的代码树。您可以通过查看git cat-file -p HEAD | grep ^treegit cat-file -p C | grep ^tree的输出进行验证。这两个命令都应该提供相同的输出。

但是,为什么要保留中间提交并不是很清楚。如果您希望它们适用于后代,请执行以下操作:git branch old-stuffgit reset C这会将您当前的分支设置回C,但DE,仍然可以在名为F的分支中查看old-stuff

答案 1 :(得分:1)

答案 2 :(得分:1)

git cherry-pick --strategy=recursive -X ours C

git-merge(1)

  

递归策略可以采用以下选项:

     

我们

     
    

此选项可以通过支持我们的版本来强制自动解决冲突的帅哥。 [...]

  

“我们的”和“他们的”是指两个提交合并。但是,我不确定git cherry-pick处理提交的方式,因此您可能需要-X theirs。你可以建立一个新的分支,试一试,看看。

答案 3 :(得分:0)

如果你想结束:  -G-D-E-F (不确定,我对&#34感到困惑; D,E和F就在那里。") 然后,到达那里的最佳方式是rebase -i,并将A-B-C压缩在一起。

答案 4 :(得分:0)

从您的评论判断到我的其他答案(我没有删除,因为该解决方案比这更正确,但这似乎是您想要的),您可以使用管道命令commit-tree作为如下:

git reset $( git commit-tree $tree -p F -m 'Revert D,E, and F' )

其中$ tree是提交C的树对象的哈希值。(git cat-file -p C | grep ^tree的输出)。这将创建一个新的提交,其中底层树与提交C的树相同,但新提交的父提交是F.它还将当前分支设置为指向新提交,使其成为新的HEAD。 / p>

答案 5 :(得分:0)

你能描述一下你想要的:“让你的工作树和C一样,然后提交”?如果是这样,这是一种方法:

git checkout C     # working tree same as C. But also moves HEAD to C...
git reset F        # ...so move HEAD back to F, leaving working tree alone
git commit -a      # commit working tree

编辑这可能会产生一系列合并冲突,因此它无法解决您问题的那一部分。

EDIT3 同样,前一个问题的selected answer解决了这个问题:首先删除所有内容,没有冲突。


顺便说一句:在不改变HEAD的情况下使工作树等于提交C会很好,但我认为没有(瓷器)这样做。如果您想要整个提交,git checkoutgit reset都会更改当前分支。 git checkout可以在不移动当前分支的情况下将单个文件提取到工作树,但是您必须单独提取每个文件,而不是整个提交...

EDIT2 哦,我从selected answer看到你之前的问题,你可以这样做。我曾尝试git checkout C -- "*",但您需要git checkout C -- .所以它只会是:

git checkout C -- .    # working tree same as C, without moving branch (NB ".")
git commit -a

答案 6 :(得分:0)

看起来你希望C成为你的git存储库的最终状态。

以“A-B-C-D-E-F-G”为例,

您可以使用

按顺序还原G,F,E,D

git revert [commitID]

然后使用 git commit

G,F,E,D全部还原后,您的存储库将保持与C相同的状态。

仅本地分支的另一种方法是:

git resert --hard HEAD~4

这将重置您的本地分支以提交C并删除D,E,F,G。

答案 7 :(得分:0)

我实际上在提交有关my own question的信息之前就找到了您的信息,但是无论如何-您可以使用树形哈希做到这一点。

这个想法是每个提交都有一个与之关联的“树对象”,它描述了整个工作树,因此您要做的就是创建一个与旧提交具有相同树对象的新提交。 HEAD。

以下是执行此操作的脚本:

#/bin/bash
COMMITID=$1
git reset --hard $(git commit-tree -m "Revert to commit $COMMITID" -p $(git rev-parse HEAD) $(git rev-parse $COMMITID^{tree}))