如何克隆所有远程分支?

4759

我在GitHub上远程追踪我的masterdevelopment分支。我该如何同时克隆这两个分支呢?


161
这里的被接受的答案(git branch -a)会展示远程仓库中的分支,但是如果你试图检出它们中的任何一个,你将处于'脱离HEAD'状态。第二个最受赞同的回答回答了另一个问题(即如何拉取所有分支,并且再次强调,这仅适用于你在本地跟踪的分支)。其中一些评论指出,你可以使用shell脚本解析git branch -a的结果来本地跟踪所有远程分支。总结:没有Git原生方法可以实现你想要的功能,而且也许这并不是一个好主意。 - Day Davis Waterbury
6
也许可以通过传统方式复制整个文件夹?scp some_user@example.com:/home/some_user/project_folder ~ 不确定这种解决方案是否适用于GitHub... - snapfractalpop
26
与其说“我已经克隆、拉取和获取了”,更好的方法是展示您执行的精确命令 - Bob Gilmore
94
“克隆”为何不是指完全的复制,这一点始终让我感到困惑。如果它是一个完全的克隆,那么所有分支不都应该是本地仓库的一部分吗?我的意思是,这不是分布式的一个重点之一吗?因此,当某个仓库消失时,您仍然拥有完整的副本。或者所谓的“远程”已经真正成为本地仓库的一部分了吗? - huggie
34
看到所有的点赞、回答、回答评论和惊人的浏览量,我认为现在是时候为此添加一个Git命令了。而你说得没错,@huggie,我的想法正是如此。 - Sнаđошƒаӽ
显示剩余9条评论
48个回答

8

当没有指定时,Git通常会从一个或多个其他存储库中获取所有分支和/或标签(引用,请参见:git ls-refs),以及完成它们的历史记录所需的对象。换句话说,它会提取已经下载的对象可以到达的对象。请参见:What does git fetch really do?

有时你可能有一些与当前分支没有直接联系的分支/标签,这时git pull --all/git fetch --all将不起作用,但你可以通过以下方式列出它们:

git ls-remote -h -t origin

通过知道引用名称手动获取它们。

因此,要全部获取,请尝试:

git fetch origin --depth=10000 $(git ls-remote -h -t origin)
--depth=10000参数可以帮助你在浅层存储库中找到更多内容。

然后再次检查所有分支:

git branch -avv

如果以上方法无法帮助,您需要手动将缺失的分支添加到跟踪列表中(因为它们在某种方式下丢失了):
$ git remote -v show origin

...
  Remote branches:
    master      tracked

通过 git remote set-branches 命令设置分支:

git remote set-branches --add origin missing_branch

因此,在获取后,它可能会出现在remotes/origin下:

$ git remote -v show origin

...
  Remote branches:
    missing_branch new (next fetch will store in remotes/origin)
$ git fetch
From github.com:Foo/Bar
 * [new branch]      missing_branch -> origin/missing_branch

故障排除

如果您仍然无法获取除主分支以外的内容,请检查以下内容:

  • 仔细检查您的远程仓库 (git remote -v),例如:
    • 验证 git config branch.master.remote 是否为 origin
    • 通过 git remote show origin 检查 origin 是否指向正确的 URL(参见此帖子)。

8

我需要做完全相同的事情。这是我的Ruby脚本。

#!/usr/bin/env ruby

local = []
remote = {}

