" git fetch"远程遥控器

时间:2017-07-24 21:34:17

标签: git

我希望能够将所有正在进行的工作分支从存储库移动到存储库,并且能够删除旧的分支而不会丢失任何提交。有没有办法从远程存储库中获取远程分支?

# 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

重申一下,在存储库 B 中,我可以安全地rm -rf ../a,然后git checkout remotes/origin/mybranch,我将file_mybranch。我想要的是在存储库 C 中进行此提交。我的问题是:我怎样才能将 B 中的分支remotes/origin/mybranch C 一起提交给它?让我们说我已经删除 A

1 个答案:

答案 0 :(得分:0)

这里显然存在一个严重的Git命名问题,因为这个问题会让人们一直绊倒。根本问题是“" branch"令人困惑。它并不意味着你的想法!另请参阅What exactly do we mean by "branch"?

克隆是故意不完美的副本

使用git clone <url>git clone <path>或类似方法克隆存储库时,您无法获得上游存储库的精确副本。相反,你会得到一份经过深思熟虑改变的副本:

  • 新副本有一个远程,通常名为origin,设置为保存原始网址。
  • 新副本从原始文件中获取所有分支,但没有远程跟踪分支。尽管名称&#34;远程跟踪分支&#34;,这些东西是分支! Git可以打电话给他们&#34;大象&#34;它可能不那么令人困惑。 :-)让我们在这里称他们为 RTBs ,只是为了让他们没有&#34; branch&#34;在他们中。
  • 事实上,新副本开始时根本没有分支,但是立即开始相当于git checkout somebranch。名称git clone赋予此git checkout命令取决于几个有点棘手的事情。
  • 新的克隆 从一堆RTB开始。记住,这些不是分支。他们是这些有趣的RTB事物。 RTB是以与远程相同的字符串开头的名称,然后是斜杠。

您获得的RTB的特定取决于您正在克隆的存储库中的分支。我们假设您正在克隆的存储库有三个实际分支,名为masterdevelopmybranch。这意味着您可以在克隆不完美副本中获得三个RTB内容(不是分支),名为origin/masterorigin/developorigin/mybranch

git checkout命令将自动创建分支

假设你有一个根本没有分支的存储库,就像git clone所做的那个,你从一个充满可能名称的帽子中选择一个分支名称:{ {1}},masterdevelop。为了现实,让我们使用Git通常选择的mybranch。您说服您的master命令将此名称传递给git clone

git checkout

现在,事情是,没有git checkout master 分支,因为根本没有分支。所以Git无法检查出来。但是 - 这是第一个棘手的部分 - 您的Git 可以扫描所有RTB,寻找名称​​类似于 master的RTB。它是:master闻起来像origin/master,你的Git去了,在你的副本中创建一个新的分支,称为{{1使用master作为此新分支的哈希ID。

这是master的最后一步:它检查了一些分支,然后结束创建该分支。您可以使用origin/master选择哪个分支,但只能获得一个名称:您可以让Git运行git clone,或者您可以让Git运行{{1}但是你不能让它同时运行。你只得到一个!

如果你没有给出-b论证,那么你的Git会从另一个Git中看到的分支名称中选出一个。它通常会选择git checkout master,但是有一些规则可以让其他 Git给你的Git一个提示选择的名称。最重要的规则是你的Git要求另一个Git哪个分支已经签出(或者更确切地说,检查它的git checkout mybranch设置)。

有一些方法可以制作更完美的克隆,但是你无法使用

如果您使用-b,您将获得完美的副本。问题是这个完美的副本没有工作树:它是Git所称的&#34;裸&#34;克隆

原因是这样的克隆被设置为一直是的盲目副本:每次在镜像克隆中运行master时,都会将其更新为匹配其他存储库中的任何内容。这意味着你丢弃在任何分支上完成的任何工作,并再次与其他存储库的分支进行盲目匹配。为确保您不会以这种方式失去工作,Git会阻止您在正确副本中执行工作。

解决方案是忍受不完善

当您克隆时,您会获得不完美的副本,并且您的Git会检出一个分支,将其从您的Git通过重命名所有分支的RTB中复制。

现在,您可以在剩余的每个RTB上运行HEAD - 除了git clone --mirror已经运行git fetch之外的所有RTB,就是这样。最简单的方法是在所有名称上运行它:毕竟再次运行git checkout并不会有什么坏处。

要提取所有名称,您可以使用git clone(用于编写脚本)或git checkout(不是那么多)。您需要按一下名称来剥离git checkout master部分,然后运行git for-each-ref

(或者,在你需要它们之前,你根本不用费心去检查它们。不要重新克隆不完美的副本:重新克隆原始文件 - 假设你仍然拥有并且可以到达它。)

如果您仍然拥有副本,但不是原始副本,并且希望第二个副本完全像第一个副本一样具有相同的分支和相同的RTB-您需要使用一个或多个技巧,因为Git没有设置这样做。一个技巧是制作镜像克隆:

git branch -r

现在你有一个完全相同的副本,除了你的副本本身是一个裸克隆。您现在可以将其从裸克隆转换为非裸克隆(请参阅,例如How do I convert a bare git repository into a normal one (in-place)?),但您还应更新其origin/设置:

git checkout

(然后转换的其余部分)。或者,您可以从普通克隆开始,然后再运行一个命令:

$ git clone --mirror url-of-copy mirror-clone-dir

请注意,最后一步将使用副本的远程跟踪分支替换所有现有远程跟踪分支(&#34; RTB&#34;)。换句话说,你失去了对 copy 分支机构的记忆,取代了我在gl-of-copy&#34;中所看到的Git&#34;记忆。记录了我从他们他们列出的他们的记录他们在<他们的原创。&#34;

你真的不能同时获得这两个,至少不能使用这些 RTB:要么你有你的分支并记住他们的分支,要么你有你的分支并记住他们对别人的分支的记忆。不过你确实有其他选择:

  • 如果真实原件仍然存在,请将其添加为第二个遥控器,然后从中取出:

    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/*' 而且还$ git clone <url-of-copy> new-clone-dir [the usual messages] $ cd new-clone-dir $ git fetch origin '+refs/remotes/origin/*:refs/remotes/origin/*'

  • 如果没有,请将副本添加为第二个远程 - 同一个存储库有两个名称没有坏处 - 然后使用相同的$ git remote add real-source <url> $ git fetch real-source 从副本填充附加RTB集的技巧:

    origin/master

    现在您有两个遥控器:real-source/master会记住&#34; git fetch,如原点所示,重命名为$ git remote add r2 <url-of-copy> $ git fetch r2 '+refs/remotes/origin/*:refs/remotes/r2/*' &#34;和origin/master记住&#34;来源/主人在r2上看到(与原点相同的网址),重命名为master&#34;。