我在一个有两个分支 A 和 B 的项目上工作。我通常在分支 A 上工作,并合并来自分支 B 的内容。对于合并,我通常会这样做:
git merge origin/branchB
但是,我也想保留分支 B 的本地副本,因为有时我可能会在不先与我的分支 A 合并的情况下签出该分支。为此,我将执行以下操作:
git checkout branchB
git pull
git checkout branchA
有没有一种方法可以在一个命令中完成上述操作,而不必来回切换分支?我应该git update-ref
吗?如何?
只要您要进行快速合并,就可以简单地使用
git fetch <remote> <sourceBranch>:<destinationBranch>
例子:
# Merge local branch foo into local branch master,
# without having to checkout master first.
# Here `.` means to use the local repository as the "remote":
git fetch . foo:master
# Merge remote branch origin/foo into local branch foo,
# without having to checkout foo first:
git fetch origin foo:foo
虽然Amber 的答案在快进情况下也可以使用,但是git fetch
相比强制移动分支引用要安全一些,因为git fetch
就会自动防止意外的非快进。请在 refspec 中+
您不能将分支 B 合并到分支 A 中,除非先签出 A,否则将导致非快进合并。这是因为需要工作副本来解决任何潜在的冲突。
但是,在快速合并的情况下,这是可能的,因为按照定义,此类合并永远不会导致冲突。要做到这一点而无需先签出分支,可以将git fetch
与 refspec 一起使用。
如果您签出了feature
这是一个更新master
(禁止非快速更改)的示例:
git fetch upstream master:master
这种用例非常普遍,以至于您可能想要在 git 配置文件中为其命名一个别名,如下所示:
[alias]
sync = !sh -c 'git checkout --quiet HEAD; git fetch upstream master:master; git checkout --quiet -'
此别名的作用如下:
git checkout HEAD
:这会使您的工作副本进入分离状态。如果您想在检出master
我认为有必要这样做,因为否则master
的分支引用不会移动,但是我不记得这是否真的很重要。
git fetch upstream master:master
:这会将您的本地master
upstream/master
相同的位置。
git checkout -
出您先前签出的分支( -
就是这样做的)。
git fetch
用于(非)快进合并的语法如果您希望fetch
命令在更新不是非快进的情况下失败,那么您只需使用以下形式的 refspec 即可:
git fetch <remote> <remoteBranch>:<localBranch>
如果要允许非快进更新,则在 refspec 的前面+
git fetch <remote> +<remoteBranch>:<localBranch>
请注意,您可以使用将本地仓库作为 “远程” 参数传递.
:
git fetch . <sourceBranch>:<destinationBranch>
从解释此语法git fetch
文档中(重点是我的):
<refspec>
<refspec>
参数的格式是可选的 plus+
,其后是源 ref<src>
,后跟冒号:
,然后是目标 ref<dst>
。获取
<src>
匹配的远程 ref,<dst>
<src>
快速转发与之匹配的本地 ref 。如果使用了可选的加号+
,则即使不导致快速更新也将更新本地引用。
不,那里没有。为了使您能够解决冲突,必须对目标分支进行检出(如果 Git 无法自动合并它们)。
但是,如果合并是快速进行的合并,则无需签出目标分支,因为您实际上不需要合并任何内容 - 您要做的就是更新分支以指向目标分支。新头号git branch -f
来做到这一点:
git branch -f branch-b branch-a
将更新branch-b
以点的头部branch-a
。
-f
选项代表--force
,这意味着使用它时必须小心。
除非您完全确定合并将是快速进行的,否则请不要使用它。
正如 Amber 所说,快进合并是您可以想到的唯一情况。可以想象,任何其他合并都需要经历整个三方合并,应用补丁程序,解决冲突问题 - 这意味着需要周围有文件。
我恰好有一个脚本可以用于此目的:进行快速合并而不会触及工作树(除非您要合并到 HEAD 中)。这有点长,因为它至少有点健壮 - 它检查以确保合并将是快进的,然后在不检出分支的情况下执行合并,但产生的结果与您所拥有的相同 - 您会看到diff --stat
更改摘要,并且 reflog 中的条目完全类似于快速向前合并,而不是使用branch -f
获得的 “重置”。如果将其命名为git-merge-ff
并将其放在 bin 目录中,则可以将其称为 git 命令: git merge-ff
。
#!/bin/bash
_usage() {
echo "Usage: git merge-ff <branch> <committish-to-merge>" 1>&2
exit 1
}
_merge_ff() {
branch="$1"
commit="$2"
branch_orig_hash="$(git show-ref -s --verify refs/heads/$branch 2> /dev/null)"
if [ $? -ne 0 ]; then
echo "Error: unknown branch $branch" 1>&2
_usage
fi
commit_orig_hash="$(git rev-parse --verify $commit 2> /dev/null)"
if [ $? -ne 0 ]; then
echo "Error: unknown revision $commit" 1>&2
_usage
fi
if [ "$(git symbolic-ref HEAD)" = "refs/heads/$branch" ]; then
git merge $quiet --ff-only "$commit"
else
if [ "$(git merge-base $branch_orig_hash $commit_orig_hash)" != "$branch_orig_hash" ]; then
echo "Error: merging $commit into $branch would not be a fast-forward" 1>&2
exit 1
fi
echo "Updating ${branch_orig_hash:0:7}..${commit_orig_hash:0:7}"
if git update-ref -m "merge $commit: Fast forward" "refs/heads/$branch" "$commit_orig_hash" "$branch_orig_hash"; then
if [ -z $quiet ]; then
echo "Fast forward"
git diff --stat "$branch@{1}" "$branch"
fi
else
echo "Error: fast forward using update-ref failed" 1>&2
fi
fi
}
while getopts "q" opt; do
case $opt in
q ) quiet="-q";;
* ) ;;
esac
done
shift $((OPTIND-1))
case $# in
2 ) _merge_ff "$1" "$2";;
* ) _usage
esac
PS:如果有人看到该脚本有任何问题,请发表评论!这项工作是一劳永逸的,但我很乐意加以改进。