我通常至少有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命令,但是你可以用一个bash行自动化它。

为了用一行安全地更新所有分支,我是这样做的:

git fetch --all && for branch in $(git branch | sed '/*/{$q;h;d};$G' | tr -d '*') ; do git checkout $branch && git merge --ff-only || break ; done

如果它不能快进一个分支或遇到错误,它将停止并将您留在该分支中,以便您可以收回控制权并手动合并。 如果所有分支都可以快进,它将以您当前所在的分支结束,使您停留在更新之前的位置。

解释:

为了更好的可读性,可以将它分成几行:

git fetch --all && \
for branch in $(git branch | sed '/*/{$q;h;d};$G' | tr -d '*')
    do git checkout $branch && \
    git merge --ff-only || break
done

git fetch --all && ... => Fetches all refs from all remotes and continue with the next command if there has been no error. git branch | sed '/*/{$q;h;d};$G' | tr -d '*' => From the output of git branch, sed take the line with a * and move it to the end (so that the current branch will be updated last). Then tr simply remove the *. for branch in $(...) ; do git checkout $branch && git merge --ff-only || break ; done = > For each branch name obtained from the previous command, checkout this branch and try to merge with a fast-forward. If it fails, break is called and the command stops here.

当然,如果你想要的话,你可以用git rebase替换git merge——ff-only。

最后,你可以把它作为一个别名放在bashrc中:

alias git-pull-all='git fetch --all && for branch in $(git branch | sed '\''/*/{$q;h;d};$G'\'' | tr -d "*") ; do git checkout $branch && git merge --ff-only || break ; done'

或者如果你害怕混淆' and ',或者你只是喜欢在编辑器中保持语法的可读性,你可以将它声明为一个函数:

git-pull-all()
{
    git fetch --all && for branch in $(git branch | sed '/*/{$q;h;d};$G' | tr -d '*') ; do git checkout $branch && git merge --ff-only || break ; done
}

奖金:

对于那些想要sed '/*/{$q;h;d};$G'部分的解释:

/*/ =>查找带*的行。 {$q =>如果它在最后一行,退出(我们不需要做任何事情,因为当前分支已经是列表中的最后一个)。 d} =>否则,将该行保存在保持缓冲区中,并将其删除在当前列表位置。 $G =>当它到达最后一行时,追加保持缓冲区的内容。

其他回答

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

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

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

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

似乎很多人都提供了类似的解决方案,但我想分享一下我的想法,并邀请其他人来贡献。这个解决方案有一个漂亮的彩色输出,优雅地处理您当前的工作目录,并且速度很快,因为它不做任何检出,并巧妙地保留您的工作目录。此外,它只是一个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

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

自动化并不难:

#!/bin/sh
# Usage: fetchall.sh branch ...

set -x
git fetch --all
for branch in "$@"; do
    git checkout "$branch"      || exit 1
    git rebase "origin/$branch" || exit 1
done

如果你在Windows上,你可以使用PyGitUp,它是Python的一个克隆版本。您可以使用pip和pip install -user git-up安装它,或者通过Scoop使用Scoop install git-up安装它

[

这里有很多可以接受的答案,但对于外行来说,有些管道可能有点不透明。下面是一个可以轻松定制的简单示例:

$ cat ~/bin/git/git-update-all
#!/bin/bash
# Update all local branches, checking out each branch in succession.
# Eventually returns to the original branch. Use "-n" for dry-run.
git_update_all() {
  local run br
  br=$(git name-rev --name-only HEAD 2>/dev/null)
  [ "$1" = "-n" ] && shift && run=echo

  for x in $( git branch | cut -c3- ) ; do
     $run git checkout $x && $run git pull --ff-only || return 2
  done

  [ ${#br} -gt 0 ] && $run git checkout "$br"
}

git_update_all "$@"

如果你添加~/bin/git到你的PATH(假设文件是~/bin/git/git-update-all),你可以运行:

$ git update-all