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中进行的本地更改(提交AB到新文件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合并源文件。

  • 合并失败后,因为你认识到被删除的文件被重命名和编辑:

    1. 你中止合并。
    2. 提交分支上的重命名文件。
    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