我通常至少有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-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。

注意,这假设本地分支和远程分支的名称相同(并且您希望跟踪所有分支),它实际上应该使用关于您拥有哪些本地分支以及它们被设置为跟踪的内容的信息。

其他回答

似乎很多人都提供了类似的解决方案,但我想分享一下我的想法,并邀请其他人来贡献。这个解决方案有一个漂亮的彩色输出,优雅地处理您当前的工作目录,并且速度很快,因为它不做任何检出,并巧妙地保留您的工作目录。此外,它只是一个shell脚本,除了git之外没有其他依赖项。(目前只在OSX上测试过)

#!/usr/bin/env bash

gitup(){    
RED='\033[33;31m'
YELLO='\033[33;33m'
GREEN='\033[33;32m'
NC='\033[0m' # No Color

HEAD=$(git rev-parse HEAD)
CHANGED=$(git status --porcelain | wc -l)

echo "Fetching..."
git fetch --all --prune &>/dev/null
for branch in `git for-each-ref --format='%(refname:short)' refs/heads`; do

    LOCAL=$(git rev-parse --quiet --verify $branch)
    if [ "$HEAD" = "$LOCAL" ] && [ $CHANGED -gt 0 ]; then
        echo -e "${YELLO}WORKING${NC}\t\t$branch"
    elif git rev-parse --verify --quiet $branch@{u}&>/dev/null; then
        REMOTE=$(git rev-parse --quiet --verify $branch@{u})
        BASE=$(git merge-base $branch $branch@{u})

        if [ "$LOCAL" = "$REMOTE" ]; then
           echo -e "${GREEN}OK${NC}\t\t$branch" 
        elif [ "$LOCAL" = "$BASE" ]; then
            if [ "$HEAD" = "$LOCAL" ]; then
                git merge $REMOTE&>/dev/null
            else
                git branch -f $branch $REMOTE
            fi
            echo -e "${GREEN}UPDATED${NC}\t\t$branch"
        elif [ "$REMOTE" = "$BASE" ]; then
            echo -e "${RED}AHEAD${NC}\t\t$branch"
        else
            echo -e "${RED}DIVERGED${NC}\t\t$branch"
        fi
    else
        echo -e "${RED}NO REMOTE${NC}\t$branch"
    fi
done
}

https://github.com/davestimpert/gitup

对不起,我似乎也想出了与上面其他工具相同的名字。

一个略有不同的脚本,它只快进与上游分支名称匹配的分支。如果可以快进,它还会更新当前分支。

通过运行git branch -vv,确保所有分支的上游分支都被正确设置。使用git branch -u origin/yourbanchname设置上游分支

复制粘贴到一个文件并chmod 755:

#!/bin/sh

curbranch=$(git rev-parse --abbrev-ref HEAD)

for branch in $(git for-each-ref refs/heads --format="%(refname:short)"); do
        upbranch=$(git config --get branch.$branch.merge | sed 's:refs/heads/::');
        if [ "$branch" = "$upbranch" ]; then
                if [ "$branch" = "$curbranch" ]; then
                        echo Fast forwarding current branch $curbranch
                        git merge --ff-only origin/$upbranch
                else
                        echo Fast forwarding $branch with origin/$upbranch
                        git fetch . origin/$upbranch:$branch
                fi
        fi
done;

这仍然不是自动的,因为我希望有一个选项-应该有一些检查,以确保这只能发生在快进更新(这就是为什么手动做拉更安全!!),但注意事项:

git fetch origin
git update-ref refs/heads/other-branch origin/other-branch

更新本地分支的位置,而无需签出。

注意:你将丢失你当前的分支位置,并将其移动到原点的分支所在的位置,这意味着如果你需要合并,你将丢失数据!

如果可能,以下一行代码将快速前进所有具有上游分支的分支,否则打印错误:

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。别名是“快进跟踪(分支)”的缩写。

我使用hub的sync子命令来实现自动化。我在我的.bash_profile中有别名git=hub,所以我键入的命令是:

git sync

这将更新具有匹配上游分支的所有本地分支。从手册页:

如果本地分支已经过时,快进; 如果本地分支包含未推送的工作,请对此发出警告; 如果分支显示为已合并,且上游分支已被删除,则删除该分支。

它还处理在当前分支上存储/解存储未提交的更改。

我曾经使用过一个类似的工具,叫做git-up,但它不再被维护,git sync几乎做了完全相同的事情。