将修补程序应用于分支中的早期提交,然后将其作为下一个提交附加

时间:2018-04-05 06:39:07

标签: git

让我们说我有一个分支,有许多提交:

A->B->C

然后我在AC之间创建一个忽略空格更改的补丁。然后我将补丁应用到A

A->B->C
 \
  ->D

但是我不想丢失我的提交历史记录,我只是想要一个额外的提交,它会从与我的补丁无关的部分代码中删除任何空白更改。

所以我希望我的提交历史看起来像这样:

A->B->C->D

其中D只是提交,与A相比,删除任何仅仅是空白的更改。

这还有什么可以实现的呢?注意我不想合并CDD应该包含所有C的更改,除了空格更改自A以来未更改的内容。合并CD我害怕可能会重新回到我试图清理的空白变化中。

2 个答案:

答案 0 :(得分:2)

git checkout D; git rebase C会做你想做的事:

A->B->C->D'

如果发生冲突,您仍然需要合并来创建D'提交。

答案 1 :(得分:2)

首先,一个小的(但重要的)技术说明。我假设在

A->B->C

你的意思是暗示AB的父提交,而BC的父提交。

在Git中,这些父/子关系存在于图中,但向后:

A<-B<-C

也就是说,孩子们知道他们的父母是谁,但父母不知道他们的孩子是谁。 (这是因为提交,一旦制作,是不可变的。没有地方记录他们的孩子!孩子是在父母存在时制作的,所以孩子们记录他们的父哈希ID,但反之亦然。 )

听起来我想要将D中的快照复制到D'之后的新提交C

A--B--C--D'   <-- branch1
 \
  D   <-- branch2

(以git diff的输出比较任何顺序的提交DD'始终为空。要做到这一点,不要做以下任何事情。相反,只需查看branch1,删除每个文件(如果C中存在D中不存在的文件 - 您可以跳过此步骤,如果事实并非如此),然后将每个文件从D'提取到索引和工作树中,然后提交:

<make sure you are at the top level of your repository>
$ git checkout branch1
$ git rm -r .                # remove ALL files (optional)
$ git checkout branch2 -- .  # restore the to-keep-files from D
$ git commit -C branch2      # make new commit, using message from D

使用git rm -r .; git checkout branch2 -- .替换git read-tree的变体稍微短一些(也许可能不那么可怕,但也有同样的东西)变体,但它更难以推理,所以我用这个来说明。

你在评论中提到:

  

我只需要一种从C-&gt; D

制作补丁文件的方法

当您使用git show将提交(快照)转换为补丁(自父提交后更改)时,Git只运行带有两个提交哈希的git diff

  • 父提交为&#34;之前&#34; part:第一个(左侧)哈希
  • 孩子犯下&#34;&#34;&#34;&#34; part:第二个(右侧)哈希

或:

git diff <hash-of-A> <hash-of-D>

例如,当您在提交A vs D上使用git log -pgit show时,就会为您提供D补丁。

您可以自己手动运行git diff,以比较提交C与提交D;您需要做的就是提供标识两个特定提交的任何内容。他们的原始哈希ID是最简单的,但您可以使用the gitrevisions documentation中描述的任何名称。

作为Camusensei suggests and evolutionxbox mentions,您可以使用git cherry-pickgit rebase计算从AD的差异,然后将差异应用于{{1} }。使用cherry-pick是C 所做的;区别:

git rebase

git checkout <branch-name-that-identifies-C>
git cherry-pick <any-name-that-identifies-D>

git checkout <branch-name-that-identifies-D> git rebase <any-name-that-identifies-C> 操作使用于标识提交rebase的分支名称现在标识副本D。这两个操作都添加了一个新的D'提交,它是D'的副本,但是当您在用于标识D的分支上时,cherry-pick命令会执行此操作,现在标识{{ 1}}。也就是说,生成的提交集是相同的;区别在于哪些分支名称标识哪些提交

这些都没有直接查看C vs D':它们都会查看C vs D以及如何将这些更改插入通过提取提取获得的快照{ {1}}。因此,这完全不等同于计算A vs D,然后将其应用于C