我正在尝试一种非常强大的git合并策略。我遇到的一个问题是我对我的分支中的某些代码进行了一些更改,但我的同事将该代码移动到其分支中的新文件中。所以当我做git merge my_branch his_branch
时,git没有注意到新文件中的代码与旧文件中的代码相同,因此我没有任何更改。
将更改再次应用于新文件中的代码的最简单方法是什么。我不会有太多问题找出需要重新应用的提交(我可以使用git log --stat
)。但据我所知,没有办法让git将更改重新应用到新文件中。我现在看到的最简单的事情是手动重新应用更改,这看起来不是一个好主意。
我知道git识别blob,而不是文件,所以肯定必须有一种方法可以告诉它,“从这个提交中应用这个确切的代码更改,除了它不是它现在在这个新文件中的位置”。
答案 0 :(得分:108)
我有一个类似的问题,我通过重新定位我的工作来解决它,以匹配目标文件组织。
假设您在分支(original.txt
分支)上修改了local
,但在主分支上,original.txt
已复制到另一个分支,例如copy.txt
。
此副本已在我们命名为commit CP
的提交中完成。
您希望将以下A
下的所有本地更改,提交B
和original.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个合并源文件。
由于“已删除的文件”导致合并失败,您实现了重命名和编辑:
演练:
创建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)
我对此问题的快速解决方案(在我的情况下,它不是单个文件,而是整个目录结构):
git commit -m "moved to original location for merging"
git merge his_branch
(这次没有冲突!)git commit -m "moved back to final location after merge"
您将在历史记录中另外进行两次提交。
但是由于git跟踪文件的移动,因此git blame
,git log
等仍然可以在这些文件上运行,因为移动文件的提交并没有改变它们。因此,我认为这种方法没有任何缺点,而且很容易理解。