我通常至少有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”,然后更新(快进或合并)当前工作的分支,但不包括其他本地分支。

我仍然需要手动切换到每个本地分支并进行更新。


当前回答

自动化并不难:

#!/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

其他回答

这里有一个很好的答案:如何获取所有git分支

for remote in `git branch -r`; do git branch --track $remote; done
git pull --all

不知道这是否可以,但如果我想快进多个分支,我通常会调用

git pull origin master staging production

如果我想推送多个分支,我会调用

git push origin master staging production

但只有当所有提到的分支都不需要任何形式的合并时,两者才有效。

以上答案都没有考虑存在多个工作树的可能性。使用git update-ref或git branch -f更新当前在其他工作树中签出的分支会产生意想不到的副作用。

考虑一下我处理工作树的解决方案:

#! /usr/bin/env bash
set -euo pipefail

# Read the default remote from config, defaulting to "origin".
DEFAULT_REMOTE=$(git config --default origin --get clone.defaultRemoteName)

# Use first argument as remote name, fallback to default.
REMOTE=${1:-$DEFAULT_REMOTE}

# Resolve the rev that HEAD points at, so that we can give it
# a special treatment.
HEAD_REV=$(git rev-parse HEAD)

# Format that allows us to easily grep for local branches that are behind,
# and have an upstream at $REMOTE.
FORMAT="%(upstream:trackshort)%(upstream:remotename)|%(refname:short)"

# Get a list of revs that are checked out. We don't want to
# update refs that are pointing at them.
set +e
WORKTREE_REVS=$(git worktree list --porcelain | grep -Po "HEAD \K(.+)" | grep -v "$HEAD_REV")
set -e

git fetch $REMOTE

for BRANCH in $(git for-each-ref refs/heads --format="$FORMAT" | grep -Po "<$REMOTE\|\K(.+)")
do
    BRANCH_REV=$(git rev-parse $BRANCH)
    if [ "$BRANCH_REV" = "$HEAD_REV" ]
    then
        # This branch is currently checked out "here". Forward it carefully.
        set +e
        git merge --no-autostash --ff-only $BRANCH@{u}
        set -e
    elif grep -q "$BRANCH_REV" <<< "$WORKTREE_REVS"
    then
        # This branch is currently checked out by another. Leave it alone.
        echo "$BRANCH skipped, because it is checked out in another worktree. Use 'git worktree list' to diagnose."
    else
        # This branch is not checked out. Just update it!
        git update-ref refs/heads/$BRANCH $BRANCH@{u}
        echo "$BRANCH forwarded"
        fi
done

我为我的giitbash写的脚本。完成以下任务:

默认情况下,为跟踪原点而设置的所有分支从原点提取,允许您根据需要指定不同的远程。 如果您的当前分支处于脏状态,那么它将存储您的更改,并在结束时尝试恢复这些更改。 对于每个用于跟踪远程分支的本地分支,将: Git结帐分支 Git拉源 最后,将您返回到原始分支并恢复状态。

**我使用这个,但没有彻底测试,使用自负风险。在.bash_alias文件中可以看到该脚本的示例。

    # Do a pull on all branches that are tracking a remote branches, will from origin by default.
    # If current branch is dirty, will stash changes and reply after pull.
    # Usage: pullall [remoteName]
    alias pullall=pullAll
    function pullAll (){
     # if -h then show help
     if [[ $1 == '-h' ]]
    then
      echo "Description: Pulls new changes from upstream on all branches that are tracking remotes."
      echo 
      echo "Usage: "
      echo "- Default: pullall"
      echo "- Specify upstream to pull from: pullall [upstreamName]"
      echo "- Help: pull-all -h"
    else

     # default remote to origin
     remote="origin"
     if [ $1 != "" ]
     then
       remote=$1
     fi

     # list all branches that are tracking remote
     # git branch -vv : list branches with their upstreams
     # grep origin : keep only items that have upstream of origin
     # sed "s/^.."... : remove leading *
     # sed "s/^"..... : remove leading white spaces
     # cut -d" "..... : cut on spaces, take first item
     # cut -d splits on space, -f1 grabs first item
     branches=($(git branch -vv | grep $remote | sed "s/^[ *]*//" | sed "s/^[ /t]*//" | cut -d" " -f1))

     # get starting branch name
     startingBranch=$(git rev-parse --abbrev-ref HEAD)

     # get starting stash size
     startingStashSize=$(git stash list | wc -l)

     echo "Saving starting branch state: $startingBranch"
     git stash

     # get the new stash size
     newStashSize=$(git stash list | wc -l)

     # for each branch in the array of remote tracking branches
     for branch in ${branches[*]}
     do
       echo "Switching to $branch"
       git checkout $branch

       echo "Pulling $remote"
       git pull $remote

     done

     echo "Switching back to $startingBranch"
     git checkout $startingBranch

     # compare before and after stash size to see if anything was stashed
     if [ "$startingStashSize" -lt "$newStashSize" ]
     then
       echo "Restoring branch state"
       git stash pop
     fi
    fi
    }

“git pull -all”可以更新我所有的本地分支吗?

不,它不能。对于快进,我只是编写了一个小工具。https://github.com/changyuheng/git-fast-forward-all

该工具的优点:

在一个存储库中支持多个远程。(集线器同步目前不支持多个遥控器。) 支持在本地分支和相应的远程跟踪分支上使用不同的名称。 比其他获取每个分支的远程脚本快得多。 没有容易出错的正则表达式解析/编辑。