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

Abe*_*bel 4 git github git-fetch git-clone git-checkout

我想我已经阅读了一些教程,但我仍然停留在一些完全基本的东西上(我几乎从不使用命令行 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
Run Code Online (Sandbox Code Playgroud)

最后两个命令给出:

git checkout master
已经在“master”上
您的分支已更新为“upstream/master”。

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

我意识到我做了一些事情的顺序是错误的,而且由于我来自 SVN 和 Mercurial 世界,我经常对术语感到困惑。

我知道目前我处于上游仓库的“master”状态。但我需要从上游存储库合并到原始(我的分支)存储库中。我认为我需要将本地副本更新为我的叉子的头部(但git checkout master没有这样做)。

我基本上尝试遵循本同步指南,并结合配置远程点

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

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)
Run Code Online (Sandbox Code Playgroud)

tor*_*rek 7

长话短说

\n\n

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

\n\n

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

\n\n

Long:详细说明一下你做了什么

\n\n
\n
git init\n
Run Code Online (Sandbox Code Playgroud)\n
\n\n

这将在当前目录中创建一个新的空 Git 存储库。(如果这里已经有一个 Git 存储库 \xe2\x80\x94ifgit rev-parse --git-dir会打印一些目录名称,而不是失败并说“我找不到存储库”\xe2\x80\x94 它基本上什么都不做,使其可以安全运行。这里有一些极端情况,但您不太可能遇到它们。)由于您打算克隆存储库,所以您实际上并不希望这样做,因为agit clone git init这样做,正如我们稍后将看到的。

\n\n

在继续git clone下面的内容之前,让我们花点时间记录一下新的空存储库的奇怪状态。您现在可能已经熟悉这样的想法:分支名称master实际上只保存一 (1) 次提交的哈希 ID。Git 使用该名称来查找分支上的最后一次提交,Git 将其称为提示提交。然后,Git 使用提示提交来查找上一个提交或提交,并使用父提交的父提交来回溯历史记录。通过跟踪父级链,Git 找到可从分支名称访问的所有提交。

\n\n

但是空的存储库没有提交。没有提示master名称master指向\xe2\x80\x94no 最新提交,master其哈希 ID 可以存储在名称下master。Git 的解决方案是还没有分支master。同时,Git 声明您位于“主分支”,即git status\xe2\x80\x94,因此您位于尚不存在的分支上

\n\n

这种奇怪的因素后来才会出现。现在,让我们转到git clone,看看它做了什么。在这种情况下,它会创建另一个单独的存储库,您随后根本不会使用它。

\n\n
\n
git clone https://github.com/abelbraaksma/visualfsharp\n
Run Code Online (Sandbox Code Playgroud)\n
\n\n

这基本上相当于一系列命令:

