【问题标题】:Track all remote git branches as local branches跟踪所有远程 git 分支作为本地分支
【发布时间】:2010-09-27 14:28:41
【问题描述】:

将单个远程分支作为本地分支进行跟踪非常简单。

$ git checkout --track -b ${branch_name} origin/${branch_name}

将所有本地分支推送到远程,根据需要创建新的远程分支也很容易。

$ git push --all origin

我想反其道而行之。如果我在一个来源有 X 个远程分支:

$ git branch -r 
branch1
branch2
branch3
.
.
.

我可以为所有这些远程分支创建本地跟踪分支,而无需手动创建每个分支吗?像这样说:

$ git checkout --track -b --all origin

我已经在 Google 上搜索过 RTM,但到目前为止还没有找到。

【问题讨论】:

  • 还有一种更简单的方法可以将单个远程分支作为本地分支进行跟踪:git checkout --track origin/branchname
  • 这不完全符合您的要求,但对我有用:获取 git 完成:github.com/git/git/blob/master/contrib/completion/…。然后输入git pull origin 并点击tab,以获取远程分支列表。然后继续输入并点击return

标签: git branch


【解决方案1】:

Otto给出的答案很好,但是所有创建的分支都会以“origin/”作为名字的开头。如果您只想将最后一部分(在最后一个 / 之后)作为结果分支名称,请使用:

for remote in `git branch -r | grep -v /HEAD`; do git checkout --track $remote ; done

它还有一个好处是不会给你任何关于模棱两可的参考的警告。

【讨论】:

  • Git 不会在本地跟踪分支名称中添加“origin”。
  • @adymitruk:实际上它的行为与我在 OSX 10.6.4 上说的完全一样,使用的是 git 1.7.2.2(截至本评论的最新稳定版本)。 Otto 甚至提到了模棱两可的 refname 警告——如果“origin/”不是每个本地分支名称的一部分,则不需要存在警告。这是运行 Otto 命令后的“git 分支”输出:[master, origin/HEAD, origin/charts, origin/master, origin/production, origin/staging]。还有我的命令:[charts, master, production, staging]。
  • 我同意 - 这是一个比目前“接受”答案更好的解决方案。
  • 而不是grep -v mastergrep -v /HEAD 怎么样?这似乎过滤掉了默认分支,不需要自定义
【解决方案2】:

使用 bash:

