我正在一个新项目中使用Git,该项目有两个并行但目前处于试验阶段的开发分支:
master:导入现有的代码库,再加上一些我通常确信的修改exp1:实验分支#1exp2:实验分支#2
exp1和exp2表示两种非常不同的体系结构方法。在我进一步相处之前,我无法知道哪一个(如果有的话)会起作用。当我在一个分支中取得进展时,我有时会对另一个分支进行有用的编辑,并希望仅合并这些编辑。
将一个开发分支中的选择性更改合并到另一个分支中,同时保留其他所有内容的最佳方法是什么?
我考虑过的方法:
gitmerge——无需提交,然后手动取消大量编辑,我不想在分支之间共享这些编辑。手动将通用文件复制到临时目录中,然后git checkout移动到另一个分支,然后更多地手动将临时目录复制到工作树中。在上述基础上的变化。暂时放弃exp分支,使用另外两个本地存储库进行实验。这使得手动复制文件更加简单。
所有这三种方法都显得乏味且容易出错。我希望有更好的方法;类似于过滤器路径参数,可以使gitmerge更有选择性。
我编写了自己的脚本“pmerge”来部分合并目录。这是一项正在进行的工作,我仍然在学习Git和Bash脚本。
该命令使用gitmerge--no提交,然后取消应用与提供的路径不匹配的更改。
用法:git pmerge分支路径示例:gitmerge-devel-src/
我还没有对它进行广泛的测试。工作目录应该没有任何未提交的更改和未跟踪的文件。
#!/bin/bash
E_BADARGS=65
if [ $# -ne 2 ]
then
echo "Usage: `basename $0` branch path"
exit $E_BADARGS
fi
git merge $1 --no-commit
IFS=$'\n'
# List of changes due to merge | replace nulls with newlines | strip lines to just filenames | ensure lines are unique
for f in $(git status --porcelain -z -uno | tr '\000' '\n' | sed -e 's/^[[:graph:]][[:space:]]\{1,\}//' | uniq); do
[[ $f == $2* ]] && continue
if git reset $f >/dev/null 2>&1; then
# Reset failed... file was previously unversioned
echo Deleting $f
rm $f
else
echo Reverting $f
git checkout -- $f >/dev/null 2>&1
fi
done
unset IFS
以下是如何让历史记录只跟踪来自另一个分支的几个文件,而不必大惊小怪,即使更“简单”的合并会带来更多您不希望的更改。
首先,您将采取不同寻常的步骤,提前声明您要提交的是合并,而Git根本不需要对工作目录中的文件执行任何操作:
git merge --no-ff --no-commit -s ours branchname1
…其中“branchname”是您声称要合并的任何内容。如果你马上提交,它不会做任何更改,但它仍然会显示来自其他分支的祖先。如果需要,也可以向命令行添加更多分支、标记等。不过,此时没有需要提交的更改,所以接下来从其他版本获取文件。
git checkout branchname1 -- file1 file2 etc.
如果要从多个其他分支合并,请根据需要重复。
git checkout branchname2 -- file3 file4 etc.
现在,来自另一个分支的文件位于索引中,准备提交,并具有历史记录。
git commit
在提交消息中,您需要做很多解释。
不过,请注意,如果不清楚的话,这是一件糟糕的事情。这不符合“树枝”的精神,而樱桃采摘是一种更诚实的方式来完成你将要做的事情。如果您想对上次未带来的同一分支上的其他文件进行另一次“合并”,它将以“已更新”消息阻止您。这是一种当我们应该分支时没有分支的症状,因为“from”分支应该是多个不同的分支。
虽然其中一些答案很好,但我觉得没有人真正回答了OP的原始约束:从特定分支中选择特定文件。这个解决方案可以做到这一点,但如果有很多文件,可能会很乏味。
假设您有master、exp1和exp2分支。您希望将每个实验分支中的一个文件合并到master中。我会这样做:
git checkout master
git checkout exp1 path/to/file_a
git checkout exp2 path/to/file_b
# Save these files as a stash
git stash
# Merge stash with master
git merge stash
这将为您提供所需的每个文件的文件差异。没什么了。一点也不差。在不同版本之间进行完全不同的文件更改非常有用——在我的例子中,将应用程序从RubyonRails 2更改为RubyonRails 3。
这将合并文件,但它会进行智能合并。我无法弄清楚如何使用此方法获取文件差异信息(也许对于极端的差异,它仍然会这样做。除非使用-s递归-X忽略所有空格选项,否则像空格这样的恼人的小东西会被合并回来)