如何恢复提交将其移动到HEAD并且不会丢失之后的提交?

时间:2014-08-20 04:28:49

标签: git

我想要签出并在之前提交我的git树的新HEAD,但我仍然希望保留它之后的所有提交。 所以...

提交:A,B,C,D,E,F 成为:A,B,C,D,E,F,C

有效地使C成为HEAD,但保留E和F.

思想?

3 个答案:

答案 0 :(得分:0)

您可以使用--soft标志重置分支以保留更改

这将使您从F回到C,但是E和F的更改将是未提交的

git reset --soft HEAD@{3}

因此,您需要在重置后提交E和F的更改,但您最终会得到一个类似于此的提交历史记录

  • 提交A
  • 提交B
  • 提交C
  • 将D + E + F作为单一提交提交

答案 1 :(得分:0)

我仍然不清楚你想要的结果。你现在拥有的(显然):

..- A - B - C - D - E - F   <-- HEAD=somebranch

也就是说,存储库中有一系列提交,提交AA代表一些丑陋的40字符SHA-1,如67de23ddb1ed5471e302f6a84fae7a9037a0d980)有一些未指定的父母和一个完整的树附加。如果您git checkout A,您的工作树中会填充您提交A时所代表的代码(或.txt文件或其他内容)。提交B已将A作为其父级,并附加了完整的树,依此类推。您当前在某个分支(我方便地称为somebranch),因此该分支的提示指向提交F。 git-repo-file HEAD包含分支的名称。

如果您git checkout somebranch~3git 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 revertD(按相反的顺序),相当于应用其更改的反向。 (这就是为什么你这样做 - 或者git以相反的顺序执行它:在恢复F之后,这是微不足道的,撤消F中的任何内容也是微不足道的,等等。如果你试图但是,首先撤消EDCDE的进一步变化而导致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}如果/需要,可以提交DF的提交。

如果允许这样做,通常就是这样。当您将分支提示发布给其他人时,可能会出现不允许的主要原因。撤销已发布的提交(通过倒回分支)使得其他人必须做一些工作才能从某些(非常常见的)情况中恢复。如果他们可以做这项工作,或者没有这样的人,倒带很好。

答案 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