我在一个有两个分支 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
esacPS:如果有人看到该脚本有任何问题,请发表评论!这项工作是一劳永逸的,但我很乐意加以改进。