简而言之
你的情况还可以,但是你有一个额外的代码库,最好是把它删除。通常应该先克隆(使用 git clone
)想要在Git中称之为origin
的代码库,然后 git remote add upstream <另一个url>
,从那里开始工作。
阅读下面的详细说明,了解你现在的情况以及如何处理它。
详细说明:你所做的事情
git init
这将在当前目录中创建一个新的空Git存储库。如果已经有一个Git存储库,即如果
git rev-parse --git-dir
会打印一些目录名称而不是失败并说“我找不到存储库”,它基本上什么也不做,这样运行是安全的。虽然这里有一些特殊情况,但你不太可能遇到它们。由于你打算克隆存储库,所以你不需要这样做,因为正如我们马上要看到的那样,
git clone
也会执行
git init
。
在我们继续下面的
git clone
之前,让我们花点时间了解一下新的空存储库的奇怪状态。你可能已经熟悉了像
master
这样的“分支名称”实际上只持有一个(1)提交的哈希ID的想法。Git使用该名称来查找分支上的最后一个提交,Git称其为“尖端提交”。Git然后使用尖端提交来查找先前或“父”提交,并使用父级的父级来向后工作。通过跟随父级链,Git找到所有可从分支名称到达的提交。
但是,空存储库没有提交。对于名称
master
指向的尖端,不存在可以在名称
master
下存储其哈希ID的最新提交。Git的解决方案是暂时没有
master
分支。同时,Git声明你正在“分支master”上,正如
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/*
名称之一创建一个本地分支名称,并将其作为当前分支。
完成后,您回到原始目录(即仍然是/D/Projects/OpenSource/VisualFSharp2
)。请注意,您的原始目录是一个Git存储库,而其visualfsharp
子目录是另一个存储库。
现在,我们将看到您再次执行大多数这些命令,但这次应用于当前为空的存储库,该存储库处于奇怪的状态,即您在master
上,但master
不存在。
git fetch https://github.com/Microsoft/visualfsharp
这将调用位于 https://github.com/Microsoft/visualfsharp
的 Git 并从中获取提交和其他对象,导入到你之前空的仓库(不是你刚克隆的那个!)。 这类似于 git fetch remote
,但没有远程跟踪名称——没有 origin/*
或 upstream/*
——因为没有远程来构建这样的名称。 这种特殊形式的 git fetch
可追溯到古老时代(2005年),在发明 git remote
之前,你可能永远不应该使用它。 它不会对你造成有害的影响,只是在这里不是有益的。
git remote add upstream https://github.com/Microsoft/visualfsharp
git remote add origin https://github.com/abelbraaksma/visualfsharp
以下这些内容都是正确的:它们设置了两个远程仓库。远程仓库只是一个短名称,其作用如下:
- 保存一个URL
- 提供了远程跟踪分支名的前缀,分别为
upstream/*
和 origin/*
。
git fetch upstream
这几乎是你之前执行的“git fetch”的重复操作。不过,这次你的Git使用了你分配的名称——“upstream”——来获取URL。因此,你的Git再次调用了
https://github.com/Microsoft/visualfsharp
上的Git。你的Git从它们那里获取所有新提交(以及与这些提交一起需要的任何其他Git对象),自上次提取以来——可能没有,具体取决于你在第一次提取和第二次提取之间的时间间隔。如果你之前没有运行过“git fetch”,则会在获取所有提交时获取每个Git对象。
但现在,已经获取了提交,存在一个关键的区别:你的Git将他们的所有分支名称更名为你的远程跟踪名称拼写为
upstream/whatever
。现在可以这样做,因为你正在使用远程而不仅仅是原始URL。远程——字面意思上的字符串
upstream
——让你进行了这种重命名。
1因此,你的Git和他们的Git非常快速地传输了所有新对象(可能没有),然后你的Git根据他们的
master
等设置了你的
upstream/master
等。
git checkout master
这里涉及到存储库的奇怪状态。你的Git会显示:
Branch master set up to track remote branch master from upstream.
Already on 'master'
发生的情况是
git checkout
查找
master
,但
未找到(因为您没有分支),所以它
创建了一个分支。首先,它查找所有远程跟踪名称,在此例中为
upstream/*
。它找到了一个匹配的分支:
master
vs
upstream/master
,然后创建了您的
master
,指向与您的
upstream/master
相同的提交。然后还设置了您的
master
,将
upstream/master
设置为其上游设置。
在完成所有这些操作 - 创建
master
后,
git checkout
尝试将您放在
master
上,并发现您只在
master
上并打印出令人困惑的“已经在”消息。在此过程中,您的HEAD已正确附加,检出所有文件,即,复制它们到索引和工作树。
您可能或可能不希望使用此方式设置您的
master
- 一旦创建了
origin/master
,您更有可能希望您的
master
开始指向与
origin/master
相同的提交,并将
origin/master
设置为其上游。有关上游的更多信息,即将一个分支设置为跟踪另一个分支的含义,请参见例如
我的答案以及
如何使用git设置多个跟踪级别的分支。
您的最后一条命令是:
git merge upstream/master
你自己的 master
分支刚刚从你的 upstream/master
创建而来,因此没有需要合并的内容:这两个名称都指向相同的提交哈希 ID。
你还没有从你的 origin
获取任何内容。现在你可能应该这样做:
git fetch origin
一旦你这样做了,你将拥有
origin/master
和
upstream/master
3。如果你想要自己的
master
跟踪
origin/master
而不是
upstream/master
(并从那里开始),你应该:
- 确保没有需要提交的内容(考虑到上述顺序,不应该有,但在使用
git reset --hard
之前检查一下总是明智的);
- 运行
git reset --hard origin/master
,使你的master
指向与origin/master
相同的提交;并且
- 运行
git branch --set-upstream-to=origin/master master
来更改上游设置。
现在,你可以运行
git merge upstream/master
。如果上游自你的分支派生以来有新的提交,那么它将合并这些提交,如果必要,使用完整合并或者快进不真正合并的操作。
在任何情况下,你可能想删除额外的存储库。
1 Git实现此重命名的基本机制非常复杂,可能是由于历史原因,但在正常实践中,它只是“将其
master
更改为你的
remote/master
”等等。
2请注意,Git在这里使用更加混乱的术语:如果一个分支名称“跟踪”一个“远程跟踪名称”(这是你的Git基于找到的另一个Git的名称创建的本地名称,该Git的URL通过“远程”找到),那么我们称其为分支(或分支名称)的“上游”。这与已跟踪和未跟踪文件完全不同。天哪!
3我在这里假设
https://github.com/abelbraaksma/visualfsharp
上的Git存储库是你自己的,并且你使用GitHub的Web GUI界面中的“fork a repository”点击按钮创建了它。当你这样做时,GitHub在GitHub本身上进行了相当复杂的
git clone
,从你选择的任何源存储库创建了你的存储库。这意味着你的GitHub存储库具有与原始源存储库相同的所有分支。
GitHub所克隆的副本不会重命名分支。它还设置了特殊的GitHub专用功能,以允许GitHub提供的拉取请求工具;这不是Git的一部分。GitHub团队还安排共享底层磁盘对象,并有各种其他方法,使其比天真地完成要快得多。因此,从原则上讲,这是一个常规的克隆,但他们通过他们的Web界面进行了调整,使其更加有用。这就是他们让你使用GitHub而不仅仅是自己完成所有工作的方式。
git clone
的模型没有地方放置那些信息。 - torek