我通常至少有3个远程分支:master、staging和production。我有3个本地分支来跟踪这些远程分支。
更新我所有的本地分支是乏味的:
git fetch --all
git rebase origin/master
git checkout staging
git rebase origin/staging
git checkout production
git rebase origin/production
我很想做一个“git pull -all”,但我还没能让它工作。它似乎做了一个“fetch -all”,然后更新(快进或合并)当前工作的分支,但不包括其他本地分支。
我仍然需要手动切换到每个本地分支并进行更新。
如果可能,以下一行代码将快速前进所有具有上游分支的分支,否则打印错误:
git branch \
--format "%(if)%(upstream:short)%(then)git push . %(upstream:short):%(refname:short)%(end)" |
sh
它是如何工作的?
它使用git分支命令的自定义格式。对于每个具有上游分支的分支,它打印一行具有以下模式的代码:
git push . <remote-ref>:<branch>
这可以直接通过管道传输到sh(假设分支名称是格式良好的)。忽略| sh,看看它在做什么。
警告
单行程序不会联系你的遥控器。在运行它之前,发出git fetch或git fetch。
当前签出的分支将不会用类似于
! [remote rejected] origin/master -> master (branch is currently checked out)
为此,您可以求助于常规的git pull -ff-only。
别名
将以下内容添加到你的.gitconfig中,以便git fft执行此命令:
[alias]
fft = !sh -c 'git branch --format \"%(if)%(upstream:short)%(then)git push . %(upstream:short):%(refname:short)%(end)\" | sh' -
参见my .gitconfig。别名是“快进跟踪(分支)”的缩写。
如果refs/heads/master可以快进到refs/remotes/foo/master,则
git merge-base refs/heads/master refs/remotes/foo/master
应该返回refs/heads/master指向的SHA1 id。这样,您就可以将一个脚本组合在一起,自动更新没有应用转移提交的所有本地分支。
这个小shell脚本(我称之为git-can-ff)说明了如何做到这一点。
#!/bin/sh
set -x
usage() {
echo "usage: $(basename $0) <from-ref> <to-ref>" >&2
exit 2
}
[ $# -ne 2 ] && usage
FROM_REF=$1
TO_REF=$2
FROM_HASH=$(git show-ref --hash $FROM_REF)
TO_HASH=$(git show-ref --hash $TO_REF)
BASE_HASH=$(git merge-base $FROM_REF $TO_REF)
if [ "$BASE_HASH" = "$FROM_HASH" -o \
"$BASE_HASH" = "$FROM_REF" ]; then
exit 0
else
exit 1
fi
这里有很多答案,但没有一个是使用git-fetch直接更新本地ref,这比检查分支简单得多,也比git-update-ref更安全。
这里我们使用git-fetch来更新非当前分支,而git pull——ff-only用于当前分支。它:
不需要检查分支机构
仅在可以快进的情况下更新分支
当它不能快进时会报告吗
就是这样:
#!/bin/bash
currentbranchref="$(git symbolic-ref HEAD 2>&-)"
git branch -r | grep -v ' -> ' | while read remotebranch
do
# Split <remote>/<branch> into remote and branchref parts
remote="${remotebranch%%/*}"
branchref="refs/heads/${remotebranch#*/}"
if [ "$branchref" == "$currentbranchref" ]
then
echo "Updating current branch $branchref from $remote..."
git pull --ff-only
else
echo "Updating non-current ref $branchref from $remote..."
git fetch "$remote" "$branchref:$branchref"
fi
done
从git-fetch的manpage:
<refspec>
The format of a <refspec> parameter is an optional plus +, followed by the source ref <src>,
followed by a colon :, followed by the destination ref <dst>.
The remote ref that matches <src> is fetched, and if <dst> is not empty string, the local ref
that matches it is fast-forwarded using <src>. If the optional plus + is used, the local ref is
updated even if it does not result in a fast-forward update.
通过指定git fetch <remote> <ref>:<ref>(没有任何+),我们得到一个只在本地ref可以快进时更新它的fetch。
注意,这假设本地分支和远程分支的名称相同(并且您希望跟踪所有分支),它实际上应该使用关于您拥有哪些本地分支以及它们被设置为跟踪的内容的信息。