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


473

我经常至少有3个远程分支机构:主分支,临时分支和生产分支。我有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”,但我一直无法使它工作。它似乎在执行“获取-全部”操作,然后更新(快进或合并)当前工作的分支,而不更新其他本地分支。

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


8
您是否只想在快进情况下自动更新本地跟踪分支?Ypu应该,因为合并可能会使您不得不解决
冲突

34
假设保守的咨询时间为300美元,那么此期发行的公司使用的视图计数为77,476,因此使公司损失了23,242,800美元。现在考虑这个问题stackoverflow.com/questions/179123/…以及所有其他问题。哇。
路加·普普利特

16
@Luke您是我所听到的第一个人,指出如何使git达到我们想要的目标花费了时间。这些简单的事情应该是自动的,并且应该非常简单,我不必打开浏览器即可阅读论坛IMO。
塞缪尔

13
@LukePuplett与Mercurial相比,关于git的git问题几乎有9倍,前者的大部分似乎是“我如何在git中执行<简单操作>”。这表明git要么设计不当,文档不完善,不直观,要么全部三种。
伊恩·肯普

26
@IanKemp在不确定SO的人口统计信息的情况下,我不确定是否可以安全地提出这一主张。如果Mercurial在这里不常用,或者它的用户使用其他论坛来询问它,我希望看到相同的结果。:)与汇编语言相比,关于Javascript的问题约为51倍-因此仅根据这些指标来判断工具可能并不总是准确的。
danShumway 2015年

Answers:


188

您描述的行为pull --all与预期的完全一样,尽管不一定有用。该选项传递给git fetch,然后git fetch从所有远程获取所有ref,而不仅仅是所需的ref。pull然后合并(或重新设置基准)相应的单个分支。

如果要签出其他分支,则必须签出。是的,合并(和重新定基)绝对需要一个工作树,因此,如果不签出其他分支就无法完成它们。如果愿意,您可以将描述的步骤包装到脚本/别名中,尽管我建议将这些命令与命令一起使用,&&以便在其中一个失败的情况下,也不会尝试继续使用。


2
如果您提供示例命令行,我将投赞成票。我在github上有这个问题。我在UI上创建了一个分支。现在,我需要本地人来显示分支。git pull --all; git branch ... argh ...命令:git branch -a
mariotti 16-10-29

@mariotti取决于您要执行的操作,您的评论并不清楚。您可能最好问一个新问题。
卡斯卡贝尔

1
或@Jefromi ..举个例子。我确实同意你的看法。
mariotti

3
@mariotti这个答案的重点是内置命令实际上并没有执行OP所要求的操作,因此有必要按顺序执行它们。可以自动执行这些步骤(例如,参见John的答案),但是必须完成这些步骤。因此,如果您要尝试的操作与OP完全相同,则没有真正的示例可以提供,如果您尝试做不同的事情,那么您应该提出一个新问题-StackOverflow的工作方式!(您的评论尚不清楚,但我最大的猜测是您想要与此处的OP有所不同,所以是新问题。)
Cascabel

是的,有些不同。但是您的答案对于上下文来说是完美的。而且我可能仅因为您的回答就不需要再问了。只是:可接受的答案使用git-up,它只是git命令行的接口(我假设)。我希望您可以在几行git命令中使其明确。当前答案不是git。
mariotti

206

我使用hubsync子命令将其自动化。我在中,因此键入的命令是:alias git=hub.bash_profile

git sync

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

  • 如果本地分支已过时,则将其快进;
  • 如果本地分支机构包含未完成的工作,请对其进行警告;
  • 如果分支似乎已合并并且其上游分支已删除,则将其删除。

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

我曾经使用过类似的工具git-up,但是不再维护,并且git sync几乎可以完成相同的操作。


14
Windows呢?
紫罗兰色长颈鹿

6
@ TrentonD.Adams提交日期和作者日期是不同的概念。重新设置基准将更改提交日期,但不会更改作者日期(除非冲突中,作者日期也会更改)。作者日期反映了提交树的创作时间,并且在无冲突的基准期间不应更改。提交日期会更改,因为变基总是创建一个新的提交。因此,提交日期将始终按正确的顺序进行。
2015年

16
要关闭git-up的自动重定基础行为,请运行git config --global git-up.rebase.auto false
Dan Loewenherz

