git merge:将更改应用于移动到其他文件的代码

时间:2010-08-16 07:19:27

标签: git

我正在尝试一种非常强大的git合并策略。我遇到的一个问题是我对我的分支中的某些代码进行了一些更改,但我的同事将该代码移动到其分支中的新文件中。所以当我做git merge my_branch his_branch时,git没有注意到新文件中的代码与旧文件中的代码相同,因此我没有任何更改。

将更改再次应用于新文件中的代码的最简单方法是什么。我不会有太多问题找出需要重新应用的提交(我可以使用git log --stat)。但据我所知,没有办法让git将更改重新应用到新文件中。我现在看到的最简单的事情是手动重新应用更改,这看起来不是一个好主意。

我知道git识别blob,而不是文件,所以肯定必须有一种方法可以告诉它,“从这个提交中应用这个确切的代码更改,除了它不是它现在在这个新文件中的位置”。

4 个答案:

答案 0 :(得分:108)

我有一个类似的问题,我通过重新定位我的工作来解决它,以匹配目标文件组织。

假设您在分支(original.txt分支)上修改了local,但在主分支上,original.txt已复制到另一个分支,例如copy.txt。 此副本已在我们命名为commit CP的提交中完成。

您希望将以下A下的所有本地更改,提交Boriginal.txt应用于新文件copy.txt

 ---- X -----CP------ (master)
       \ 
        \--A---B--- (local)

使用move在更改的起点创建一次性分支git branch move X。也就是说,将move分支放在提交X,即要合并的提交之前;最有可能的是,这是您为实施更改而分支的提交。用户 @digory doo 写在下面,您可以git merge-base master local查找X

 ---- 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上的所有更改。 现在,您的local分支就像您始终修改copy.txt而非original.txt一样,并且您可以继续与其他人合并。

                /--A''---B''-- (local)
               /
 -----X-------CP----- (master)

更改应用于CP或其他copy.txt不一定非常重要,更改将应用​​于original.txt

希望这很清楚。 这个答案很晚,但这可能对其他人有用。

答案 1 :(得分:26)

您始终可以使用git diff(或git format-patch)生成修补程序,然后手动编辑修补程序中的文件名,并将其应用于git apply(或{{1} })。

如果没有这个,那么它自动运行的唯一方法是,如果git的重命名检测可以发现旧文件和新文件是相同的 - 听起来它们实际上不是你的情况,只是一大块他们确实git使用blob而不是文件,但blob只是整个文件的内容,没有附加文件名和元数据。因此,如果您在两个文件之间移动了一大块代码,那么它们实际上并不是相同的blob - blob内容的其余部分是不同的,只是共同的块。

答案 2 :(得分:17)

这是一个 merge 解决方案,遇到与重命名的合并冲突,并使用mergetool解析它,识别正确的3个合并源文件。

  • 由于“已删除的文件”导致合并失败,您实现了重命名和编辑:

    1. 您中止合并。
    2. 在您的分支上提交重命名的文件。
    3. 再次合并。

演练:

创建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

创建一个分支,稍后您将对其进行编辑:

$ git branch branch-with-edits
Branch branch-with-edits set up to track local branch master.

在master上创建重命名和编辑:

$ 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(+)

尝试合并master:

$ 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

答案 3 :(得分:1)

我对此问题的快速解决方案(在我的情况下,它不是单个文件,而是整个目录结构):

  • 将“ my_branch”中的文件移动到“ his_branch”中的位置(git rm / git add)
  • git commit -m "moved to original location for merging"
  • git merge his_branch(这次没有冲突!)
  • 将文件移动到我想要的位置(git rm / git add)
  • git commit -m "moved back to final location after merge"

您将在历史记录中另外进行两次提交。

但是由于git跟踪文件的移动,因此git blamegit log等仍然可以在这些文件上运行,因为移动文件的提交并没有改变它们。因此,我认为这种方法没有任何缺点,而且很容易理解。