Git子树合并在合并简单的上游更改时报告冲突

4
我开始学习git 1.8.2中的子树合并。我创建了一个简单的示例来测试将第三方repo迁移到主项目中的更改。
我正在遵循6.7 Git工具-子树合并的示例。
'sub'项目包含在'main'项目的子目录中。
在对'sub'项目进行更改后,当我尝试将更改合并到'main'项目中时,git报告冲突。
测试摘要:
1. 创建项目'main'和'sub'的repos(用'sub'代替rack)。 2. 添加名为sub_remote的远程到main,指向sub。 3. 使用sub_branch跟踪sub_remote。 4. 更改并提交'sub'项目中的一行文件。 5. 将更改从sub拉到main/sub_branch。 6. 将main/sub_branch合并到main/master。
合并失败并出现冲突。合并程序不确定要保留哪个版本的更改行。
<<<<<<< HEAD
main
=======
main upstream change
>>>>>>> sub_branch
main.git
sub
sub.git
tm

完整的测试脚本

#!/bin/sh

# initialize empty repos
for i in main sub
do
  rm -rf $i{,.git}
  mkdir $i.git
  cd $i.git;
  git --bare init;
  cd ..;
  git clone $i.git
  cd $i
  echo $i > readme.md
  git add readme.md
  git commit -a -m "added readme.md"
  git push origin master
  cd ..
done

# add data to sub
ls > sub/data
cd sub
git add data
git commit -m "Added data"
git push origin master
cd ..

# add sub as a sub-tree in main
cd main
git remote add sub_remote ../sub.git
git fetch sub_remote
git checkout -b sub_branch sub_remote/master
git checkout master
git read-tree --prefix=sub/ -u sub_branch
git commit -m "Added sub"
git push origin master
cd ..

# make change to sub
cd sub
sed -i -e 's/main$/main upstream change/' data
git commit -a -m "upstream change made to data"
git push origin master
cd ..

# merge sub change to main
cd main
git checkout sub_branch
git pull

#merge sub_branch changes into master
git checkout master
git merge -s subtree sub_branch
cat sub/data

git-scm书中涵盖子树合并的新页面在这里:https://git-scm.com/book/en/v2/Git-Tools-Advanced-Merging#Other-Types-of-Merges 但是,我认为它仍然存在同样的问题。 - Tim Swast
希望使用 Git 2.19(2018 年第三季度)的相同 git merge -s subtree 命令能够更好地工作。请参见我的下面的答案 - VonC
2个回答

6
在这种情况下,read-tree 的作用只是将另一个树的内容添加到当前树中的一个目录中。这些内容会像创建和添加常规文件和目录一样被添加,没有任何历史记录被保留。所有这些文件都将被视为您创建的文件。
当您尝试合并时,该过程会失败,因为它看到子分支历史记录创建了 data 文件,而目标目录也包含由您创建的不同的 data 文件。
您正在使用的页面缺少使子树正常工作所需的非常重要的步骤,以便您实际上可以拉取更新。
正确的示例可在以下两个页面中看到: https://www.kernel.org/pub/software/scm/git/docs/howto/using-merge-subtree.html https://help.github.com/articles/working-with-subtree-merge 在您的情况下缺失的是在创建子树时正确链接历史记录。
# create the merge record but not change anything in your tree yet
git merge -s ours --no-commit sub_branch
# bring the changes and place them in the proper subdirectory
git read-tree --prefix=sub/ -u sub_branch

之后,您的main仓库将包含sub仓库的历史记录。调用以前失败的合并应该现在可以正常工作了。调用 git log --graph 将让您看到不同的提交是如何合并的。


0
问题在于Git 1.8.2.2(2013年3月)只是引入了一个影响git merge -s subtree的错误版本。
Tim Swast提到的Subtree Merging section仍然存在这个问题,但在Git 2.19(2018年第三季度)中应该能更好地解决。

"git merge -s subtree"中的自动树匹配在5年前就已经出现问题,但直到现在才被修复,而没有人注意到。

查看提交2ec4150(2018年8月2日)由Jeff King (peff)提交。
协助者:René Scharfe (rscharfe)
(由Junio C Hamano -- gitster --合并于提交60858f3,2018年8月17日)

score_trees(): 修复遍历缺失条目的树的问题

score_trees() 中,我们遍历两个排序过的树,以查找这两个树之间缺失或具有不同内容的条目。
因此,如果我们有这些条目的两个树:

one   two
---   ---
a     a
b     c
c     d

我们期望循环执行以下操作:

  • 将 "a" 与 "a" 进行比较
  • 将 "b" 与 "c" 进行比较;由于这些是排序列表,我们知道第二棵树没有 "b"
  • 将 "c" 与 "c" 进行比较
  • 将 "d" 与列表结尾进行比较;我们知道第一棵树没有 "d"

d8febdematch-trees: simplify score_trees() using tree_entry(), 2013-03-24, Git 1.8.2.2)之前,这是有效的。
但是在那次提交之后,即使我们只处理了一侧的条目,我们错误地在每个循环迭代中增加了树指针。
结果,我们会做到这一点:

  • 将 "a" 与 "a" 进行比较
  • 将 "b" 与 "c" 进行比较;我们知道没有 "b",但我们仍然增加了两个树指针;此时我们已经不同步了,所有后续的比较都是错误的
  • 将 "c" 与 "d" 进行比较,并错误地声称第二棵树没有 "c"
  • 退出循环,错误地没有意识到第一棵树没有 "d"

因此,与 d8febde 中的声明相反,我们确实需要手动使用 update_tree_entry(),因为推进树指针取决于条目比较。

这意味着我们必须停止使用 tree_entry() 来访问每个条目,因为它会自动推进指针。
相反:

  • 我们将直接使用 tree_desc.size 来知道是否还有剩余内容要查看(这是 tree_entry() 在幕后执行的操作)
  • 而不是进行额外的结构分配到 "e1" 和 "e2",我们可以直接访问 tree_desc 的 "entry" 字段。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接