17
@MaxYankov通常应避免对共享历史记录进行重定基础,在拉动过程中对本地提交进行重定基础没有错。
2015年

23
改写本地提交将重新编写历史记录并使之变得比实际更简单。使用rebase,您可能会发现自己的代码会自动合并但无法编译,或更糟糕的是,编译却无法正常工作。合并确认您的工作方式:您在合并其他人的变更之前实施了更改并进行了测试,并且合并提交是非常有用的一点:在这里,您可以确保不同的Chagesets可以很好地协同工作。变基使该过程看起来从未发生过,这是不正确的,并且是非常危险的做法。
Max Yankov

39

我知道这个问题将近3年了,但是我问自己同样的问题,没有找到任何现成的解决方案。因此,我创建了一个自定义的git command shell脚本。

这里有云,该git-ffwd-update脚本执行以下操作...

  1. 它发出一个git remote update获取最新版本的转速
  2. 然后用于git remote show获取跟踪远程分支的本地分支的列表(例如可以与一起使用的分支git pull
  3. 然后它检查git rev-list --count <REMOTE_BRANCH>..<LOCAL_BRANCH>本地分支位于远程后面的提交数量(反之亦然)
  4. 如果本地分支为1或多个,则不能进行快速转发,而需要手工合并或重新设置
  5. 如果本地分支为0,则向前提交,然后为1或更多,则可以通过以下方式快速转发: 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 $@

1
感谢您的脚本。有人可以将该脚本转换为Windows批处理吗?
萨里科

@Saariko为什么不在普通的Windows Shell上使用git?如果您使用cygwin之类的脚本,该脚本应该可以正常工作...(尽管我尚未测试过)
muhqu 2012年

@RyanWilcox谢谢,我每天(工作日)都在使用它; ;-)您可能想看看我的点文件以获取更多与git相关的脚本和别名: github.com/muhqu/dotfiles
muhqu 2014年

@muhqu我正在尝试使用您的脚本,但我不知道为什么它第一次起作用,但是它现在无法“按预期”起作用。例如,看看this。为什么运行脚本后master仍然落后78提交?
BPL

1
@muhqu在较新的git版本上,-t和-l不应在一个git branch调用中一起使用。我删除了-l来将调用更改为git branch -f $LB -t $ARB >/dev/null;,现在脚本可以正常工作了。
Radek Liska

24

自动化并不难:

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

4
最好不要在脚本中使用别名。这实际上也不会获取任何东西,只是基于已经获取的内容。您应该更改git rebase origin/$branchgit pull,以便它将从适当的跟踪分支(大概是在原始位置)获取,并根据配置确定合并或变基。
卡斯卡贝尔

@Jefromi:我忘记了fetch。已编辑;附加功能/修复,取决于OP。
Fred Foo 2010年

8
我仍然认为您可能要使用pull(或检查branch.<branch>.rebase),以便您不会意外地使设置为正常拉(合并)的分支变基。
卡斯卡贝尔

1
考虑使用set -e而不是|| exit 1使解释器在第一个错误时退出。
crishoj

18

这仍然不是自动的,因为我希望有一个选项-并且应该进行一些检查以确保仅在快速转发更新中会发生这种情况(这就是为什么手动进行拉动更加安全!!),但请注意,您可以:

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

无需签出即可更新本地分支机构的位置。

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


1
这正是我一直在寻找的解决方案。我通常不会在多个分支机构上进行未更改的更改,而只想更新我的各种本地分支机构以匹配远程服务器。这个解决方案比我通常的删除/重新签出方法好得多!
戴夫·奈特

1
合并为一个命令:git fetch origin other-branch:other-branch
fabb

12

这里有很多答案,但没有一个答案可用于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

   <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>(不带任何值+),我们可以获取仅在可以快速转发本地引用时更新本地引用的访存。

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


1
“仅在可以快速转发的情况下更新分支” - 快速转发的意义是什么?如果我想要所有分支机构的最新资源,那为什么不关心快速转发呢?这样的事情让我嘲笑Git及其Fanboi的。您不能仅通过一个命令来执行此操作。取而代之的是,您需要执行c*n步骤(而不是1),其中c的重复命令n数是分支的数量。
jww

@jww当世界上大多数人使用的VCS时,“嘲笑Git及其Fanboi的”并没有帮助。但是我离题了……我认为在这种“全局拉”脚本的上下文中,如果非当前分支存在合并冲突,则不要尝试对它们进行更改是明智的。
Ville

