git仅合并添加
我在不同的项目中使用了一个库,并根据需要进行了更新。因为我忘了复制一些更改,所以我最终得到了两个文件,其中添加了不同的内容,而我只添加了这些内容 因为我计划为这个库创建一个git repo,所以我创建了一个,添加了第一个文件,在一个分支上添加了第二个文件,并合并了它们。这给我留下了第二个文件的副本,而不是合并在一起的文件git仅合并添加,git,merge,Git,Merge,我在不同的项目中使用了一个库,并根据需要进行了更新。因为我忘了复制一些更改,所以我最终得到了两个文件,其中添加了不同的内容,而我只添加了这些内容 因为我计划为这个库创建一个git repo,所以我创建了一个,添加了第一个文件,在一个分支上添加了第二个文件,并合并了它们。这给我留下了第二个文件的副本,而不是合并在一起的文件 因此,我最终所做的是创建一个新的RPO,其中包含一个空白文件,然后将第一个文件复制到一个新的提交中,然后检查空白文件提交,然后复制第二个文件并创建一个新的分支,然后合并。这导致
因此,我最终所做的是创建一个新的RPO,其中包含一个空白文件,然后将第一个文件复制到一个新的提交中,然后检查空白文件提交,然后复制第二个文件并创建一个新的分支,然后合并。这导致了合并冲突,但在我删除
git插入的行我得到了我想要的文件
我想知道有没有更好的办法?尤其是当多个文件再次出现这种情况时。我尝试了一个可视化的合并工具,但它可以跨函数边界分割块,所以我不得不更手动地进行
编辑:我拥有的和我想要的例子
我有两个文件(伪代码):
文件1
文件2
defmodule foo
foo.bar = ...
foo.qux = ...
return foo
然后我想把这些合并成一个文件。因为新函数(baz和qux)没有相互调用,所以我对这两个函数都没意见
defmodule foo
foo.bar = ...
foo.baz = ...
foo.qux = ...
return foo
或
由于我只在这些文件中添加了内容,因此似乎我应该能够在不必手动剪切和粘贴的情况下获得所需的文件,而使用空文件和两个分支的技巧感觉过于复杂,无法很好地扩展多个文件。所以我想知道是否有更好的方法 好的,所以我把这个编成了。我们从
master
中带有自述文件的存储库开始:
$ mkdir mergesamp
$ cd mergesamp
$ git init
Initialized empty Git repository in .../mergesamp/.git/
$ cat << END > README
> We put a dummy README file into the base,
> to get an initial commit.
> END
$ git add README && git commit -m initial
[master (root-commit) 40d9565] initial
1 file changed, 2 insertions(+)
create mode 100644 README
然后我们回到master并创建一个新分支b2
来保存file2
(我在这里使用了一个简单的快捷方式,从master
标识的提交开始创建b2
,而不是使用两个单独的git命令):
在这一点上,我们希望回到master
,并使git合并file1
和file2
。但是当然,master
中没有通用的基本版本的文件,所以简单的git合并
是行不通的
(旁白:也许我们只是想将b2
合并到b1
,或者将b1
合并到b2
。我从您的原始版本中没有发现这一点,这就是为什么这种SSCCE/MVCE是一个好主意。幸运的是,这里的最终解决方案并不重要。)
处理这个问题有多种方法。也许从蓝天“思考”的角度来看,最简单的方法是回到master,创建一个公共基础文件,然后将两个分支重新设置到这一点上,这样它们就有了一个公共基础文件
然而,这是错误的方式。尽管如此,让我们展示一下
走错路
请注意,master
中的这个新提交与b1
中的file1
完全相同,因此当我执行重新基时,我必须保留一个空提交。(如果分支b1
中有其他更改,我不需要-k
和下面的其他内容。)
我想要空的提交(用于说明),因此我按照说明操作(添加--no edit
,因为我不想编辑提交消息):
唉,我遇到了一个git bug!我没有时间修复这个示例,所以我将强制完成重基,并让git做它在这里应该做的事情。(如果你不明白这一点,不要担心,git不应该做它刚刚做的事情,我正在努力解决它。)
现在我将重复使用b2
。不过,在重定基址之后,我需要将文件2重命名为文件1
$ git rebase master b2
First, rewinding head to replay your work on top of it...
Applying: add file2
$ git rm file1 && git mv file2 file1 && git commit -m 'rename file2->file1'
rm 'file1'
[b2 435e6e7] rename file2->file1
2 files changed, 3 insertions(+), 18 deletions(-)
delete mode 100644 file2
让我们查看提交图:
$ git log --graph --oneline --decorate --all
* 435e6e7 (HEAD -> b2) rename file2->file1
* 63a19b5 add file2
| * 3080d64 (b1) add file1
|/
* 71b0f5e (master) copy b1 file1 to common base
* 40d9565 initial
现在我可以在master上进行合并(分两步,我需要--no ff
,因为master
与b1
完全匹配,因为这个示例可能太小/太小了):
合并都完成了,但是如果我们查看file1
我们的版本是错误的:git认为它应该只使用b2
版本
让我们解开这团乱麻,看看如果我们简单地将b2
合并到b1
中会发生什么,因为它们有一个共同的基础:
$ git reset --hard 71b0f5e
HEAD is now at 71b0f5e copy b1 file1 to common base
$ git merge-file file1 /dev/null file2
(我在这里剪切并粘贴了SHA-1,因为它仍然在窗口中;或者我可以使用master~2
,因为有两个合并要丢弃。)
唉,和以前一样(这真的不令人惊讶),file1
只是拾取了b2
的更改,现在匹配了b2
中的版本。所以让我们也放弃这个合并,事实上,回到我们做所有重定基之前的设置,因为这是错误的方法
幸运的是,我们在原始的git日志--graph--oneline--decoration--all
输出中仍然有所有的初始提交ID
$ git checkout master && git reset --hard 40d9565
Switched to branch 'master'
HEAD is now at 40d9565 initial
$ git checkout b1 && git reset --hard f603e15
Switched to branch 'b1'
HEAD is now at f603e15 add file1
$ git checkout b2 && git reset --hard 01ef1ca
Switched to branch 'b2'
HEAD is now at 01ef1ca add file2
(注意:可以使用master
、b1
和b2
的reflogs来完成所有这些,但只要我们手头有原始SHA-1,这就更容易了。)
正确的方法:git合并文件
由于我们只想手动合并两个分支中的file1
和file2
,使用“空文件”作为公共基础版本,因此我们只想这样做。首先,让我们将这两个文件放入工作树:
$ git show b1:file1 > file1
$ git show b2:file2 > file2
现在我们告诉git merge file
使用空文件/dev/null
作为公共基础:
$ git reset --hard 71b0f5e
HEAD is now at 71b0f5e copy b1 file1 to common base
$ git merge-file file1 /dev/null file2
在这种情况下,合并会发现添加的项目之间存在冲突,因此我们必须手动编辑结果(在file1
),但它现在有了通常的。您的意思是,在进行新回购之前,您有:(1)与文件a
和B
的公共合并基础;(2) 对文件a
进行了一些添加,但未触及文件B
的分支;(3)您在其中对文件B
B添加了一些内容的分支
$ git branch -f b1 HEAD && git checkout b1
Switched to branch 'b1'
$ git log --graph --oneline --decorate --all
* 3080d64 (HEAD -> b1) add file1
* 71b0f5e (master) copy b1 file1 to common base
| * 01ef1ca (b2) add file2
|/
* 40d9565 initial
$ git rebase master b2
First, rewinding head to replay your work on top of it...
Applying: add file2
$ git rm file1 && git mv file2 file1 && git commit -m 'rename file2->file1'
rm 'file1'
[b2 435e6e7] rename file2->file1
2 files changed, 3 insertions(+), 18 deletions(-)
delete mode 100644 file2
$ git log --graph --oneline --decorate --all
* 435e6e7 (HEAD -> b2) rename file2->file1
* 63a19b5 add file2
| * 3080d64 (b1) add file1
|/
* 71b0f5e (master) copy b1 file1 to common base
* 40d9565 initial
$ git checkout master
Switched to branch 'master'
$ git merge --no-ff --no-edit b1
Already up-to-date!
Merge made by the 'recursive' strategy.
$ git merge --no-edit b2
Merge made by the 'recursive' strategy.
file1 | 4 +++-
1 file changed, 3 insertions(+), 1 deletion(-)
$ git reset --hard 71b0f5e
HEAD is now at 71b0f5e copy b1 file1 to common base
$ git checkout b1
Switched to branch 'b1'
$ git merge --no-edit b2
Merge made by the 'recursive' strategy.
file1 | 4 +++-
1 file changed, 3 insertions(+), 1 deletion(-)
$ git checkout master && git reset --hard 40d9565
Switched to branch 'master'
HEAD is now at 40d9565 initial
$ git checkout b1 && git reset --hard f603e15
Switched to branch 'b1'
HEAD is now at f603e15 add file1
$ git checkout b2 && git reset --hard 01ef1ca
Switched to branch 'b2'
HEAD is now at 01ef1ca add file2
$ git show b1:file1 > file1
$ git show b2:file2 > file2
$ git merge-file file1 /dev/null file2