如果我有两个提交,它们之间有很多提交距离,并且在这两个提交中都有许多文件,那么如何将一个hunk从一个提交到另一个,例如:
提交100中的:
我有很多文件更改和文件“aa.txt”中的许多更改,还有这一个:
- aaaa
- bbbb
+ cccc
10次提交后,我有另一次提交更改了很多文件,还有“aa.txt”:
+dddd
我想将换行-aaaa
从前者移到后者。
是否有任何CLI / UI工具可以帮助您轻松完成? (我显然没有历史改写的问题)
答案 0 :(得分:4)
交互式rebase可能会起作用。但是很多因素可能会使这一点复杂化。所以你已经描述了这么多:
x -- x -- A -- B -- C -- D -- x -- x <--(master)
A
中的某些行已更改,因此B
,C
,D
等也有所不同。但您想要一个新的历史记录t改为D
。所以你可以说
git rebase --interactive A^ master
(其中A
是先前有更改的提交的SHA ID,并记下所述ID末尾的^
。在出现的文本编辑器中,您将看到“待办事项”列表。第一行是pick
提交A
;将其更改为edit
。然后找到D
的行(在此示例中稍后是3次提交,但在您声明的示例中可能稍后会提交10次)。同时标记edit
。
rebase将会启动,但在暂时重新应用A
后,它会暂停,以便您可以编辑提交。
现在,如果您无法通过手动/从内存轻松完成对问题的更改,那么您可以取消对该文件的更改
git reset HEAD^ -- aa.txt
然后以“补丁模式”再次登台。
git add --patch -- aa.txt
系统会提示您如何处理每个更改块。如果要删除的更改显示在与其他更改相同的块中,您可以使用e
回答提示并编辑更改块(然后替换您不再需要的行之前的-
使用删除。
现在将您的(暂存)编辑内容提交到提交
git commit --amend
您从索引中还原的更改仍在工作树中;把它弄出来,告诉rebase重新开始工作。
git stash
git rebase --continue
随着rebase继续向commit D
工作,干预提交可能会发生冲突(如果他们编辑的aa.txt太接近你还原的更改)。这些冲突应该很容易解决。 (冲突的HEAD
方将包括您不再删除的行;除了该行之外,您可能还需要冲突的“其他”方。)
提交D
也可能会出现冲突。如果是这样,你的工作很简单:只需通过保持冲突的“其他”方面来解决这个问题(包括删除相关行,因为这是你最终要做的事情)。然后,当单独提示编辑D
时(因为您在TODO列表中将其标记为edit
),您可以立即告知rebase --continue
。
如果D
没有冲突,没什么大不了的。系统会提示您进行编辑。弹出您之前创建的存储,重新应用您从A
提交中推迟的更改; add
; commit --amend
现在这种方法存在问题:如果有多个引用可以达到A
,则只会更新一个(上例中为master
)。例如,
x -- A -- B -- C -- D -- x <--(master)
\
x -- x <--(branch)
在这种情况下,branch
仍会看到旧历史记录。你最终得到了
x -- A' -- B' -- C' -- D' -- x <--(master)
\
A -- B -- x -- x <--(branch)
您可以通过执行类似
的操作来解决此问题rebase --onto B' B branch
如果有很多分支要处理,这将会变得很快。
另一个问题是如果rebase会遇到合并提交。在某种程度上,您可以使用--preserve-merges
来缓解这种情况,但如果合并是“邪恶的”(即可以使用默认合并策略自动解决,但是在编辑时,它仍然会导致问题(可能会默默地破坏历史记录))某种方式)。在这种情况下,你可以做的最接近的事情就是细分并在每一步中仔细地重现合并。
答案 1 :(得分:2)
使用git format-patch
编辑所需的修补程序并使用apply
或am
$ git format-patch HEAD~10
$ git am ...
如果您想创建单个文件,可以使用--stdout
并将其打印到文件中:
$ git format-patch master --stdout > changes.patch