在 git 1.9.1 之后
for i in `git branch -a | grep remote | grep -v HEAD | grep -v master`; do git branch --track ${i#remotes/origin/} $i; done

致谢: Val Blant、elias 和 Hugo

在 git 1.9.1 之前

注意:以下代码如果用在更高版本的git(>v1.9.1)中会导致

  1. (错误)所有创建的分支都用于跟踪 master
  2. (烦恼)所有创建的本地分支名称都以origin/为前缀
for remote in `git branch -r `; do git branch --track $remote; done

更新分支,假设您的本地跟踪分支没有变化:

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

忽略不明确的引用名警告,git 似乎更喜欢本地分支。

【讨论】:

  • 感谢您提供有关 refname 警告的提示。这很有帮助。
  • 谢谢 Otto,我怀疑脚本是唯一的解决方案。你提供了一个非常简单的。
  • @Jason 今天仍然是唯一的解决方案吗?
  • @naught101 git pull --all 获取所有分支,但只合并当前分支。
  • 这对我在 Git 1.9.1 上不起作用。 "git branch --track " 创建一个新的分支 来跟踪本地分支 master,而不是我们想要的远程分支。所以这个脚本创建了一堆本地分支,都指向本地主节点。我将在下面发布解决方案。
【解决方案3】:

这里的大多数答案都使git branch -r 的输出解析过于复杂。您可以使用以下for 循环来针对远程上的所有分支创建跟踪分支,如下所示。

示例

假设我有这些远程分支。

$ git branch -r
  origin/HEAD -> origin/master
  origin/development
  origin/integration
  origin/master
  origin/production
  origin/staging

确认我们没有在本地跟踪除 master 以外的任何内容:

$ git branch -l    # or using just git branch
* master

您可以使用这一行来创建跟踪分支:

$ for i in $(git branch -r | grep -vE "HEAD|master"); do 
    git branch --track ${i#*/} $i; done
Branch development set up to track remote branch development from origin.
Branch integration set up to track remote branch integration from origin.
Branch production set up to track remote branch production from origin.
Branch staging set up to track remote branch staging from origin.

现在确认:

$ git branch
  development
  integration
* master
  production
  staging

删除它们:

$ git br -D production development integration staging 
Deleted branch production (was xxxxx).
Deleted branch development (was xxxxx).
Deleted branch integration (was xxxxx).
Deleted branch staging (was xxxxx).

如果你使用-vv切换到git branch你可以确认:

$ git br -vv
  development xxxxx [origin/development] commit log msg ....
  integration xxxxx [origin/integration] commit log msg ....
* master      xxxxx [origin/master] commit log msg ....
  production  xxxxx [origin/production] commit log msg ....
  staging     xxxxx [origin/staging] commit log msg ....

for 循环的分解

循环基本上调用命令git branch -r,使用grep -vE "HEAD|master" 过滤掉输出中的任何HEAD 或master 分支。为了只得到分支的名称减去origin/ 子字符串,我们使用 Bash 的字符串操作${var#stringtoremove}。这将从变量$var 中删除字符串“stringtoremove”。在我们的例子中,我们从变量 $i 中删除字符串 origin/

注意:您也可以使用git checkout --track ... 来执行此操作:

$ for i in $(git branch -r | grep -vE "HEAD|master" | sed 's/^[ ]\+//'); do 
    git checkout --track $i; done

但我并不特别在意这种方法,因为它会在执行结帐时在分支之间切换。完成后,它会将您留在它创建的最后一个分支上。

参考文献

【讨论】:

  • 与 git 版本 2.3.2 (Apple Git-55) 完美配合
【解决方案4】:

2020 年第一季度更新:Mohsen Abasi 提出 in the comments,基于 2014 年 slmanswer,更简单的替代方案:

for i in $(git branch -r | grep -vE "HEAD|master" | sed 's/^[ ]\+//'); 

它使用$() instead of obsolete backticks

正如我在another old answer 中提到的,使用git for-each-refprobably faster
我会使用新的 (Git 2.23+) git switch command,它取代了 confusing git checkout

for i in $(git for-each-ref --format=%(refname:short) \
  --no-merged=origin/HEAD refs/remotes/origin); do \
    git switch --track $i; \
done

这样,不需要grep


旧(2011)原始答案:

这是我使用的单行代码(在 bash shell 中,使用 msysgit1.7.4 测试):

复制粘贴:

remote=origin ; for brname in `git branch -r | grep $remote | grep -v master | grep -v HEAD | awk '{gsub(/^[^\/]+\//,"",$1); print $1}'`; do git branch --set-upstream-to $remote/$brname $brname; done

为了提高可读性:

remote=origin ; // put here the name of the remote you want
for brname in `
    git branch -r | grep $remote | grep -v master | grep -v HEAD 
    | awk '{gsub(/^[^\/]+\//,"",$1); print $1}'
`; do 
    git branch --set-upstream-to $remote/$brname $brname; 
done
  • 它只会从您在remote 变量中指定的远程选择上游分支(可以是“origin”或您为当前 Git 存储库的远程之一设置的任何名称)。
  • 它将通过awk 表达式提取分支名称:origin/a/Branch/Name => a/Branch/Name
  • 它将设置上游分支through --set-upstream-to (or -u),而不是--track:
    好处是,如果分支已经存在,它不会失败,也不会改变那个分支的来源,它只会配置branch.xxx.(remote|merge)设置。

    branch.aBranchName.remote=origin
    branch.aBranchName.merge=refs/heads/a/Branch/Name
    

该命令将为所有远程上游分支创建本地分支,并将其远程和合并设置设置为该远程分支。

【讨论】:

  • 这给了我“致命的:分支'whatever'不存在”,每个分支只存在于远程并且没有相应的本地分支。
  • 我认为如果一个分支名称包含/例如:feature/rc-41-bckend,这个解决方案不起作用!!!
  • @VonC 基于“slm”的回答: $ for i in $(git branch -r | grep -vE "HEAD|master" | sed 's/^[ ]\+// ');做 git checkout --track $i;完成
  • @MohsenAbasi 看起来不错。在我的回答中,我提到使用 --set-upstream-to 而不是 --track
  • @MohsenAbasi 我已将您的替代方案包含在答案中以提高知名度。我添加了另一种列出远程分支的可能方式,并使用git switch 而不是git checkout。但是您的(非常好的)想法仍然存在。
【解决方案5】:

你可以很容易地编写脚本,但我不知道它什么时候有价值。这些分支很快就会落后,你必须一直更新它们。

远程分支会自动保持最新,因此最简单的方法是在您真正想要处理的地方创建本地分支。

【讨论】:

  • 这很好。我正在考虑的主要用例是基于远程 git 存储库设置本地开发环境。因此,当我进行初始克隆时,我还想跟踪当时的所有远程分支。
  • 方便的git up 更新所有本地分支。
  • 用于合并两个仓库并删除远程
【解决方案6】:

没有任何脚本(在一个空目录中):

$ git clone --bare repo_url .git
$ git config core.bare false
$ git checkout

之后,所有远程分支都将被视为本地分支。


original (in russian).

【讨论】:

  • 这是迄今为止最简单的解决方案,在 2.21.0.windows.1 上为我工作
  • 哇,它有效,而且非常简单。你能详细说明一下它是如何工作的吗?
  • @MaximKy 尝试使用和不使用--bare 选项进行克隆。然后在这两种情况下比较文件.git/packed-refs 的内容。使用此选项,分支最初创建为本地分支。
【解决方案7】:
for i in `git branch -a | grep remote`; do git branch --track ${i#remotes/origin/} $i; done

【讨论】:

  • 我必须在管道中添加一个| grep -v HEAD 才能使其正常工作。
【解决方案8】:

如果你想使用 powershell 并且你的遥控器被称为 origin。然后就可以了。

git fetch    
git branch -r  | %{$_ -replace "  origin/"} | %{git branch --track $_ "origin/$_"}

【讨论】:

  • 这非常有帮助,我最终使用了一个细微的变化来使它与我的git svn clone'd repo 一起工作:git branch -r | %{$_ -replace " origin/"} | %{git checkout -b $_ "origin/$_"}
  • 我也做了一点改动,因为我的本地分支机构已经存在:git branch -r | %{$_ -replace " origin/"} | %{git branch -u "origin/$_" $_}
【解决方案9】:
for branch in `git branch -a | grep remotes | grep -v HEAD | grep -v master`; do  git branch --track ${branch##*/} $branch; done

使用这个,你不会有这样的警告:refname 'origin/dev' is ambiguous

【讨论】:

    【解决方案10】:

    这是我对@tjmcewan 引用的 BASH 命令的解决方案:

    for remote in `git branch -r | grep -v /HEAD `; do git branch --track ${remote/"origin/"/""}; done
    

    我的目标是解决所有创建的分支都以“origin/”作为名称开头的问题,因为我测试了$remote变量仍然包含“origin/”:

    for remote in `git branch -r | grep -v /HEAD`; do echo $remote ; done
    

    【讨论】:

    • 在我测试了@tjmcewan 的 BASH 之后,我发现所有被跟踪的分支名称在本地都没有 'origin/',我不知道为什么。
    • 第一个命令创建跟踪“master”的分支。这不是大多数人可能想要的东西。
    • @AlexeiOsipov 谢谢!
    【解决方案11】:

    从 git 2.23 开始:

    for branch in `git branch -r | grep origin/`; do git switch -t -C ${branch#origin/} $branch; git pull; done
    

    git switch-C 标志创建或重置(如果已存在)。

    git switch documentation

    【讨论】:

      【解决方案12】:

      要执行与 tjmcewan's answer 相同的操作,但在 Windows 上,请从 批处理文件中调用它:

      for /f "delims=" %%r in ('git branch -r ^| grep -v master') do git checkout --track %%r
      

      或者从命令行

      for /f "delims=" %r in ('git branch -r ^| grep -v master') do git checkout --track %r
      

      【讨论】:

        【解决方案13】:

        通过更改 sed 可以进一步简化 VonC 的解决方案(我没有代表点可以直接评论他的帖子):

        for branch in $(git branch -r | sed 's,[^/]*/,,g'); do git switch $branch; done
        

        通过替换所有不是斜线的东西直到最后一个斜线,剩下的分支名称适合本地使用;重复切换到同一个分支不是错误(它可能效率低下,但它可能比管道中的 grep 更有效:->)。

        switch 命令足够智能,可以根据需要跟踪每个远程分支。

        【讨论】:

        • 我 2011 年旧答案的有趣之处。赞成。
        【解决方案14】:

        如果您已经签出了一些分支并想要

        • 从远程检查所有剩余的分支
        • 确保所有本地分支都跟踪远程分支

        您可以使用以下 bash 和 zsh 兼容的脚本:

        git branch -r | while read b; do if git branch | grep -q " ${b##*/}$"; then git branch --set-upstream ${b##*/} $b; else git branch --track ${b##*/} $b; fi; done
        

        【讨论】:

          【解决方案15】:
          for rembranch in `git remote update 2>&1 > /dev/null ; git branch -r|egrep -wv "HEAD|master"`
          do 
              git checkout --track -b `echo $rembranch|awk -F\/ '{print $2}'` $rembranch; 
          done
          

          解释:

          第 1 行:“git branch -r”(后跟“git remote update”以更新远程更改信息)列出所有远程分支; 'egrep -vw' 用于敲除结果中包含 HEAD 和 master 的条目。

          第 3 行:在本地签出时跟踪命名的远程分支。一个简单的 awk 用于避免 'origin/' 成为本地分支的后缀。

          【讨论】:

            【解决方案16】:

            使用 bash, 如果你想检查所有分支:

            for remote in `git branch -r`; do git checkout $(echo $remote | cut -d'/' -f 2); done
            

            请务必注意,当您执行 fetch 会关闭新的远程跟踪分支时,您不会自动拥有它们的本地、可编辑副本。

            【讨论】:

              猜你喜欢
              • 2013-04-30
              • 2014-06-09
              • 2013-11-15
              • 2019-02-16
              • 2010-10-05
              • 2014-02-04
              • 2012-03-05
              • 2011-07-27
              相关资源
              最近更新 更多