如何克隆,然后与上游主服务器同步/更新/推送分叉

时间:2018-06-28 19:10:43

标签: git github git-clone git-checkout git-fetch

我认为我已经阅读了一些教程,并且坚持使用完全基础的东西(我几乎从不使用命令行git,所以请耐心;))。

我要做的就是从上游存储库中将fork(https://github.com/abelbraaksma/visualfsharp)更新为最新版本的Master(https://github.com/Microsoft/visualfsharp)。由于我不关心本地更改,因此我决定创建一个新的克隆(以前我使用过GUI工具,但是它们是如此混乱和局限,以至于我放弃了它,而跳入git命令的树林;)。

我做到了:

cd /D/Projects/OpenSource/VisualFSharp2
git init
git clone https://github.com/abelbraaksma/visualfsharp
git fetch https://github.com/Microsoft/visualfsharp
git remote add upstream https://github.com/Microsoft/visualfsharp
git remote add origin https://github.com/abelbraaksma/visualfsharp
git fetch upstream
git checkout master
git merge upstream/master

最后两个命令给出:

  

git checkout master
  已经在“主人”上
  您的分支机构的最新信息是“上游/母版”。

     

git merge upstream/master
  已经是最新的。

我意识到我做错了一些事情,并且由于我来自SVN和Mercurial世界,所以我经常对术语感到困惑。

我知道目前我是上游仓库的“主管”。但是我需要将上游回购合并到原始(我的fork)回购中。我假设我需要将本地副本更新为我的叉子的头部(但是git checkout master不会这样做)。

我基本上是尝试将this guide on syncingconfiguring remote points结合使用。

我在哪里感到困惑或更好,我得到了哪些命令?

git remote -v给我:

origin  https://github.com/abelbraaksma/visualfsharp (fetch)  
origin  https://github.com/abelbraaksma/visualfsharp (push)  
upstream        https://github.com/Microsoft/visualfsharp (fetch)  
upstream        https://github.com/Microsoft/visualfsharp (push)

2 个答案:

答案 0 :(得分:2)

TL; DR

您还可以,但是您还有一个额外的存储库,您可能应该删除它。通常,您应该首先克隆(使用git clone),让您的Git调用origin,然后git remote add upstream <the other url>并从那里开始工作。

阅读下面的详细说明,以了解您现在拥有的内容以及如何使用它。

长:您做了什么,详细

git init

这将在当前目录中创建一个新的空Git存储库。 (如果这里已经有一个Git储存库-如果git rev-parse --git-dir会打印一些目录名,而不是失败并说“我找不到储存库”,则它基本上什么也不做,因此可以安全运行。由于您打算克隆存储库,因此您实际上并不想这样做,因为git clone 也会执行{{1} },我们稍后会看到。

在继续下面的git init之前,让我们花点时间记录一下新的空存储库的怪异状态。您现在可能已经熟悉这样的想法,即像git clone这样的分支名称实际上仅持有一(1)个提交的哈希ID。 Git使用该名称在分支上找到 last 提交,Git将其称为 tip commit 。然后,Git使用技巧提交来查找先前的提交或 parent 提交,并使用父级的父级回顾历史。通过跟踪父链,Git从分支名称中找到所有可达的提交。

但是空的存储库没有提交。名称master不能指向master指向-master中没有最新提交,其哈希ID可以存储在名称master下。 Git的解决方案是还没有一个master分支。同时,如master所说,Git声明您在“分支主服务器上” —因此,您在尚不存在的分支上

此怪异因素会在以后出现。现在,让我们继续进行git status,然后看看它的作用。在这种情况下,它将创建另一个单独的存储库,您随后将不再使用它。

git clone

这基本上等同于一系列命令:

  • git clone https://github.com/abelbraaksma/visualfsharp :在当前目录(当前为mkdir visualfsharp)中创建一个新的子目录
  • /D/Projects/OpenSource/VisualFSharp2:输入新的子目录
  • cd visualfsharp:添加名为git remote add origin https://github.com/abelbraaksma/visualfsharp的遥控器(这也会为其配置一些设置)
  • origin:获取所有提交内容
  • git fetch origin,其中 git checkout somebranch 通常为somebranch:从master名称之一创建本地分支名称,并使其成为当前分支。

完成这些操作后,您将返回到原始目录(即,仍为origin/*)。请注意,您的原始目录是一个Git存储库,而其/D/Projects/OpenSource/VisualFSharp2子目录是另一个。

我们现在将看到您再次执行这些命令中的大多数命令,但是这次将其应用于您当前为空的存储库,该存储库处于您处于visualfsharp但{{1 }}不存在。

master

这将调用master处的Git,并从它们中获取提交和其他对象,并将其提交到以前为空的存储库中(而不是刚刚创建的克隆!)。就像git fetch https://github.com/Microsoft/visualfsharp 一样,除了没有远程跟踪名称(没有https://github.com/Microsoft/visualfsharpgit fetch remote)之外,因为没有远程可用于构造这样的名称。 origin/*的这种特殊形式可以追溯到upstream/*发明之前的远古时代(2005年),也许永远不要使用它。这不是有害,在这里也不是有用

git fetch

这些很好:他们设置了两个远程。遥控器只是一个简称:

  • 保存URL,然后
  • 分别提供远程跟踪名称的前导部分git remotegit remote add upstream https://github.com/Microsoft/visualfsharp git remote add origin https://github.com/abelbraaksma/visualfsharp
upstream/*

这几乎是您先前的origin/*的重复。但是,这次,您的Git使用您分配的名称git fetch upstream 来获取URL。因此,您的Git再次调用git fetch上的Git。自上次获取以来,您的Git从它们获取任何新提交(以及与这些提交一起进行的任何其他必要的Git对象)-可能没有,这取决于您在第一次获取和第二次获取之间相隔了多长时间。如果您没有运行早期的upstream,则将在获取所有提交的同时获取每个Git对象。

但是现在,有了提交之后,就存在一个关键的区别:您的Git会使用所有分支名称,并将其重命名为拼写为https://github.com/Microsoft/visualfsharp的远程跟踪名称。它现在可以执行此操作,因为现在您使用的是远程URL,而不仅仅是原始URL。遥控器-文字字符串git fetch-为您重命名。 1 因此,您的Git及其Git可以非常快速地传输所有新对象(可能没有),然后Git进行设置您的upstream/whatever等,基于他们的upstream等。

upstream/master

这是存储库的怪异状态出现的地方。您的Git会说:

master

发生了什么事,git checkout master 寻找了Branch master set up to track remote branch master from upstream. Already on 'master' ,并且找不到它(因为您没有分支),所以它创建了一个。首先,它会查看您所有的远程跟踪名称,在这种情况下为git checkout。它找到了一个匹配的:masterupstream/*。因此,它创建了您的master,并指向与您的upstream/master相同的提交。然后,它还将您的master设置为upstream/master作为其上游设置。

完成所有操作后-创建master-upstream/master试图将您放到master上,发现您只是在git checkout上并打印出令人困惑的内容“已经开始”消息。尽管如此,它还是在过程中正确地连接了HEAD,签出了所有文件,即将它们复制到索引和工作树中。

您可能希望或不希望您的master设置为这种方式-一旦您完成操作,您就更可能希望master指向与master相同的提交创建master,并将origin/master设置为其上游。有关上游是什么的更多信息,即,将一个分支设置为 track 2 意味着另一个分支,请参见my answer到{{ 3}}。

您在这里的最后一条命令是:

origin/master

您的origin/master刚从您的git merge upstream/master 中创建,因此没有任何可合并的地方:这两个名称都指向相同的提交哈希ID。

您尚未从master获取任何信息。您现在可能应该这样做:

upstream/master

完成后,您将同时拥有origingit fetch origin 3 如我所愿,如果您希望拥有自己的origin/master音轨upstream/master而非master(并从那里开始),您应该:

  1. 确保没有要提交的内容(不应给出上述顺序,但是使用origin/master之前检查总是明智的做法);
  2. 运行upstream/master,使您的git reset --hard指向与git reset --hard origin/master相同的提交;和
  3. 运行master更改上游设置。

现在,您可以运行origin/master。如果上游在您进行了自己的分叉之后有了新的提交,则将合并这些提交,如果需要,可以使用完全合并,或者如果可能的话,使用快进非真正合并操作。

无论如何,您可能想要删除额外的存储库。


1 Git实现此重命名的基本机制非常复杂,可能是出于历史原因,但在正常实践中,它只是“将其git branch --set-upstream-to=origin/master master更改为您的git merge upstream/master等等。

2 请注意,Git在这里使用了更加混乱的术语:如果分支名称​​ tracks 远程跟踪名称(这是本地您的Git创建的名称基于在另一个Git中找到的名称,该名称的URL是通过 remote 找到的,然后我们将该分支称为(或分支名称)为上游。这与跟踪文件和未跟踪文件完全不同。 kes!

3 我在这里假设master上的Git存储库是您自己的,并且您是使用其Web GUI界面中GitHub的“ fork存储库” clicky按钮创建的。当您这样做时,GitHub在GitHub本身上做了一个稍微复杂的remote/master,可以从您选择的任何源存储库中创建存储库。这意味着您的GitHub存储库具有与原始源存储库相同的所有分支。

(克隆的GitHub不会重命名分支。它还具有特殊的仅限GitHub的功能,以允许GitHub提供的拉取请求工具;这不是Git的一部分。GitHub伙计们还安排共享以下内容:将磁盘对象隐藏在幕后,并具有各种其他技巧,使其比天真地完成时要快得多。因此,它在原理上是常规克隆 ,但他们已经对其进行了调整通过他们的Web界面更有用。这就是他们让您使用GitHub的方法,而不仅仅是您自己做。)

答案 1 :(得分:2)

我所做的事情与您所做的非常相似,这是我的工作方式:

  1. 获取叉子的网址。
  2. 切换到终端。 cd到我们要克隆的目录。
  3. git clone fork-url-here将克隆我们的fork并将其设置为remote/origin
  4. cd fork-name/更改为克隆目录。
  5. git remote add upstream upstream-url-here会将上游设置为remote/upstream
  6. git fetch upstream从上游获取所有分支
  7. git checkout master,因为我们已经在原始/母版上,所以会收到一条消息,通知我们相同的信息。因此,一切都很好,这不是表明存在问题。
  8. git branch -a列出所有本地+ remote/origin/* + remote/upstream/*分支。其中一个将是upstream/master(最初,我使用git branch仅显示本地分支,这让我有些困惑,因为我在列表中看不到upstream/master)。
  9. git merge upstream/master,这会将upstream/master分支合并到您当前的分支origin/master中,从而同步到上游。

您遇到的问题是因为在将上游作为远程对象添加之前,您要从上游获取它(代码块的第四行)。这将阻止您从上游获取所有分支。其他事情对我来说很好。

PS:我可以看到这是一个老问题,但是我只是想我可以帮助git初学者(像我一样),他们可能会急于使用并且无法阅读torek给出的非常好的和有益的答案。