这很有帮助,谢谢。我唯一不喜欢的是它为每个远程分支(包括我不感兴趣的分支)在本地创建了一个分支,因此我更改git branch -r | grep -v ' -> ' | while read remotebranchgit branch -r | grep -v ' -> ' | grep -f <(git branch | cut -c 3- | awk '{print "\\S*/"$0"$"}') | while read remotebranch将其限制为我已经在本地拥有的分支。另外git fetch --prune,在开始执行任何操作之前,我还在开头添加了一个以更新远程分支的列表,这避免了一些警告。
Nate Cook

11

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

主要的理由是您不需要:

使用不是很古老的git(即v1.5.0或更高版本),就没有理由让本地的“ dev”不再纯粹跟踪远程服务器了。如果您只想看一看,可以直接在带有“ git checkout origin/dev” 的独立HEAD上签出远程跟踪分支。

这意味着,我们需要为用户提供方便的唯一情况是,当您进行本地更改或计划进行某些更改时,处理这些“跟踪”远程分支的本地分支。

如果您确实在“ dev”上进行了本地更改,并标记为跟踪删除的“ dev”,并且您所在的分支与“ dev”不同,则在git fetch更新远程跟踪“ dev” 之后我们不应该执行任何操作。反正它不会快进

解决方案的呼吁是使用选项或外部脚本来修剪现在跟随远程跟踪分支的本地分支,而不是像要求原始海报那样通过快速转发使它们保持最新状态。

那么git branch --prune --remote=<upstream>遍历本地分支的“ ” 怎么样,如果

(1)不是当前分支;和
(2)它被标记来跟踪从采取了一些分支的<上游>; 和
(3)它不会对自己的任何承诺;

然后删除该分支?“ git remote --prune-local-forks <upstream>”也很好;我不太在乎哪个命令可以实现该功能。

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


而不是仅发布链接,使用链接作为参考发布实际内容。该链接现在已消失。太糟糕了,听起来很有希望。(我意识到这个答案来自2009年,所以这只是一个注释,以供将来参考。)
迈克尔

谢谢(哇,这么多年后迅速回复)。现在,我看到此线程是“ 要求简单解决方案”,与我最初的误读相反,“ 提供简单解决方案”。
迈克尔

@michael_n:扩展了...嗯,现在我看到该帖子与请求的解决方案不完全相关,但是与问题有关(假设XY问题)。
JakubNarębski17年

嗯,应该使抬头时偷看更容易一些,尤其是它应该在状态中显示有用的信息,并允许通过一些反馈(例如拉入的提交)快速前进工作空间。然后它将替代只读的本地分支。
eckes

9

这里有很多可以接受的答案,但是对于一些初学者来说,某些管道可能有点不透明。这是一个更简单的示例,可以轻松自定义:

$ 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

谢谢!您节省了我一个小时玩bash的时间
8ctopus

5

将此脚本添加到.profileMac OS X上:

# 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};
};

1
这不应该先存储所有更改,然后再还原它们吗?
梅尔

5

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

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

你为什么建议做git fetchgit pull,而不是仅仅git pull
宪法

谢谢。拉似乎从所有远程获取所有分支。更改了
milkovsky 2015年

8
这将获取所有远程,但只会合并当前分支。如果您有10个遥控器,则需要手动检出每个遥控器并合并。
mpoisot

这样做将在本地创建所有带有origin/前缀的远程分支
Yassine ElBadaoui

3

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

  • 默认情况下,将所有设置为跟踪原点的分支从原点拉出,允许您根据需要指定其他遥控器。
  • 如果您当前的分支处于脏状态,则它将存储您的更改,并在最后尝试恢复这些更改。
  • 对于设置为跟踪远程分支的每个本地分支,将:
    • git checkout branch
    • git pull origin
  • 最后,将使您返回到原始分支并还原状态。

**我使用此工具,但尚未彻底测试,使用风险自负。在.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
    }

您可以提供等效的Windows bat文件吗?
贾菲2015年

1
@Jaffy不知道我手上有多少时间,但我不是很流利,但是我可以试一试。我将在这里发布进度,也许其他人可以介入并提供帮助?
philosowaffle 2015年

3

如果您使用的是Windows,则可以使用PyGitUp,它是git-upPython 的克隆版本。您可以通过安装它的PIPpip install --user git-up或通过炒到使用scoop install git-up

