子模块移动后合并冲突

时间:2018-07-10 17:30:35

标签: git

在开发分支中移动子模块后,每次我从master分支合并更改时都会遇到合并冲突。要解决,我必须git add mysubmodule。我如何才能避免每次合并后解决此冲突?

以下是说明问题的脚本:

cd ~/src
git init MyProduct
git init MySubmodule
cd MySubmodule
echo "foo" > foo.txt
git add foo.txt
git commit -m "Add foo.txt"
cd ../MyProduct
echo "bar" > bar.txt
git add bar.txt
git commit -m "Add bar.txt"
git submodule add ../MySubmodule
git commit -m "Add MySubmodule"
git branch development
git checkout development
git mv MySubmodule OurSubmodule
git commit -m "Move MySubmodule to OurSubmodule."
git checkout master
echo "barbar" > bar.txt
git commit -am"Update bar.txt"
git checkout development
git merge master
git add OurSubmodule
git commit -am"Resolve conflict"

我在合并中收到的合并冲突消息是:

Auto-merging OurSubmodule
Adding as OurSubmodule~HEAD instead
Automatic merge failed; fix conflicts and then commit the result.

2 个答案:

答案 0 :(得分:1)

问题是由于在合并之前运行了git submodule update,但我不确定为什么。如果OurSubmodule为空,则合并正常。但是,如果OurSubmodule包含git repo,合并将失败。

$ git submodule update
Submodule path 'OurSubmodule': checked out 'fc7d6244ff60b52884da1e562edbc9059f758494'

$ git status
On branch development
nothing to commit, working tree clean

$ git merge master
Auto-merging OurSubmodule
Adding as OurSubmodule~HEAD instead
Automatic merge failed; fix conflicts and then commit the result.

$ git status
On branch development
You have unmerged paths.
  (fix conflicts and run "git commit")
  (use "git merge --abort" to abort the merge)

Changes to be committed:

    modified:   bar.txt

Unmerged paths:
  (use "git add <file>..." to mark resolution)

    added by us:     OurSubmodule

Adding as OurSubmodule~HEAD instead表示git merge无法注意到重命名。不记录Git中的重命名,Git查看内容的相似程度。我猜这是git merge的带有子模块的重命名检测中的某些错误或失败。

如果您git add OurSubmodule一切都很好。

$ git add OurSubmodule/
$ git status
On branch development
All conflicts fixed but you are still merging.
  (use "git commit" to conclude merge)

Changes to be committed:

    modified:   bar.txt

如果您随后将开发合并到主版本中,一切都会很好。

由于重命名子模块非常罕见,除非您想深入了解Git的内胆,我建议您解决冲突并继续进行。 Git的自动合并功能非常好,但是有时会发生冲突。


关于子模块的注释。子模块通常比其价值更大。如果您的代码依赖于其他存储库,请考虑改用软件包管理器。最好是可以直接从Git存储库中拉出的存储卡。

即使正确使用,更改代码和子模块以使其匹配的简便性也鼓励将应该分开的项目紧密地绑定在一起。将它们分开放置在必须单独处理并分别构建的程序包中,即使只花一分钟,也可以鼓励项目之间的良好界限。

答案 1 :(得分:0)

我没有弄清楚为什么git merge无法正确检测到子模块的重命名,而是通过编写脚本在维护和开发分支中分别删除和重新添加子模块的方法来解决此问题:

#!/bin/bash -ex

# -e: Exit on error
# -x: Print commands as they are executed

# move_submodule: Move a submodule in a development branch while keeping
# it in the same location in a maintenance branch.  If git mv is used to
# move the submodule instead, there will be a merge conflict every time
# changes are merged up to the development branch from the maintenance
# branch.  This script works by deleting the submodule and then readding
# it separately in both branches.  If git mv has already been attempted,
# the moved submodule is also deleted.

if [ $# -ne 5 ]; then
    echo $0: usage: $0 maintenance_branch development_branch submodule_url old_path new_path
    exit 1
fi

maintenance=$1
development=$2
submodule_url=$3
old_path=$4
new_path=$5

repository=`git rev-parse --show-toplevel`
cd $repository

# Get branches ready
git checkout $maintenance
git pull
git checkout $development
git pull
git submodule update --init --recursive
git merge $maintenance --no-edit
git push

# Delete submodule in $development if you already moved it with git mv.
if [ -d "$new_path" ]; then
    git rm $new_path
    git commit -m"Remove $new_path temporarily to resolve conflict with $maintenance."
    git push
fi

# Delete submodule in $maintenance and merge up.
git checkout $maintenance
git submodule update --init --recursive
git rm $old_path
git commit -m"Remove $old_path temporarily to resolve conflict with $development."
git push
git checkout $development
git submodule update --init --recursive
git merge $maintenance --no-edit
git push

# Re-add submodule in new location in $development.
git submodule add --force $submodule_url $new_path
git commit -m"Re-add $new_path"
git push

# Re-add submodule in original location in $maintenance.
git checkout $maintenance
rm -rf $new_path
git submodule update --init --recursive
git submodule add --force $submodule_url $old_path
git commit -m"Re-add $old_path."
git push

# Merge up, discarding maintenance submodule change.
git checkout $development
rm -rf $old_path
git submodule update --init --recursive
git merge $maintenance --no-edit -s ours
git push