我想要签出并在之前提交我的git树的新HEAD,但我仍然希望保留它之后的所有提交。 所以...
提交:A,B,C,D,E,F 成为:A,B,C,D,E,F,C
有效地使C成为HEAD,但保留E和F.
思想?
答案 0 :(得分:0)
您可以使用--soft
标志重置分支以保留更改
这将使您从F回到C,但是E和F的更改将是未提交的
git reset --soft HEAD@{3}
因此,您需要在重置后提交E和F的更改,但您最终会得到一个类似于此的提交历史记录
答案 1 :(得分:0)
我仍然不清楚你想要的结果。你现在拥有的(显然):
..- A - B - C - D - E - F <-- HEAD=somebranch
也就是说,存储库中有一系列提交,提交A
(A
代表一些丑陋的40字符SHA-1,如67de23ddb1ed5471e302f6a84fae7a9037a0d980
)有一些未指定的父母和一个完整的树附加。如果您git checkout A
,您的工作树中会填充您提交A
时所代表的代码(或.txt文件或其他内容)。提交B
已将A
作为其父级,并附加了完整的树,依此类推。您当前在某个分支(我方便地称为somebranch
),因此该分支的提示指向提交F
。 git-repo-file HEAD
包含分支的名称。
如果您git checkout somebranch~3
或git checkout HEAD~3
,您将发现自己处于“独立HEAD”模式,工作树中填充了附加到提交C
的任何内容。这使您可以在不执行任何其他操作的情况下使用其内容,稍后您可以git checkout somebranch
返回分支somebranch
和提交F
。
如果您愿意,可以将附加到提交C
的树复制到您的工作树中,同时在分支somebranch
和提交F
上,然后进行新的提交G
。这是一种方法,它假设您处于存储库的顶层:
$ git rm -rf . # tell git to remove everything on the next
# commit, but don't commit that yet!
$ git checkout HEAD~3 -- . # tell git to repopulate from C
$ git commit
git rm
步骤会清除F
中但C
中没有的任何内容 - 或者说清除所有内容,包括 在C
。 1 然后我们将C
中的所有内容提取到索引/登台区域和工作树中,但不更改{{1点。然后HEAD
将索引写入新的提交(我们可以调用commit
或更好,G
):其父级为C'
,但其树< / em>,这个提交F
时出来的文件集与git checkout
的文件集相同。
1 如果C
中的任何内容都不在C
中,则F
步骤是不必要的。通过查找rm
中不在F
中的任何文件并仅删除那些文件,也可以更加聪明地对工作树所做的工作,但它可能不值得做多少工作优化这个,除了练习。好吧,除非你经常这样做。
还有其他方法可以达到这一点,即给出相似甚至相同的结果。例如,您可以C
提交git revert
到D
(按相反的顺序),相当于应用其更改的反向。 (这就是为什么你这样做 - 或者git以相反的顺序执行它:在恢复F
之后,这是微不足道的,撤消F
中的任何内容也是微不足道的,等等。如果你试图但是,首先撤消E
,D
或C
因D
或E
的进一步变化而导致F
- 至 - git revert
的任何变化都会产生冲突。)git revert HEAD~3..HEAD
命令可以执行此操作,或者进行中间提交:
git revert --no-commit HEAD~3..HEAD
或跳过它们以便您必须自己提交最终结果:
C'
第一个版本为您提供了几个中间提交,最终结果实际上是提交rm, checkout old version, commit
;第二个给你与C'
相同的东西,即只提交D
。
最后,还有一个选择。目前尚不清楚为什么你要F
通过C'
,但一个经典的原因是你认为它们不是很正确,但实际上它们可能是正确的,或者你可能想要把他们将来。所以我们就是这样说的。制作新的提交F
而不是为了恢复某些工作,而是将其保留在历史记录中,您可以简单地重命名这段历史。我们首先简单地添加一个新的分支名称,该名称也指向提交$ git checkout somebranch # if not already there
$ git branch savedwork
:
..- A - B - C - D - E - F <-- HEAD=somebranch, saved-work
现在我们有了这个:
..- A - B - C
\
D - E - F <-- HEAD=somebranch, saved-work
但是让我们像这样绘制它(它是相同的绘图,只是在行中扭结):
git reset --hard
现在我们只需somebranch
使C
指向提交C
,并更新工作树以匹配..- A - B - C <-- HEAD=somebranch
\
D - E - F <-- saved-work
:
somebranch
现在我们在分支C
上,它已被“重绕”,因此它以提交saved-work
结束,但新分支F
继续指向提交{{1}如果/需要,可以提交D
到F
的提交。
如果允许这样做,通常就是这样。当您将分支提示发布给其他人时,可能会出现不允许的主要原因。撤销已发布的提交(通过倒回分支)使得其他人必须做一些工作才能从某些(非常常见的)情况中恢复。如果他们可以做这项工作,或者没有这样的人,倒带很好。
答案 2 :(得分:0)
使用硬重置将commit C设置为当前分支的头部将有效地执行您想要的操作 - 其他提交成为&#34;分离的头部&#34; (但最终它们将作为垃圾收集的一部分进行清理)。保存它们所需要做的就是将它们分成一个单独的分支:
让我们说你当前的分支是master
。在提交F运行:
git checkout -b saved-commits // Create the new branch, on commit F
git chekcout master // checkout master again
git reset --hard C // reset the HEAD to commit C (you'll need commit C's hash after the --hard paramter)
现在,您将拥有两个分支:master
(在C上)和saved-commits
(在F上)。如果你再次提交master,它将实际上是提交G.你可以稍后合并,挑选,或继续在saved-commits分支中工作,并检查出来(git checkout saved-commits
)