\n\n
    \n
  • mkdir visualfsharp/D/Projects/OpenSource/VisualFSharp2:在当前目录(当前目录)内创建一个新的子目录
  • \n
  • cd visualfsharp:进入新的子目录
  • \n
  • git remote add origin https://github.com/abelbraaksma/visualfsharp:添加名为的远程origin(这也会为其配置一些设置)
  • \n
  • git fetch origin:获取他们的所有提交
  • \n
  • git checkout somebranch,其中somebranch通常master:从其中一个名称创建本地分支名称origin/*,并将其设为当前分支。
  • \n
\n\n

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

\n\n

我们现在将看到您再次执行大部分命令,但这一次,应用于您当前为空的存储库,该存储库处于您打开mastermaster不存在的奇怪状态。

\n\n
\n
git fetch https://github.com/Microsoft/visualfsharp\n
Run Code Online (Sandbox Code Playgroud)\n
\n\n

这会调用 Git athttps://github.com/Microsoft/visualfsharp并从中获取提交和其他对象,并将其放入您之前为空的存储库(不是您刚刚创建的克隆!)。就像除了没有远程跟踪名称 \xe2\x80\x94no或\xe2\x80\x94 一样,因为没有远程可用于构造此类名称。这种特殊形式可以追溯到远古时代(2005 年),在 发明之前,人们可能永远不应该使用它。它没有害处,只是在这里也没有帮助git fetch remoteorigin/*upstream/*git fetchgit remote

\n\n
\n
git remote add upstream https://github.com/Microsoft/visualfsharp\ngit remote add origin https://github.com/abelbraaksma/visualfsharp\n
Run Code Online (Sandbox Code Playgroud)\n
\n\n

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

\n\n
    \n
  • 保存 URL,并且
  • \n
  • 分别提供远程跟踪名称的前导部分upstream/*和。origin/*
  • \n
\n\n
\n
git fetch upstream\n
Run Code Online (Sandbox Code Playgroud)\n
\n\n

几乎是您之前的重复git fetch。不过,这一次,您的 Git 使用您分配的名称 \xe2\x80\x94 upstream\xe2\x80\x94 来获取 URL。所以你的 Git 再次调用 Git at https://github.com/Microsoft/visualfsharp。自上次 fetch\xe2\x80\x94 以来,你的 Git 从它们那里获取任何新的提交(以及与这些提交一起使用的任何其他必要的 Git 对象),可能没有,具体取决于第一次获取和第二次获取之间的时间间隔。如果您没有运行之前的git fetch,这将在获取所有提交的同时获取每个 Git 对象。

\n\n

但现在,在获得提交后,有一个关键的区别:您的 Git 获取所有分支名称并将它们重命名为拼写为 的远程跟踪名称。它现在可以做到这一点,因为现在您使用的是远程,而不仅仅是原始 URL。远程\xe2\x80\x94文字字符串\xe2\x80\x94可以让你重命名。1 因此,你的 Git 和他们的 Git 非常快速地传输所有新对象(可能没有),然后你的 Git根据他们的等等设置你的等等。upstream/whateverupstreamupstream/mastermaster

\n\n
\n
git checkout master\n
Run Code Online (Sandbox Code Playgroud)\n
\n\n

这就是存储库奇怪状态出现的地方。你的 Git 会说:

\n\n
Branch master set up to track remote branch master from upstream.\nAlready on \'master\'\n
Run Code Online (Sandbox Code Playgroud)\n\n

发生的事情是git checkout寻找master没有找到它(因为你没有分支),所以它创建了一个。首先,在本例中,它会查看您所有的远程跟踪名称upstream/*。它找到了一个匹配的:mastervs upstream/master。所以它创建了你的master,指向与你的相同的提交upstream/master。然后,它还将您设置masterupstream/master上游设置

\n\n

完成所有这些之后\xe2\x80\x94创建你的master\xe2\x80\x94git checkout试图将你放入你的master,并发现你只在你的master并打印了令人困惑的“已经开启”消息。尽管如此,它仍然在此过程中正确附加了您的 HEAD,检查所有文件,即将它们复制到索引和工作树。

\n\n

您可能希望也可能不希望以这种方式进行设置\xe2\x80\x94 ,一旦您创建了 ,master您更有可能希望您master开始指向与 相同的提交,并将其设置为其上游。有关上游是什么的更多信息\xe2\x80\x94,即,将一个分支设置为跟踪2 个另一个分支\xe2\x80\x94意味着什么,请参阅我如何设置分支的多个跟踪级别的回答与 gitorigin/masterorigin/masterorigin/master

\n\n

您的最后一个命令是:

\n\n
\n
git merge upstream/master\n
Run Code Online (Sandbox Code Playgroud)\n
\n\n

您自己的名称master刚刚您的中创建upstream/master,因此无需合并:两个名称都指向相同的提交哈希 ID。

\n\n

您还没有从您的 中获取任何内容origin。你现在可能应该这样做:

\n\n
git fetch origin\n
Run Code Online (Sandbox Code Playgroud)\n\n

一旦你这样做了,你将拥有origin/master以及upstream/master3 如果你像我怀疑的那样希望有自己的master轨道origin/master而不是upstream/master(并从那里开始),你应该:

\n\n
    \n
  1. 确保没有任何需要提交的内容(不应给出上述顺序,但在使用之前检查总是明智的git reset --hard);
  2. \n
  3. rungit reset --hard origin/master以使您的master观点与origin/master;相同的提交 和
  4. \n
  5. 运行git branch --set-upstream-to=origin/master master以更改上游设置。
  6. \n
\n\n

现在你可以运行了git merge upstream/master。如果自您自己的分叉发生以来上游有新的提交,那么将合并这些提交,如果需要,使用完整合并,或者如果可能,使用快进非真正合并操作。

\n\n

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

\n\n
\n\n

1 Git 实现此重命名的底层机制非常复杂,可能是出于历史原因,但在正常实践中,它只是“将其更改master为您的remote/master”等等。

\n\n

2请注意,Git 在这里使用了更令人困惑的术语:如果一个分支名称跟踪远程跟踪名称(这是您的 Git 根据在另一个 Git 中找到的名称创建的本地名称,而该 Git 的 URL 是通过远程找到的,那么我们称之为分支(或分支名称)的上游。这与跟踪文件和未跟踪文件完全不同。哎呀!

\n\n

3我在这里假设 Git 存储库https://github.com/abelbraaksma/visualfsharp是您自己的,并且您使用 GitHub Web GUI 界面中的“分叉存储库”点击按钮创建了它。当您这样做时,GitHub 在 GitHub 本身上做了一些复杂的操作git clone,从您选择的任何源存储库创建您的存储库。这意味着您的 GitHub 存储库具有与原始源存储库相同的分支。

\n\n

(GitHub 制作的克隆不会重命名分支。它还设置了仅限 GitHub 的特殊功能,以允许 GitHub 提供的拉取请求功能;这不是 Git 的一部分。GitHub 人员还安排共享背后的底层磁盘对象场景并有各种其他技巧可以使其比天真地完成要快得多。所以原则上它是一个常规克隆,但他们对其进行了调整,使其通过网络界面变得更有用。这就是他们如何让你使用 GitHub 而不是自己做这一切。)

\n

  • @Sharak:不,Git 无法知道这一点。Git*Hub* 知道这一点,但他们不会告诉 Git。`git clone` 的模型没有地方放置该信息。 (2认同)