简体   繁体   English

遥控器的“ git fetch”遥控器

[英]“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"? 另请参见“分支”到底是什么意思?

A clone is a deliberately imperfect copy 克隆是故意不完美的副本

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: 相反,您会得到一份经过一些故意更改的副本:

  • The new copy has a remote , usually named origin , set to hold the URL of the original. 新副本具有一个远程文件 (通常命名为origin ,设置为保存原始URL。
  • The new copy takes all the branches from the original, but none of its remote-tracking branches . 新的副本取走了原始副本的所有分支 ,但没有一个远程跟踪分支 Despite the name "remote-tracking branch", these things are not branches! 尽管名称为“远程跟踪分支”,但这些不是分支! Git could call them "elephants" and it would probably be less confusing. Git可以称它们为“大象”,这可能会减少混乱。 :-) Let's call them RTBs here, just so that they do not have the word "branch" in them. :-)在这里我们称它们为RTB ,只是为了使它们中没有单词“ branch”。
  • The new copy starts out, in fact, with no branches at all , but then immediately does the equivalent of 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 new clone does start out with a bunch of RTBs. 新的克隆确实从大量RTB开始。 These are not branches, remember. 请记住,这些不是分支机构。 They're these funny RTB things. 他们是这些有趣的实时出价工具。 RTBs are names that start with the same string as the remote, and then have a slash. RTB是以与遥控器相同的字符串开头,然后带有斜杠的名称。

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 . 假设您要克隆的存储库具有三个实际分支,分别称为masterdevelopmybranch 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/masterorigin/developorigin/mybranch

The 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创建的分支之一,并且从一顶帽子中挑选了一个分支名称,其中包括可能的名称: masterdevelopmybranch 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设置)。

There are ways to make a more-perfect clone, but then you can't use it 有很多方法可以制作出更完美的克隆,但是您不能使用

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会阻止您使用精确副本进行工作。

The solution is to put up with the imperfections 解决的办法是忍受缺陷

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/masterorigin/master记住“在来源上看到的master ,重命名为origin/master ”,而r2/master记住“在r2上看到的origin / master(与URL相同的URL),重命名为r2/master ”。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

相关问题 git delete remotes:远程引用不存在 - git delete remotes: remote refs do not exist git fetch不会更新.git / refs / remotes / origin / master - git fetch does not update .git/refs/remotes/origin/master 为什么 git remote sill 的旧名称在 .git/refs/remotes 中? - Why is old name of git remote sill in .git/refs/remotes? git fetch失败“refs / remotes / origin / pr / 34跟踪两者” - git fetch failed “refs/remotes/origin/pr/34 tracks both” git remote 用于获取和推送的不同遥控器 - git remote different remotes for fetch and push 致命:refspec的远程部分不是.git / refs / heads / master中的有效名称:.git / refs / remotes / origin / master - fatal: remote part of refspec is not a valid name in .git/refs/heads/master:.git/refs/remotes/origin/master Git远程命令返回致命:无效的refspec + refs / heads / *:refs / remotes /:origin / * - Git remote command returns fatal: Invalid refspec +refs/heads/*:refs/remotes/:origin/* git fetch不获取远程分支-如何获取所有远程 - git fetch not fetching remote branches - how to fetch all remotes GIT从远程跟踪中删除FETCH引用 - GIT Removing FETCH refs from remote tracking 为什么git fetch origin + refs / heads / master:refs / remotes / origin / mymaster和git fetch origin master:mymaster的行为不同? - Why behaviour of git fetch origin +refs/heads/master:refs/remotes/origin/mymaster and git fetch origin master:mymaster is different?
 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM