让我们说我有一个分支,有许多提交:
A->B->C
然后我在A
和C
之间创建一个忽略空格更改的补丁。然后我将补丁应用到A
。
A->B->C
\
->D
但是我不想丢失我的提交历史记录,我只是想要一个额外的提交,它会从与我的补丁无关的部分代码中删除任何空白更改。
所以我希望我的提交历史看起来像这样:
A->B->C->D
其中D
只是提交,与A
相比,删除任何仅仅是空白的更改。
这还有什么可以实现的呢?注意我不想合并C
和D
,D
应该包含所有C
的更改,除了空格更改自A
以来未更改的内容。合并C
到D
我害怕可能会重新回到我试图清理的空白变化中。
答案 0 :(得分:2)
git checkout D; git rebase C
会做你想做的事:
A->B->C->D'
如果发生冲突,您仍然需要合并来创建D'
提交。
答案 1 :(得分:2)
首先,一个小的(但重要的)技术说明。我假设在
A->B->C
你的意思是暗示A
是B
的父提交,而B
是C
的父提交。
在Git中,这些父/子关系存在于图中,但向后:
A<-B<-C
也就是说,孩子们知道他们的父母是谁,但父母不知道他们的孩子是谁。 (这是因为提交,一旦制作,是不可变的。没有地方记录他们的孩子!孩子是在父母存在时制作的,所以孩子们记录他们的父哈希ID,但反之亦然。 )
听起来我想要将D
中的快照复制到D'
之后的新提交C
:
A--B--C--D' <-- branch1
\
D <-- branch2
(以git diff
的输出比较任何顺序的提交D
和D'
始终为空。要做到这一点,不要做以下任何事情。相反,只需查看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
:
或:
git diff <hash-of-A> <hash-of-D>
例如,当您在提交A vs D
上使用git log -p
或git show
时,就会为您提供D
补丁。
您可以自己手动运行git diff
,以比较提交C
与提交D
;您需要做的就是提供标识两个特定提交的任何内容。他们的原始哈希ID是最简单的,但您可以使用the gitrevisions documentation中描述的任何名称。
作为Camusensei suggests and evolutionxbox mentions,您可以使用git cherry-pick
或git rebase
计算从A
到D
的差异,然后将差异应用于{{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
。