可以"git pull --all"更新我所有的本地分支机构吗?

mpo*_*sot 439 git

我经常至少有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
Run Code Online (Sandbox Code Playgroud)

我很乐意能够做一个"git pull -all",但我无法让它发挥作用.它似乎执行"fetch --all",然后更新(快进或合并)当前工作分支,而不是其他本地分支.

我仍然卡在手动切换到每个本地分支和更新.

Joh*_*ohn 199

我用的sync子命令中枢自动执行此.Hub的别名为alias git=hub,所以我输入的命令是:

git sync
Run Code Online (Sandbox Code Playgroud)

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

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

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

我曾经使用过类似的工具git-up,但它不再被维护,并且.bash_profile几乎完全相同.

  • 重新定位本地提交是重写历史并使其比实际更简单.使用rebase,您可能会发现自己使用自动合并但不编译的代码,或者更糟糕的是,编译但不起作用.合并确认了您的工作方式:您实现了更改并在合并其他人的更改之前对其进行了测试,并且合并提交是一个非常有用的点:在这里您可以确保不同的chageset可以很好地协同工作.重新定位使得这个过程看起来永远不会发生,这根本不是真的,是一种非常危险的做法. (23认同)
  • @MaxYankov通常要避免重新分享共享历史记录,在拉动期间重新定位本地提交没有任何问题. (17认同)
  • 要关闭的混帐了自动重订基期的行为,运行`git配置--global git-up.rebase.auto返回FALSE. (16认同)
  • Windows怎么样? (14认同)
  • @TrentonD.Adams提交日期和作者日期是不同的概念.rebase将更改提交日期,但不会更改作者日期(冲突除外,其中作者日期也会更改).作者日期反映何时创建提交树,并且在未冲突的rebase期间不应更改.提交日期更改,因为rebase始终创建新提交.因此,提交日期将始终按正确的顺序排列. (6认同)
  • 请注意以下描述:"此项目已不再维护,原因如下:我已停止使用使其与我相关的工作流程.Git 2.0更新了默认行为以删除它正在解决的主要问题(通过更改`git push`的默认行为所以它只作用于当前分支,而不是所有分支.)从Git 2.9开始,`git pull --rebase --autostash`基本上做同样的事情." (6认同)
  • 请注意,此软件不再维护.有关详细信息,请参阅警告部分[link](http://aanandprasad.com/git-up/). (4认同)
  • 我认为对两种不同的rebase类型存在误解.1)当你做git rebase 2)当你做git pull --rebase这是完全不同的过程,由@MaxYankov发布的关于"Rebase Considered Harmful"的文章是关于git rebase但是这个帖子中的大多数人都没有谈论这个.我们正在谈论拉动期间的反转.抱歉英文不好:( (4认同)
  • 此脚本的问题是它不会获取新创建的远程分支. (2认同)
  • @VioletGiraffe我对Windows的首选方法:1.安装git(我希望已经完成)2.安装ruby(https://www.ruby-lang.org/)或使用RailsInstaller安装ruby/rails(http:// railsinstaller.org/en)3.打开git bash并运行`gem install git-up` (2认同)
  • 旧的,但让我在合并时抛弃我的偏好.单行历史记录更易于思考和编写脚本.至于"有害"/等等...... linux内核(git是为了帮助构建而开发的)大量使用不包含合并历史记录的电子邮件补丁.我认为这并不像许多人那样明确对错.http://nickdesaulniers.github.io/blog/2017/05/16/submitting-your-first-patch-to-the-linux-kernel-and-responding-to-feedback/ (2认同)

Cas*_*bel 178

您描述的行为pull --all完全符合预期,但不一定有用.该选项被传递给git fetch,然后从所有遥控器获取所有引用,而不仅仅是所需的引用; pull然后合并(或在你的情况下,rebase)适当的单个分支.

如果你想查看其他分支机构,你将不得不检查它们.是的,合并(和重新定位)绝对需要一个工作树,所以如果不检查其他分支就无法完成.如果你愿意的话,你可以把你描述的步骤包装成一个脚本/别名,虽然我建议加入这些命令,&&这样如果其中一个失败了,它就不会尝试使用.

  • @mariotti这个答案的要点是内置命令实际上并没有执行OP所要求的,因此他们必须执行的步骤顺序.可以自动执行这些步骤(例如参见John的回答),但必须完成这些步骤.因此,如果你要做的事与OP完全相同,那么就没有真正的例子,如果你想做一些不同的事情,那么你应该问一个新的问题 - 这就是StackOverflow的工作方式!(你的评论不清楚,但我最好的猜测是你想要一些与OP不同的东西,所以是的,新的问题.) (3认同)
  • 如果你给出一个示例命令行,我会投票.我在github上有这个问题.我在UI上创建了一个分支.现在我需要我的本地人来展示这个分支.git pull --all; git branch ... argh ...命令:git branch -a (2认同)

muh*_*hqu 37

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

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

  1. 它发出一个git remote update来获取lates revs
  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
Run Code Online (Sandbox Code Playgroud)

完整的脚本应该保存为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 $@
Run Code Online (Sandbox Code Playgroud)

  • @muhqu 在较新的 git 版本上,-t 和 -l 不应该在一个“git分支”调用中一起使用。我删除了 -l 以将调用更改为“git Branch -f $LB -t $ARB &gt;/dev/null;”,现在脚本可以正常工作。 (2认同)

Fre*_*Foo 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
Run Code Online (Sandbox Code Playgroud)

  • 我仍然认为你可能想要使用`pull`(或检查`branch.<branch> .rebase`),这样你就不会意外地重新设置一个设置为正常拉(合并)的分支. (7认同)
  • 最好不要在脚本中使用别名.这实际上并没有获取任何内容,只是重新绑定到已经获取的内容上.您应该将`git rebase origin/$ branch`更改为`git pull`,以便它从相应的跟踪分支(可能是原点)获取,并根据配置确定合并或重组. (3认同)

Mat*_*lly 17

这仍然不是自动的,因为我希望有一个选项 - 并且应该进行一些检查以确保这只能发生在快进更新中(这就是为什么手动执行拉动更安全!!),但除了警告,你可以:

git fetch origin
git update-ref refs/heads/other-branch origin/other-branch
Run Code Online (Sandbox Code Playgroud)

更新本地分支的位置而无需检查.

注意:您将失去当前的分支位置并将其移动到原始分支的位置,这意味着如果您需要合并,则会丢失数据!

  • 合并为一个命令:`git fetch origin other-branch:other-branch` (5认同)

Jak*_*ski 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关于删除远程不再存在的分支的远程跟踪分支,而不是删除跟踪远程跟踪分支的本地分支(远程跟踪分支是上游分支).


quo*_*ian 11

这里有很多答案,但没有一个用于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
Run Code Online (Sandbox Code Playgroud)

从联机帮助页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.
Run Code Online (Sandbox Code Playgroud)

通过指定git fetch <remote> <ref>:<ref>(没有任何+),我们得到一个获取,只有当它可以快进时才更新本地ref.

注意:这假设本地和远程分支的名称相同(并且您希望跟踪所有分支),它应该真正使用有关您拥有哪些本地分支以及它们设置为跟踪的内容的信息.


mic*_*ael 7

这里有很多可接受的答案,但有些管道可能对于不熟悉的人来说有点不透明.这是一个可以轻松定制的更简单的示例:

$ 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 "$@"
Run Code Online (Sandbox Code Playgroud)

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

$ git update-all
Run Code Online (Sandbox Code Playgroud)


小智 7

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

我想知道这一点,我在我的 .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"
}
Run Code Online (Sandbox Code Playgroud)

为我工作(:


mil*_*sky 6

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

for remote in `git branch -r`; do git branch --track $remote; done
git pull --all
Run Code Online (Sandbox Code Playgroud)

  • 这将获取所有遥控器,但它只会合并当前分支.如果您有10个遥控器,则需要手动检查每个遥控器并合并. (8认同)

Mik*_*ike 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};
};
Run Code Online (Sandbox Code Playgroud)


Bou*_*uty 5

您无法仅使用一个 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
Run Code Online (Sandbox Code Playgroud)
  • 如果它无法快进一个分支或遇到错误,它将停止并将您留在该分支,以便您可以收回控制权并手动合并。

  • 如果所有分支都可以快进,它将以您当前所在的分支结束,让您保持在更新之前的位置。

说明:

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

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
Run Code Online (Sandbox Code Playgroud)
  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'
Run Code Online (Sandbox Code Playgroud)

或者,如果您担心弄乱 ' 和 ",或者您只是希望在编辑器中保持语法可读性,则可以将其声明为函数:

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
}
Run Code Online (Sandbox Code Playgroud)

奖金:

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

  • /*/=> 搜索带有*.

  • {$q=> 如果它在最后一行,则退出(我们不需要做任何事情,因为当前分支已经是列表中的最后一个)。

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

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