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

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


当前回答

将此脚本添加到Mac OS X的.profile中:

# Usage:
#   `git-pull-all` to pull all your local branches from origin
#   `git-pull-all remote` to pull all your local branches from a named remote

function git-pull-all() {
    START=$(git symbolic-ref --short -q HEAD);
    for branch in $(git branch | sed 's/^.//'); do
        git checkout $branch;
        git pull ${1:-origin} $branch || break;
    done;
    git checkout $START;
};

function git-push-all() {
    git push --all ${1:-origin};
};

其他回答

这个问题(目前)还没有解决,至少在没有脚本的情况下不容易解决:参见Junio C Hamano在git邮件列表上发布的这篇文章,解释了这种情况并提供了一个简单的解决方案。

主要的理由是你不需要这个:

With git that is not ancient (i.e. v1.5.0 or newer), there is no reason to have local "dev" that purely track the remote anymore. If you only want to go-look-and-see, you can check out the remote tracking branch directly on a detached HEAD with "git checkout origin/dev". Which means that the only cases we need to make it convenient for users are to handle these local branches that "track" remote ones when you do have local changes, or when you plan to have some. If you do have local changes on "dev" that is marked to track the remove "dev", and if you are on a branch different from "dev", then we should not do anything after "git fetch" updates the remote tracking "dev". It won't fast forward anyway

解决方案需要一个选项或外部脚本,以修剪当前远程跟踪分支的本地分支,而不是像最初的海报所要求的那样,通过快进来保持它们的最新状态。

那么,“git branch -prune -remote=<upstream>”如何呢 本地分支,如果 (1)不是目前的分支机构;而且 (2)标记为从<上游>取的某个分支;而且 (三)自身无过错; 然后把那根树枝去掉?“git remote——prune-local-forks <upstream>”是 还好;我不关心哪个命令实现了这个特性 多。

注意:从git 2.10开始就没有这样的解决方案了。注意,git remote prune子命令和git fetch——prune是关于删除不再存在于远程上的分支的远程跟踪分支,而不是关于删除跟踪远程跟踪分支的本地分支(其中远程跟踪分支是上游分支)。

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

$ 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

我知道这个问题已经提了将近3年了,但我也问过自己同样的问题,但没有找到任何现成的解决方案。所以,我自己创建了一个自定义的git命令shell脚本。

在这里,git-ffwd-update脚本执行以下操作…

it issues a git remote update to fetch the lates revs then uses git remote show to get a list of local branches that track a remote branch (e.g. branches that can be used with git pull) then it checks with git rev-list --count <REMOTE_BRANCH>..<LOCAL_BRANCH> how many commit the local branch is behind the remote (and ahead vice versa) if the local branch is 1 or more commits ahead, it can NOT be fast-forwarded and needs to be merged or rebased by hand if the local branch is 0 commits ahead and 1 or more commits behind, it can be fast-forwarded by git branch -f <LOCAL_BRANCH> -t <REMOTE_BRANCH>

脚本可以这样调用:

$ git ffwd-update
Fetching origin
 branch bigcouch was 10 commit(s) behind of origin/bigcouch. resetting local branch to remote
 branch develop was 3 commit(s) behind of origin/develop. resetting local branch to remote
 branch master is 6 commit(s) behind and 1 commit(s) ahead of origin/master. could not be fast-forwarded

完整的脚本应该保存为git-ffwd-update,并且需要在PATH上。

#!/bin/bash

main() {
  REMOTES="$@";
  if [ -z "$REMOTES" ]; then
    REMOTES=$(git remote);
  fi
  REMOTES=$(echo "$REMOTES" | xargs -n1 echo)
  CLB=$(git rev-parse --abbrev-ref HEAD);
  echo "$REMOTES" | while read REMOTE; do
    git remote update $REMOTE
    git remote show $REMOTE -n \
    | awk '/merges with remote/{print $5" "$1}' \
    | while read RB LB; do
      ARB="refs/remotes/$REMOTE/$RB";
      ALB="refs/heads/$LB";
      NBEHIND=$(( $(git rev-list --count $ALB..$ARB 2>/dev/null) +0));
      NAHEAD=$(( $(git rev-list --count $ARB..$ALB 2>/dev/null) +0));
      if [ "$NBEHIND" -gt 0 ]; then
        if [ "$NAHEAD" -gt 0 ]; then
          echo " branch $LB is $NBEHIND commit(s) behind and $NAHEAD commit(s) ahead of $REMOTE/$RB. could not be fast-forwarded";
        elif [ "$LB" = "$CLB" ]; then
          echo " branch $LB was $NBEHIND commit(s) behind of $REMOTE/$RB. fast-forward merge";
          git merge -q $ARB;
        else
          echo " branch $LB was $NBEHIND commit(s) behind of $REMOTE/$RB. resetting local branch to remote";
          git branch -f $LB -t $ARB >/dev/null;
        fi
      fi
    done
  done
}

main $@

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

通过运行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

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

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