[英]“git fetch” remote refs of remotes
I would like to be able to move all work-in-progress branches from repository to repository and be able to delete the old ones without losing any commits. 我希望能够将所有正在进行的分支从存储库移到存储库,并能够删除旧的分支而不丢失任何提交。 Is there a way I can fetch the remote branches from a remote repository?
有没有办法可以从远程存储库中获取远程分支?
# A: Create a repo with two branches
> mkdir a ; cd a ; git init
> echo initial > file_master ; git add file_master ; git commit -am "initial"
> git checkout -b mybranch
> echo test > file_mybranch ; git add file_mybranch ; git commit -am "test"
> git checkout master
# B: Clone
> git clone . ../b ; cd ../b
> git branch -a
* master
remotes/origin/HEAD -> origin/master
remotes/origin/master
remotes/origin/mybranch
# if I wanted, I could delete a and checkout remotes/origin/mybranch
# C: Clone of clone, but it's missing mybranch
> git clone . ../c ; cd ../c
> git branch -a
* master
remotes/origin/HEAD -> origin/master
remotes/origin/master
# no remotes/origin/mybranch - it's a remote of origin
# if I delete a and b I lose mybranch for good
>git ls-remote
7505fa4ec342ff85095737d27df0a5062c53d4d5 HEAD
7505fa4ec342ff85095737d27df0a5062c53d4d5 refs/heads/master
7505fa4ec342ff85095737d27df0a5062c53d4d5 refs/remotes/origin/HEAD
7505fa4ec342ff85095737d27df0a5062c53d4d5 refs/remotes/origin/master
dfd057c18baa4227905999b32bffdecf639185f7 refs/remotes/origin/mybranch
# there it is, but I don't have it locally
Just to reiterate, in repository B I can safely rm -rf ../a
, then git checkout remotes/origin/mybranch
and I'll have file_mybranch
. 重申一下,在存储库B中,我可以安全地
rm -rf ../a
,然后git checkout remotes/origin/mybranch
,我将拥有file_mybranch
。 What I want is to have this commit in repository C . 我想要的是在存储库C中进行此提交。 My question is: how can I get the branch
remotes/origin/mybranch
from B into C along with the commits it points to? 我的问题是: 如何从B将分支的
remotes/origin/mybranch
指向的提交放入C ? Lets say I've already deleted A . 可以说我已经删除了A。
There is clearly a serious Git Naming Problem here because this problem trips people up all the time . 显然有严重的Git命名问题在这里,因为这个问题旅行的人所有的时间 。 The fundamental issue is that the word "branch" is confusing.
根本问题是“分支”一词令人困惑。 It doesn't mean what you think it does!
这并不意味着您认为它有用! See also What exactly do we mean by "branch"?
另请参见“分支”到底是什么意思?
When you clone a repository using git clone <url>
or git clone <path>
or similar, you don't get an exact copy of the upstream repository. 当您使用
git clone <url>
或git clone <path>
或类似方法克隆存储库时,您不会获得上游存储库的确切副本。 You get, instead, a copy with some deliberate changes: 相反,您会得到一份经过一些故意更改的副本:
origin
, set to hold the URL of the original. origin
,设置为保存原始URL。 git checkout somebranch
. git checkout somebranch
的等效git checkout somebranch
。 The name git clone
gives to this git checkout
command depends on several somewhat tricky things. git clone
这个git checkout
命令的名字取决于一些棘手的事情。 The specific set of RTBs you get depends on what branches there are in the repository you're cloning. 您获得的特定RTB 集取决于您要克隆的存储库中的哪些分支 。 Let's say that the repository you're cloning has three actual branches, named
master
, develop
, and mybranch
. 假设您要克隆的存储库具有三个实际分支,分别称为
master
, develop
和mybranch
。 This means you get, in your clone-imperfect-copy, three of these RTB thingies (which aren't branches), named origin/master
, origin/develop
, and origin/mybranch
. 这意味着,在克隆不完善的副本中,您将获得其中三个RTB事物(不是分支),它们分别是
origin/master
, origin/develop
和origin/mybranch
。
git checkout
command will create branches automatically git checkout
命令将自动创建分支 Let's say you have a repository that has no branches at all, like one of the ones made by git clone
, and you pick a branch name out of a hat-full of possible names: master
, develop
, and mybranch
. 假设您有一个完全没有分支的存储库,例如
git clone
创建的分支之一,并且从一顶帽子中挑选了一个分支名称,其中包括可能的名称: master
, develop
和mybranch
。 For the sake of realism, let's use the one Git usually picks, master
. 为了真实起见,让我们使用Git通常选择的
master
。 You convince your git clone
command to pass this name to git checkout
: 您说服
git clone
命令将此名称传递给git checkout
:
git checkout master
Now, the thing is, there is no master
branch because there are no branches at all. 现在,问题是, 没有
master
分支,因为根本没有分支。 So Git can't possibly check it out. 因此,Git无法将其检出。 But—this is the first tricky part—your Git can scan through all your RTBs, looking for one whose name resembles
master
. 但是,这是第一个棘手的部分,您的Git 可以扫描您所有的实时出价,寻找名称类似于
master
实时出价。 And there it is: origin/master
smells enough like master
, that your Git goes and creates a new branch in your copy, called master
, using origin/master
as the hash ID for this new branch. 就是这样:
origin/master
闻起来像master
一样,Git会在副本中创建一个新的分支,称为master
,使用origin/master
作为该新分支的哈希ID。
That's the final step of git clone
: it checks out some branch, and winds up creating that branch in the process. 那是
git clone
的最后一步:它签出一些分支,并在此过程中最终创建该分支。 You can choose which branch, using -b
, but you only get one name: you can have your Git run git checkout master
, or you can have your Git run git checkout mybranch
, but you cannot have it run both. 您可以使用
-b
选择哪个分支,但只有一个名称:您可以让Git运行git checkout master
,也可以让Git运行git checkout mybranch
,但不能同时运行它们。 You only get one! 你只有一个!
If you don't give a -b
argument, your Git picks one out of the hat-full of branch names it saw on the other Git. 如果不提供
-b
参数,则您的Git会从在另一个Git上看到的完整分支名称中选择一个。 It usually picks master
, but there are rules by which the other Git gives your Git a hint which name to pick. 它通常采
master
,但也有通过其他的Git给你的Git暗示这名挑规则。 The most important rule is that your Git asks the other Git which branch it has checked-out (or more precisely, inspects its HEAD
setting). 最重要的规则是,你的Git会询问哪些分支已经签出了其他的Git(或者更准确地说,检查其
HEAD
设置)。
If you use git clone --mirror
, you will get a perfect copy. 如果使用
git clone --mirror
,则将获得完美的副本。 The problem is that this perfect copy has no work-tree: it's what Git calls a "bare" clone. 问题在于,这个完美的副本没有工作树:这就是Git所说的“裸”克隆。
The reason for this is that such a clone is set up to be a slavish copy all the time : every time you run git fetch
in the mirror clone, you update it to exactly match whatever is in the other repository. 这样做的原因是,这样的克隆被设置成为一个盲目的复制所有的时间 :每次运行时
git fetch
镜中的克隆,你更新它完全匹配无论是在其他存储库。 This means you throw away any work being done on any branch, and slavishly match the other repository's branches again. 这意味着您将放弃在任何分支上完成的所有工作,并再次奴隶地匹配另一个存储库的分支。 To make sure you don't lose work this way, Git prevents you from doing work in the exact-copy.
为了确保您不会丢失这种工作,Git会阻止您使用精确副本进行工作。
When you clone, you get that imperfect copy, and your Git checks out one branch, copying it from the RTBs your Git made by renaming all of their branches. 克隆时,您会得到不完美的副本,Git会签出一个分支,并通过重命名所有分支来从Git制作的RTB复制该分支。
You can now run git checkout
on each of those remaining RTBs—all but the one that git clone
already ran git checkout
on, that is. 现在,您可以在其余所有RTB上运行
git checkout
,也就是说,除了git clone
已对其运行git checkout
RTB之外的所有RTB。 The easiest thing is to just run it on all the names: it doesn't hurt to run git checkout master
again, after all. 最简单的方法是仅对所有名称运行它:毕竟再次运行
git checkout master
并没有什么坏处。
To extract all the names, you can use git for-each-ref
(meant for scripting) or git branch -r
(not so much). 要提取所有名称,您可以使用
git for-each-ref
(脚本的意思是)或git branch -r
(不是很多)。 You will have to massage the names a bit to strip off the origin/
part, and run git checkout
. 您将需要按摩一下名称以去除
origin/
零件,然后运行git checkout
。
(Or, you can simply not bother to check them out until you need them. Don't re-clone the imperfect copy: re-clone the original—assuming you still have and can reach it.) (或者,您可以简单地在需要它们之前就不花心去检查它们。不要重新克隆不完美的副本:重新克隆原件-假设您仍然有并且可以拿到它。)
If you still have the copy, but not the original, and want a second copy that's exactly like the first copy—down to having the same branches and the same RTBs—you need to use one or more tricks, because Git is not set up to do that. 如果您仍然有副本,但没有原始副本,并且想要第二个副本与第一个副本完全相同 (直到拥有相同的分支和相同的实时出价),则需要使用一个或多个技巧,因为未设置Git要做到这一点。 One trick is to make a mirror clone anyway:
一个诀窍是无论如何都要进行镜像克隆:
$ git clone --mirror url-of-copy mirror-clone-dir
Now you have an exact duplicate of the copy, except that your duplicate itself is a bare clone. 现在,您具有该副本的完全相同的副本,只是副本本身是一个空克隆。 You can now convert it from a bare clone to a non-bare clone (see, eg, How do I convert a bare git repository into a normal one (in-place)? ), but you should also update its
remote.origin.fetch
setting: 现在,您可以将其从裸克隆转换为非裸克隆(例如,请参见如何将裸git存储库转换为普通的(就地)存储库? ),但是还应该更新其
remote.origin.fetch
设置:
$ cd mirror-clone-dir
$ git config --get remote.origin.fetch
+refs/*:refs/*
$ git config remote.origin.fetch '+refs/heads/*:refs/remotes/origin/*'
(and then the rest of the conversion). (然后是其余的转换)。 Or, you can start with a normal clone, but then run one more command:
或者,您可以从普通克隆开始,然后再运行一个命令:
$ git clone <url-of-copy> new-clone-dir
[the usual messages]
$ cd new-clone-dir
$ git fetch origin '+refs/remotes/origin/*:refs/remotes/origin/*'
Note that this last step will replace all your existing remote-tracking branches ("RTBs") with the copy's remote-tracking branches. 请注意,最后一步将用副本的远程跟踪分支替换所有现有的远程跟踪分支(“ RTB”)。 In other words, you lose the memory of the copy 's branches, replacing your Git's "memory of what I saw in url-of-copy" with "memory of what I got from url-of-copy that they had listed as their memory of what they saw in their original."
换句话说,您失去了副本分支的记忆,将Git的“我在url副本中看到的内容”替换为“我从url副本中获得的内容, 它们已被列为它们的内存”。记住他们在原始作品中看到的内容 。”
You literally cannot get both, at least not using these RTBs: either you have your branches and remember their branches, or you have your branches and remember their memory of someone else's branches. 从字面上看,您不能同时获得两者,至少不能使用这些实时出价工具:要么拥有分支并记住他们的分支,要么拥有分支并记住他们对别人分支的记忆。 You do have some additional alternatives, though:
但是,您确实还有一些其他选择:
If the real original still lives, add it as second remote, and fetch from it: 如果真正的原件仍然存在,请将其添加为第二个遥控器,然后从中获取:
$ git remote add real-source <url> $ git fetch real-source
Now you have not just origin/master
but also real-source/master
. 现在您不仅拥有
origin/master
而且拥有real-source/master
。
If not, add the copy as a second remote—there's no harm in having two names for the same repository—and then use the same git fetch
trick to populate the additional set of RTBs from the copy: 如果不是这样,则将副本添加为第二个远程对象(在相同的存储库中使用两个名称没有什么害处),然后使用相同的
git fetch
技巧从副本中填充其他RTB集:
$ git remote add r2 <url-of-copy> $ git fetch r2 '+refs/remotes/origin/*:refs/remotes/r2/*'
Now you have two remotes: origin/master
remembers " master
as seen on origin, renamed to origin/master
" and r2/master
remembers "origin/master as seen on r2 (same URL as origin), renamed to r2/master
". 现在,您有两个远程
origin/master
: origin/master
记住“在来源上看到的master
,重命名为origin/master
”,而r2/master
记住“在r2上看到的origin / master(与URL相同的URL),重命名为r2/master
”。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.