[4]


3

只是发布更新的答案。git-up不再维护,如果您阅读文档,他们会提到git中现在提供了该功能

从Git 2.9开始,git pull --rebase --autostash基本上做同样的事情。

因此,如果您更新到Git 2.9或更高版本,则可以使用以下别名代替安装git-up:

git config --global alias.up 'pull --rebase --autostash'

您还可以git pull在Git 2.9以及更高版本中进行设置(感谢@VonC,请在此处查看其答案)

git config --global pull.rebase true
git config --global rebase.autoStash true

1
您不需要别名。一个简单的git pull就足够了,使用正确的配置:stackoverflow.com/a/40067353/6309
VonC

大叫唤感谢@VonC我更新了我的答案:)也可以提交一个PR的git-up文件,因为他们没有提到
八月

这不会一次更新所有本地分支,这就是我主要使用的原因git-up
射线

文档更新git-up:)
八月

3

我遇到了这个问题的同一问题...

让我感到奇怪的是,我在.bashrc文件内部做了一个小的别名函数 :

gitPullAll() {
    for branch in `git branch | sed -E 's/^\*/ /' | awk '{print $1}'`; do
        git checkout $branch
        git pull -p
        printf "\n"
    done
    echo "Done"
}

为我工作(:


2

如果refs / heads / master可以快速转发到refs / remotes / foo / master,则输出

git merge-base refs/heads/master refs/remotes/foo/master

应该返回ref / heads / master指向的SHA1 ID 。这样,您可以将一个脚本组合在一起,该脚本可以自动更新所有未应用转移提交的本地分支。

这个小shell脚本(我称其为git-can-ff)说明了它是如何完成的。

#!/bin/sh

set -x

usage() {
    echo "usage: $(basename $0) <from-ref> <to-ref>" >&2
    exit 2
}

[ $# -ne 2 ] && usage

FROM_REF=$1
TO_REF=$2

FROM_HASH=$(git show-ref --hash $FROM_REF)
TO_HASH=$(git show-ref --hash $TO_REF)
BASE_HASH=$(git merge-base $FROM_REF $TO_REF)

if [ "$BASE_HASH" = "$FROM_HASH" -o \
     "$BASE_HASH" = "$FROM_REF" ]; then
    exit 0
else
    exit 1
fi

您的评论暗示了什么?
丘卢

我自己没有能力编写Hillu建议的脚本,并且我对git的知识不够自信,无法使用git-merge-base。
诺曼·拉姆齐

2
恐怕我对模型不够了解,无法利用如此提供的脚本。这足以使一个人想要转向商业化。
诺曼·拉姆齐

我个人发现Tommi Virtanen的文章“计算机科学家的Git”对于熟悉git的模型和术语很有帮助。
丘卢

2

为了完成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

2

脚本稍有不同,仅名字快进的分支与其上游分支匹配。如果可以快进,它也会更新当前分支。

确保通过运行正确设置了所有分支的上游分支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;

2

如果可能,以下一线式快进所有具有上游分支的分支,否则显示错误:

git branch \
  --format "%(if)%(upstream:short)%(then)git push . %(upstream:short):%(refname:short)%(end)" |
  sh

它是如何工作的?

它与git branch命令一起使用自定义格式。对于具有上游分支的每个分支,它将打印具有以下模式的行:

git push . <remote-ref>:<branch>

这可以直接通过管道传递到sh(假设分支名称格式正确)。忽略| sh可以看到它在做什么。

注意事项

单线不会与您的遥控器联系。在运行前发出a git fetchgit fetch --all

当前已签出的分支将不会更新,例如

! [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' -

另请参阅我的.gitconfig。别名是“快速跟踪(分支)”的简写。


这是一个很好的解决方案,但我想我会用hub通过@约翰propsed soluction它的更好的输出。
Didier L

这是快速,简单且切实可行的!我git push对它感到困惑,因为它与您期望的完全相反。有什么秘密?
BrandonLWhite

@BrandonLWhite:我不明白这个问题。您有什么期望git push
krlmlr

git push具有上载语义-我想在本地发送一些提交到上游。 git pull具有下载语义-我想将一些上游远程提交提交到我的本地分支中。由于我们正在谈论从远程将新提交下载到本地,因此git pull是显而易见的选择。但不,此技巧使用git push。如何git push将远程更改拉到我的本地分支?
BrandonLWhite

git push也可以用于更新本地分支,只要这是快速更新即可。
krlmlr

1

@larsmans的脚本有了一些改进:

#!/bin/sh

set -x
CURRENT=`git rev-parse --abbrev-ref HEAD`
git fetch --all
for branch in "$@"; do
  if ["$branch" -ne "$CURRENT"]; then
    git checkout "$branch" || exit 1
    git rebase "origin/$branch" || exit 1
  fi
done
git checkout "$CURRENT" || exit 1
git rebase "origin/$CURRENT" || exit 1

完成后,将工作副本从调用脚本之前的同一分支中检出。

git pull版本:

#!/bin/sh

set -x
CURRENT=`git rev-parse --abbrev-ref HEAD`
git fetch --all
for branch in "$@"; do
  if ["$branch" -ne "$CURRENT"]; then
    git checkout "$branch" || exit 1
    git pull || exit 1
  fi
done
git checkout "$CURRENT" || exit 1
git pull || exit 1

1

看起来许多其他人都在提供类似的解决方案,但是我想我会分享我的想法并邀请其他人来做贡献。该解决方案具有出色的彩色输出,可以优雅地处理您当前的工作目录,并且速度很快,因为它不执行任何签出操作,并且使您的工作目录保持原样。而且,它只是一个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

抱歉,我似乎也想出了与上面其他工具相同的名称。


2
你是写这个的那个人吗?如果是这样,请透露您的隶属关系,即告诉我们您的关系。请阅读此内容以获取更多信息。具体来说, 不要告诉-显示!; 告诉我们您脚本的哪些部分以及如何/为什么解决问题。
Keale 2015年

1
是的,我写了。我已经在上面包含了用于快速复制粘贴到.bashrc或.zshrc中的源。
Stimp

这是一个很好的解决方案,效果很好。没人注意到吗?
Ville

1

可以使用以下脚本来完成...首先将提取所有分支并逐个签出并自行更新。

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

添加一些评分标准的解释
fool-dev

1

您不能仅使用一个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
  1. git fetch --all && ... =>从所有远程获取所有引用,如果没有错误,则继续执行下一个命令。

  2. git branch | sed '/*/{$q;h;d};$G' | tr -d '*'=>从的输出中git branchsed以a作为一行,*然后将其移至末尾(这样,当前分支将最后更新)。然后tr只需删除即可*

  3. for branch in $(...) ; do git checkout $branch && git merge --ff-only || break ; done=>对于从上一条命令获得的每个分支名称,请检出此分支并尝试与快进合并。如果失败,将break被调用并在此处停止命令。

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

最后,您可以将它作为别名放在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'

或者,如果您担心弄乱'和',或者只想在编辑器中保持句法可读性,则可以将其声明为一个函数:

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 =>如果它在最后一行,请退出(我们不需要做任何事情,因为当前分支已经是列表中的最后一个)。

  • ;h;d} =>否则,将行存储在保留缓冲区中,然后将其删除在当前列表位置。

  • ;$G =>当到达最后一行时,附加保留缓冲区的内容。


您可以&&通过set -e在脚本顶部进行设置来避免所有无休止的疯狂行为。
mcepl

0

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

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

该工具的优点:

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

-1

从git 2.9开始:

git pull --rebase --autostash

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

在操作开始之前自动创建一个临时存储,并在操作结束之后应用它。这意味着您可以在肮脏的工作树上运行rebase。但是,请谨慎使用:成功重新设置基准之后的最终存储应用程序可能会导致非平凡的冲突。


-1

实际上,使用git version 1.8.3.1,它可以工作:

[root@test test]# git br
* master
  release/0.1
  update
[root@test test]# git pull --rebase
remote: Enumerating objects: 9, done.
remote: Counting objects: 100% (9/9), done.
remote: Compressing objects: 100% (9/9), done.
remote: Total 9 (delta 2), reused 0 (delta 0)
Unpacking objects: 100% (9/9), done.
From http://xxx/scm/csdx/test-git
   d32ca6d..2caa393  release/0.1 -> origin/release/0.1
Current branch master is up to date.
[root@test test]# git --version
git version 1.8.3.1

在master分支中,您可以更新所有其他分支。@卡斯卡贝尔

我不知道哪个版本可以在2.17(我使用的版本)中对其进行修复/修复。

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.