我想跟进另一个关于此问题的问题:“跟进”: 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是完全相同的。
一个答案表明樱桃选择,这似乎很完美,除了它让我解决C
和F
之间的每一次冲突。我查看了文档,无论如何我尝试了--force
,然后是--patch
的建议。 --patch
最接近,但并非绝对。那么有没有办法让樱桃挑选只选择C
版本的冲突?
另一个最接近的答案是结帐C
,但我找不到将其保留在同一分支上的魔术字。我最近完成的训练说最后使用“魔术破折号”告诉git
你想在当前分支上使用它,但无论我做什么,都会创建一个“(无分支)”分支。
我相信你可以告诉我,我对git(以及一般的命令行)很新,但我试图自己搞清楚。如果你可以使用你推荐的详细版本,那么它会更好地贴在我的头上,我将不胜感激。 (-a
= --all
或-a = --annotate
或-a = --albuquerque?
)
看起来很简单,而且你可能想用git做什么 - 如果你改变主意,就回去上一次提交而不会丢失中间提交。
答案 0 :(得分:5)
您是否介意生成:A-B-C-D-E-F-F'-E'-D'
,D'
处的代码状态与C
处的状态完全相同(G
== D'
)?在这种情况下,只需还原F
,E
和D
。如果您不想要中间步骤,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 ^tree
和git cat-file -p C | grep ^tree
的输出进行验证。这两个命令都应该提供相同的输出。
但是,为什么要保留中间提交并不是很清楚。如果您希望它们适用于后代,请执行以下操作:git branch old-stuff
,git reset C
这会将您当前的分支设置回C
,但D
,E
,仍然可以在名为F
的分支中查看old-stuff
。
答案 1 :(得分:1)
我认为你需要使用git cherry-pick
。
https://www.kernel.org/pub/software/scm/git/docs/git-cherry-pick.html
答案 2 :(得分:1)
git cherry-pick --strategy=recursive -X ours C
递归策略可以采用以下选项:
我们
此选项可以通过支持我们的版本来强制自动解决冲突的帅哥。 [...]
“我们的”和“他们的”是指两个提交合并。但是,我不确定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解决了这个问题:首先删除所有内容,没有冲突。
git checkout
和git 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}))