git merge:将更改应用到移动到不同文件的代码
我正在尝试一个相当强大的git merge操作。 我遇到的一个问题是,我对分支中的一些代码做了一些修改,但是我的同事将这些代码移到了他的分支中的一个新文件中。 所以当我把git merge my_branch his_branch
,git没有注意到新文件中的代码和旧的一样,所以我的更改都没有。
再次将更改应用到新文件中的代码最简单的方法是什么? 我不会有太多的问题找出哪些提交需要重新应用(我可以只使用git log --stat
)。 但据我所知,没有办法让git将更改重新应用到新文件中。 我现在看到的最简单的事情是手动重新应用更改,这看起来不是一个好主意。
我知道git可以识别blob,而不是文件,所以一定有办法告诉它,“从这个提交中应用这个确切的代码更改,除了不在哪里,而是在这个新文件中的位置”。
我有类似的问题,我通过重新configuration我的工作来匹配目标文件组织来解决这个问题。
假设你在你的分支( local
分支)上修改了original.txt
,但是在master分支上, original.txt
已经被复制到了另外一个,比如说copy.txt
。 这个副本已经在我们提交CP
的提交中完成了。
您希望将所有在original.txt
中进行的本地更改(提交A
和B
到新文件copy.txt
。
---- X -----CP------ (master) \ \--A---B--- (local)
在更改的起始点创build一次性分支move
。 也就是说,将move
分支放置在提交X
之前,即提交要合并之前的分支; 最有可能的是,这是您从中实施您的更改的承诺。 正如用户@digory doo在下面写的,你可以做git merge-base master local
来findX
---- X (move)-----CP----- (master) \ \--A---B--- (local)
在此分支上,发出以下重命名命令:
git mv original.txt copy.txt
这将重命名该文件。 请注意, copy.txt
在您的树中还不存在。
提交你的改变(我们把这个提交MV
命名为)。
/--MV (move) / ---- X -----CP----- (master) \ \--A---B--- (local)
您现在可以在move
分配您的工作:
git rebase move local
这应该没有问题,您的更改将应用于您的本地分支copy.txt
。
/--MV (move)---A'---B'--- (local) / ---- X -----CP----- (master)
现在,你不一定需要或者不需要在主分支的历史中提交MV
,因为移动操作可能导致与主分支中提交CP
的复制操作冲突。
你只需要重新工作,丢弃移动操作,如下所示:
git rebase move local --onto CP
…其中CP
是在其他分支中引入copy.txt
的提交。 这将copy.txt
设置CP
提交上的copy.txt
上的所有更改。 现在,你的local
分支就像你总是修改copy.txt
而不是original.txt
,你可以继续和其他人合并。
/--A''---B''-- (local) / -----X-------CP----- (master)
在CP
上应用更改非常重要,否则copy.txt
将不存在,并且更改将应用于original.txt
。
希望这是明确的。 这个答案来得晚,但这对其他人可能是有用的。
你总是可以使用git diff
(或git format-patch
)来生成补丁,然后手动编辑补丁中的文件名,并使用git apply
(或git am
)来应用它。
简而言之,它自动工作的唯一方法是,如果git的重命名检测可以发现新旧文件是相同的东西 – 这听起来像他们不是真的在你的情况下,只是其中的一大块。 确实git使用的是blob,而不是文件,但blob只是整个文件的内容,没有附加文件名和元数据。 所以,如果你在两个文件之间移动了一段代码,那么它们就不是同一个blob了 – 其余的blob内容是不同的,只不过是块的共同点。
这是一个合并解决scheme,遇到合并冲突与重命名和编辑和解决它mergetool识别正确的3合并源文件。
-
合并失败后,因为你认识到被删除的文件被重命名和编辑:
- 你中止合并。
- 提交分支上的重命名文件。
- 然后再合并。
演练:
创build一个file.txt文件:
$ git init Initialized empty Git repository in /tmp/git-rename-and-modify-test/.git/ $ echo "A file." > file.txt $ git add file.txt $ git commit -am "file.txt added." [master (root-commit) 401b10d] file.txt added. 1 file changed, 1 insertion(+) create mode 100644 file.txt
创build一个分支,稍后您将进行编辑:
$ git branch branch-with-edits Branch branch-with-edits set up to track local branch master.
在master上创build重命名和编辑:
$ git mv file.txt renamed-and-edited.txt $ echo "edits on master" >> renamed-and-edited.txt $ git commit -am "file.txt + edits -> renamed-and-edited.txt." [master def790f] file.txt + edits -> renamed-and-edited.txt. 2 files changed, 2 insertions(+), 1 deletion(-) delete mode 100644 file.txt create mode 100644 renamed-and-edited.txt
交换分支,并在那里编辑:
$ git checkout branch-with-edits Switched to branch 'branch-with-edits' Your branch is behind 'master' by 1 commit, and can be fast-forwarded. (use "git pull" to update your local branch) $ $ echo "edits on branch" >> file.txt $ git commit -am "file.txt edited on branch." [branch-with-edits 2c4760e] file.txt edited on branch. 1 file changed, 1 insertion(+)
尝试合并主人:
$ git merge master CONFLICT (modify/delete): file.txt deleted in master and modified in HEAD. Version HEAD of file.txt left in tree. Automatic merge failed; fix conflicts and then commit the result.
注意冲突很难解决 – 文件被重命名。 中止,模仿重命名:
$ git merge --abort $ git mv file.txt renamed-and-edited.txt $ git commit -am "Preparing for merge; Human noticed renames files were edited." [branch-with-edits ca506da] Preparing for merge; Human noticed renames files were edited. 1 file changed, 0 insertions(+), 0 deletions(-) rename file.txt => renamed-and-edited.txt (100%)
再次尝试合并:
$ git merge master Auto-merging renamed-and-edited.txt CONFLICT (add/add): Merge conflict in renamed-and-edited.txt Recorded preimage for 'renamed-and-edited.txt' Automatic merge failed; fix conflicts and then commit the result.
大! 合并导致可以通过mergetool解决的“正常”冲突:
$ git mergetool Merging: renamed-and-edited.txt Normal merge conflict for 'renamed-and-edited.txt': {local}: created file {remote}: created file $ git commit Recorded resolution for 'renamed-and-edited.txt'. [branch-with-edits 2264483] Merge branch 'master' into branch-with-edits