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

asm*_*rer 114 git

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

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

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

cor*_*ump 115

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

假设您original.txt在分支(local分支)上进行了修改,但在主分支上,original.txt已经复制到另一个分支,比如说copy.txt.此副本已在我们提交的提交中完成CP.

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

 ---- X -----CP------ (master)
       \ 
        \--A---B--- (local)
Run Code Online (Sandbox Code Playgroud)

move在更改的起始点创建一个一次性分支git branch move X.也就是说,将move分支置于commit X,即想要合并的提交之前; 最有可能的是,这是您为实现更改而分支的提交.用户@digory doo在下面写道,你可以git merge-base master local找到X.

 ---- X (move)-----CP----- (master)
       \ 
        \--A---B--- (local)
Run Code Online (Sandbox Code Playgroud)

在此分支上,发出以下重命名命令:

git mv original.txt copy.txt
Run Code Online (Sandbox Code Playgroud)

这会重命名文件.请注意,copy.txt此时树中尚不存在.
提交您的更改(我们将此提交命名为MV).

        /--MV (move)
       /
 ---- X -----CP----- (master)
       \ 
        \--A---B--- (local)
Run Code Online (Sandbox Code Playgroud)

您现在可以在以下方面重新定位您的工作move:

git rebase move local
Run Code Online (Sandbox Code Playgroud)

这应该没有问题,您的更改将应用​​于copy.txt您的本地分支.

        /--MV (move)---A'---B'--- (local)
       /
 ---- X -----CP----- (master)
Run Code Online (Sandbox Code Playgroud)

现在,您不一定要或不需要MV在主分支的历史记录中进行提交,因为移动操作可能会导致与CP主分支中的提交时的复制操作发生冲突.

您只需要再次修改工作,放弃移动操作,如下所示:

git rebase move local --onto CP
Run Code Online (Sandbox Code Playgroud)

...在另一个分支中引入CP的提交位置copy.txt.这会在提交copy.txt之上重新定义所有更改CP.现在,您的local分支就像您始终修改copy.txt而不是original.txt,并且您可以继续与其他人合并.

                /--A''---B''-- (local)
               /
 -----X-------CP----- (master)
Run Code Online (Sandbox Code Playgroud)

重要的是应用更改CPcopy.txt不存在更改,并且将更改应用更改original.txt.

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

  • 这个解决方案只涉及基本的git命令,不像编辑补丁或使用`patch`(这也涉及很多工作),这就是为什么我认为展示它可能很有趣.此外,请注意,在我的情况下,我花了更多时间来写答案,而不是实际应用更改.您会在哪一步使用合并?为什么?我看到的唯一区别是,通过重新定位,我进行了一个临时提交,后来被丢弃(提交`MV`),这对于仅合并是不可能的. (6认同)
  • 我添加了一些ASCII树来阐明方法.在这种情况下重新考虑合并与rebase:我想要做的是在我的分支中对'original.txt'进行所有更改并将它们应用到master分支中的'copy.txt',因为出于某种原因,'原创. txt'在某些时候被复制(而不是移动)到'copy.txt'.在该副本之后,'original.txt'也可能在主分支上进化.如果我直接合并,我对original.txt的本地更改将应用​​于master分支中的修改后的original.txt,这将很难合并.问候. (4认同)
  • 这是很多工作,但我认为原则上应该有效.不过,我认为你在合并时会有更好的运气. (2认同)
  • 使用 rebase,你有更高的机会处理合并冲突,因为你处理每个提交,而使用合并你一次处理所有事情,这意味着可能在 rebase 中发生的一些更改在合并中将不存在。我要做的是合并,然后手动移动合并的文件。不过,也许我误解了你的答案。 (2认同)

Cas*_*bel 28

You can always use git diff (or git format-patch) to generate the patch, then go manually edit the filenames in the patch, and apply it with git apply (or git am).

Short of this, the only way it's going to work automatically is if git's rename detection can figure out that the old and new files are the same thing - which it sounds like they aren't really in your case, just a chunk of them. It's true that git uses blobs, not files, but a blob is just the contents of an entire file, without the filename and metadata attached. So if you have a chunk of code moved between two files, they aren't really the same blob - the rest of the blob's content is different, just the chunk in common.

  • 嗯,这是迄今为止最好的答案。我不知道如何使“git format-patch”适用于提交。如果我执行“git format-patch SHA1”,它会为整个历史生成一大堆补丁文件。但我想 `git show SHA1 > diff.patch` 也能正常工作。 (2认同)

Vin*_*eib 19

这是一个合并解决方案,遇到合并冲突,重命名和编辑,并使用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
Run Code Online (Sandbox Code Playgroud)

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

$ git branch branch-with-edits
Branch branch-with-edits set up to track local branch master.
Run Code Online (Sandbox Code Playgroud)

在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
Run Code Online (Sandbox Code Playgroud)

切换到分支,并在那里编辑:

$ 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(+)
Run Code Online (Sandbox Code Playgroud)

尝试合并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.
Run Code Online (Sandbox Code Playgroud)

请注意,冲突很难解决 - 并且文件已重命名.中止,模仿重命名:

$ 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%)
Run Code Online (Sandbox Code Playgroud)

再次尝试合并:

$ 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.
Run Code Online (Sandbox Code Playgroud)

大!合并导致可以使用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
Run Code Online (Sandbox Code Playgroud)

  • 在该解决方案中,在我看来,第一步,即中止的合并,仅对找出哪些文件被远程重命名和编辑有用。如果你提前认识他们的话。您可以跳过该步骤,基本上,解决方案只是在本地手动重命名文件,然后照常合并并解决冲突。 (2认同)