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

for remote in `git branch -r`; do git branch --track $remote; done
git pull --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 \
  --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。别名是“快进跟踪(分支)”的缩写。

从git 2.9开始:

Git pull -rebase -autostash

参见https://git-scm.com/docs/git-rebase

在行动开始前自动创建一个临时藏匿点, 操作结束后再应用。这意味着你可以跑 基于一个肮脏的工作树。然而,小心使用:最后的收藏 应用程序在成功的重基后可能会导致非平凡 冲突。

为了完成Matt Connolly的回答,这是一种更安全的更新本地分支引用的方法,可以快进,而不签出分支。它不会更新不能快进的分支(即已经分离的分支),也不会更新当前签出的分支(因为这样工作副本也应该更新)。

git fetch

head="$(git symbolic-ref HEAD)"
git for-each-ref --format="%(refname) %(upstream)" refs/heads | while read ref up; do
    if [ -n "$up" -a "$ref" != "$head" ]; then
        mine="$(git rev-parse "$ref")"
        theirs="$(git rev-parse "$up")"
        base="$(git merge-base "$ref" "$up")"
        if [ "$mine" != "$theirs" -a "$mine" == "$base" ]; then
            git update-ref "$ref" "$theirs"
        fi
    fi
done

它可以使用下面的脚本…它将首先获取所有分支,逐个签出并自行更新。

#!/bin/bash
git branch -r | grep -v '\->' | while read remote; do git branch --track 
"${remote#origin/}" "$remote"; done

set -x
CURRENT=`git rev-parse --abbrev-ref HEAD`
git fetch --all
branch_name=$(git branch | awk '{print $1" "}' | grep -v '*' | xargs)
for branch in $branch_name; do
   git checkout "$branch" || exit 1
   git rebase "origin/$branch" || exit 1
   git pull origin $branch|| exit 1
done
git checkout "$CURRENT" || exit 1
git pull || exit 1