# Prepare
%x[git reset --hard HEAD]
%x[git checkout master] # Makes sure that * is on master.
%x[git branch -a].each_line do |line|
  line.strip!
  if /origin\//.match(line)
     remote[line.gsub(/origin\//, '')] = line
   else
     local << line
   end
end
# Update 
remote.each_pair do |loc, rem|
  next if local.include?(loc)
  %x[git checkout --track -b #{loc} #{rem}]
end
%x[git fetch]

请查看我在下面发布的答案,避免运行此脚本。 - lacostenycoder

7

这里是另一个简短的单行命令,可以为所有远程分支创建本地分支:

(git branch -r | sed -n '/->/!s#^  origin/##p' && echo master) | xargs -L1 git checkout

如果已经创建了本地分支,它也可以正确运行。您可以在第一次 git clone 之后或任何时候调用它。

如果克隆后不需要检出 master 分支,请使用

git branch -r | sed -n '/->/!s#^  origin/##p'| xargs -L1 git checkout

7
截至2017年初,这个评论中的答案是可行的:git fetch <origin-name> <branch-name> 可以为您带来分支。虽然这不会一次拉取所有分支,但您可以逐个执行每个分支。

3
这需要你一次获取一个分支。如果有很多分支,这并不是很好。 - lacostenycoder

4
这个变化将克隆一个远程仓库,并在本地获取所有可用的分支,无需逐个检出每个分支。不需要复杂的脚本。
创建一个与要克隆的仓库同名的文件夹,并进入该文件夹,例如:
mkdir somerepo
cd somerepo

现在请按照实际的仓库用户名/仓库名称执行这些命令。
git clone --bare git@github.com:someuser/somerepo.git .git
git config --bool core.bare false
git reset --hard
git branch

完成了!您已经全部获得了分支!


这是对我有效的方法。简单而快速。 - Kevin Ghadyani
1
git rev-parse --abbrev-ref --symbolic-full-name '@{u}' 显示 fatal: no upstream configured for branch 'master'。应该是 origin/master - konsolebox
@konsolebox 我想答案已经更新了,你的评论现在已经过时了。 - Devin Rhode
@DevinRhode 没有仔细审查,我猜测我在这里暗示提到的解决方案带来了不一致的结果。详细阐述不是我的问题。 - konsolebox

3
如何为远程origin上的每个分支创建一个本地分支,以匹配指定的pattern
#!/bin/sh
git fetch --all
git for-each-ref --format='%(refname:short)' refs/remotes/origin/pattern |\
    sed 's@\(origin/\)\(.*\)@\2\t\1\2@' |\
    xargs -n 2 git branch --track

所有远程引用(分支/标签)都被获取,然后创建本地引用。在大多数系统上运行良好,速度快,无需检出索引或依赖于bashisms。


2

我无法编辑Bigfish的答案。他提出了一个bash脚本,我建议更新并提供更好的git集成。egrep已经过时,应该被grep -E替换。

#!/bin/bash
for branch in $(git branch --all | grep '^\s*remotes' | grep -E --invert-match '(:?HEAD|master)$'); do
        git branch --track "${branch##*/}" "$branch"
done

您可以通过将此bash文件添加为git自定义子命令来扩展git:

$ mkdir ~/.gitbin; touch ~/.gitbin/git-fetchThemAll
$ chmod u+x ~/.gitbin/git-fetchThemAll

将bash脚本的内容放入git-fetchThemAll中。
$ echo 'export PATH="$HOME/.gitbin:$PATH"' >> ~/.bashrc
$ source ~/.bashrc # update PATH in your current shell
$ git fetchThemAll

如果您愿意,您可以使用用户cfi的一行命令的shell别名。
别名fetchThemAll=git branch -a | grep -v HEAD | perl -ne 'chomp($_); s|^\*?\s*||; if (m|(.+)/(.+)| && not $d{$2}) {print qq(git branch --track $2 $1/$2\n)} else {$d{$_}=1}' | csh -xfs

2
我认为这就是解决方法:
mkdir YourRepo
cd YourRepo
git init --bare .git                       # create a bare repo
git remote add origin REMOTE_URL           # add a remote
git fetch origin refs/heads/*:refs/heads/* # fetch heads
git fetch origin refs/tags/*:refs/tags/*   # fetch tags
git init                                   # reinit work tree
git checkout master                        # checkout a branch

目前为止,这对我来说是有效的。


根据git fetch的refspec章节下的注释#2(http://www.kernel.org/pub/software/scm/git/docs/git-fetch.html),这可能需要进行调整。 - Andy
你是指笔记开头的那句话,“您永远不会在<refspec>冒号右侧出现的分支上进行自己的开发”吗?并且,调整后,原因是什么? - MarkDBlackwell
@MarkDBlackwell,说实话,我现在不确定当时我想表达什么。 - Andy

2
我试图找出如何拉取我已经在本地删除的远程分支。Origin不是我的,我不想费力重新克隆一切。
以下方法对我有效:
假设你需要在本地重新创建该分支:
git checkout -b recreated-branch-name
git branch -a (to list remote branches)
git rebase remotes/remote-origin/recreated-branch-name

如果我从 gituser/master fork 到 sjp,然后分支到 sjp/mynewbranch,它会看起来像这样:

$ git checkout -b mynewbranch

$ git branch -a
  master
  remotes/sjp/master
  remotes/sjp/mynewbranch

$ git fetch (habit to always do before)

$ git rebase remotes/sjp/mynewbranch

2
这个解决方案对我很有用,可以将一个仓库“复制”到另一个仓库:
git merge path/to/source.git --mirror
cd source.git
git remote remove origin
git remote add origin path/to/target.git
git push origin --all
git push origin --tags

在目标存储库中,我可以看到与原始存储库相同的分支和标签。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接