git merge:对移动到不同文件的代码应用更改

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/3491270/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-09-10 08:54:12  来源:igfitidea点击:

git merge: apply changes to code that moved to a different file

git

提问by asmeurer

I am attempting a pretty beefy git merge maneuver right now. One problem that I am coming across is that I made some changes to some code in my branch, but my colleague moved that code to a new file in his branch. So when I did git merge my_branch his_branch, git did not notice that the code in the new file was the same as the old, and so none of my changes are there.

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

What's the easiest way to go about applying my changes again to the code in the new files. I won't have too many problems finding out which commits need to be reapplied (I can just use git log --stat). But as far as I can tell, there is no way to get git to reapply the changes into the new files. The easiest thing I am seeing right now is to manually reapply the changes, which is not looking like a good idea.

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

I know that git recognizes blobs, not files, so surely there must be a way to tell it, "apply this exact code change from this commit, except not where it was but where it now is in this new file".

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

采纳答案by coredump

I had a similar issue, and I resolved it by rebasing my work to match the target file organization.

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

Say that you modified original.txton your branch (the localbranch), but on the master branch, original.txthas been copied to another one, say copy.txt. This copy has been done in a commit that we name commit CP.

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

You want to apply all your local changes, commits Aand Bbelow, that were made on original.txt, to the new file copy.txt.

您希望将在 上所做的所有本地更改、提交AB以下更改应用original.txt到新文件copy.txt

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

Create a throwaway branch moveat the starting point of your changes with git branch move X. That is to say, put the movebranch at commit X, the one before the commits you want to merge; most likely, this is the commit from which you branched out to implement your changes. As user @digory doowrote below, you can do git merge-base master localto find X.

move使用git branch move X.在更改的起点创建一个一次性分支。也就是说,把move分支放在 commit X,也就是你要合并的 commit 之前的那个;最有可能的是,这是您分支以实现更改的提交。正如用户@digory doo在下面所写的那样,您可以git merge-base master local找到X.

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

On this branch, issue the following renaming command:

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

git mv original.txt copy.txt

This renames the file. Note that copy.txtdid not yet exist in your tree at this point.
Commit your change (we name this commit MV).

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

        /--MV (move)
       /
 ---- X -----CP----- (master)
       \ 
        \--A---B--- (local)

You can now rebase your work on top of move:

您现在可以在以下基础上重新构建您的工作move

git rebase move local

This should work without problem, and your changes are applied to copy.txtin your local branch.

这应该可以正常工作,并且您的更改将应用​​于copy.txt您的本地分支。

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

Now, you do not necessarily want or need to have commit MVin your main branch's history, because the move operation may lead to a conflict with the copy operation at commit CPin the main branch.

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

You only have to rebase your work again, discarding the move operation, as follows:

你只需要再次重新设置你的工作,放弃移动操作,如下所示:

git rebase move local --onto CP

... where CPis the commit where copy.txtwas introduced in the other branch. This rebases all the changes on copy.txton top of the CPcommit. Now, your localbranch is exactly as if you always modified copy.txtand not original.txt, and you can continue merging with others.

...在另一个分支中引入CP的提交在哪里copy.txt。这会将所有更改重新设置copy.txtCP提交之上。现在,您的local分支就好像您一直在修改copy.txt而不是 一样original.txt,您可以继续与其他人合并。

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

It is important that the changes are applied on CPor otherwise copy.txtwould not exist and the changes would be applied back on original.txt.

重要的是,更改应用于CP或以其他方式copy.txt不存在并且更改将应用​​回original.txt

Hope this is clear. This answer comes late, but this may be useful to someone else.

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

回答by Cascabel

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).

您始终可以使用git diff(或git format-patch) 生成补丁,然后手动编辑补丁中的文件名,并使用git apply(或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 的重命名检测是否可以确定旧文件和新文件是同一回事 - 听起来它们并不是你的情况,只是其中的一部分。确实,git 使用 blob,而不是文件,但 blob 只是整个文件的内容,没有附加文件名和元数据。因此,如果您在两个文件之间移动了一段代码,那么它们实际上并不是同一个 blob - blob 的其余内容是不同的,只有相同的块。

回答by Vincent Scheib

Here is a mergesolution of encountering a merge conflict with rename and edit and resolving it with mergetool recognizing the correct 3 merge source files.

这是遇到合并冲突的合并解决方案,重命名和编辑并使用合并工具识别正确的 3 个合并源文件来解决它。

  • After a merge fails because of 'deleted file' that you realize was renamed and edited:

    1. You abort the merge.
    2. Commit renamed files on your branch.
    3. And merge again.
  • 由于您意识到已重命名和编辑的“已删除文件”而导致合并失败后:

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

Walk-through:

演练:

Create a file.txt:

创建一个文件.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

Create a branch where you will edit later:

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

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

Create the rename and edit on 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

Swap to branch, and edit there too:

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

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

Attempt to merge master:

尝试合并 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.

Notice the conflict is hard to resolve - and that files were renamed. Abort, mimic the rename:

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

$ 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%)

Try merge again:

再次尝试合并:

$ 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.

Great! Merge results in a 'normal' conflict that can be resolved with mergetool:

伟大的!合并会导致“正常”冲突,可以使用 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