这是一个多部分的答案,因为这里有两个单独的问题现在纠缠在一起。以下是我们将涵盖的内容的摘要:
main
对比master
error: src refspec main does not match any
- 协调单独
main
和master
分支
这些中的每一个都在其自己的部分中。
main
对比master
Git 本身没有特殊的分支名称。1 您可以使用main
、master
、trunk
或任何其他名称作为您的第一个分支的名称。Git 传统上在master
这里使用这个名称,但有一个项目可以使这个名称可配置,因此如果您是法语或西班牙语,您可以使用名称principal
or ,première
或者primero
如果您更喜欢毛利语,您可以使用matua
or tuatahi
。目前,您可以在 a git init
, 2期间或之后手动执行此操作,但该项目使 Git 自动执行此操作,无需第二步:如果出于任何原因您需要默认任何其他名称,您可以对其进行配置。
与此同时,GitHub 已经选择了跨越式发展,将其默认的初始分支名称main
改为master
. 但这会让你的Git 和GitHub 的Git 不同步。更多关于 GitHub 的转换,请参阅
Github 中主分支和主分支的区别?
1这种说法存在一些技术缺陷。众所周知,技术上正确是最好的正确,所以让我在这个脚注中添加一些警告:
merge branch X into Y
当您在分支上Y
并运行时,合并会自动生成表单的消息。但是,当您打开时,Git 传统上只生成格式为 的消息。git merge X
master
merge branch X
一个新的空存储库由git init
没有提交,因此没有分支(因为分支只能通过提交才能存在)。但是,您必须在这个新的空存储库中的某个分支上。所以 Git 将一些名称存储在名为 的符号引用中HEAD
。这是您所在的分支名称,即使该分支名称不存在(尚不存在)。很长一段时间以来,Git 都在其中硬编码了一些代码来将分支名称粘贴master
在其中。(实际上,这就是 GitHub 改变的地方。)
源代码和文档中还有许多其他字符串文字master
;他们正在转换为使用配置设置,但这都需要时间。
2如果您有 Git 2.28 或更高版本,请在您的系统或全局配置中运行和/或设置with 。如果您安装了较早版本的 Git,或者已经运行,只需使用重命名为您喜欢的任何名称。git init --initial-branch=name
init.defaultBranch
git config
git init
git branch -m
master
error: src refspec main does not match any
这条来自 Git 的错误消息对于新手来说非常神秘,但实际上非常简单。问题是它加载了行话(webster;wikipedia),并将“source”缩写为“src”。
Git 是关于提交的。当我们克隆一个存储库时,我们的 Git 可以访问其他 Git。另一个 Git 查找一个存储库,而另一个存储库充满了提交。然后我们让我们的 Git 在本地创建一个新的存储库,将所有提交转移到其中,并将所有分支名称转换为远程跟踪名称。然后我们的 Git 在这个新的存储库中创建一个分支名称,基于它们的一个分支名称。至少,这是正常的过程。(而且,如果您知道所有这些术语的含义,那就太好了!如果不知道,现在不要太担心它们。这里要记住的一点是,我们得到了他们所有的提交,而没有他们的分支,然后我们通常让我们的 Git创建一个分支来匹配他们的一个。)
由于 Git 是关于提交的,所以这个过程——复制他们所有的提交,但只复制他们的一个分支名称到我们自己的存储库中拼写相同的名称——就是我们所需要的。我们的 Git重命名了它们所有的分支名称这一事实——因此除了一个例外,我们根本没有任何分支——通常并不是很重要。我们自己的 Git 会在必要时自动处理这个问题。
当我们使用 时git push
,我们要求我们的 Git 程序(它正在读取我们自己的 Git 存储库)连接到其他一些 Git 程序(通常在服务器机器上运行),然后该程序可以写入其他一些 Git 存储库。我们希望我们的 Git 向他们的 Git 发送我们的一些提交。特别是,我们想向他们发送我们的新提交:我们刚刚提交的那些。毕竟,这些是我们放置所有好新东西的地方。(Git 是关于提交的,所以这是我们唯一可以放任何东西的地方。)
但是,一旦我们发送了这些提交,我们需要在他们的 Git 中设置他们的分支名称之一以记住我们的新提交。那是因为 Git查找提交的方式是使用分支名称。3 每个commit的真实姓名都是大而丑的hash ID号,没人想记住或看;所以我们让 Git 使用分支名称记住这些数字。这样,我们只需要查看分支名称,这些名称对我们来说可能是有意义的:trunk
, 或feature/tall
, 或tuatahi
, 或其他。
默认情况下,我们使用的git push
方式非常简单:
git push origin main
例如。该git push
部分是表示发送提交并要求他们设置名称的命令。这origin
部分是 Git 所说的远程:一个短名称,主要包含一个 URL。最后的main
部分,在这里,是我们的分支名称。那是我们的Git 用来查找我们的提交的那个。我们会让我们的 Git 发送我们的提交,然后让他们的 Git 也设置他们的 main
。
最后一部分——我们在main
这里放的地方——就是 Git 所说的refspec。Refspecs 实际上让我们输入两个名称,用冒号分隔,或者其他几个形式。例如,我们可以在Arka 的回答HEAD:main
中使用as (尽管出于技术原因,我们可能希望在许多情况下使用)。但在简单的情况下,我们可以只使用一个分支名称:. 简单分支名称是 refspec 的一种简单形式。HEAD:refs/heads/main
git push origin main
为此,源名称必须是我们自己的 Git 存储库中现有分支的名称。 这就是事情出错的地方。
(在 Git 中推送提交时,另请参阅消息 'src refspec master does not match any')
3 Git 可以使用任何名称,而不仅仅是分支名称。例如,标签名称可以正常工作。但是这个答案是关于分支名称的,因为问题是关于分支名称的,而分支名称是这里最常用的名称。
如果我们的Git 只创建了master
怎么办?
假设我们正在使用 GitHub,并且我们已经要求 GitHub 为我们创建一个新的存储库。他们运行一种git init
提供的形式,作为新存储库的初始分支名称 name main
。他们也可能会也可能不会创建一个提交。假设我们确实让他们创建了这个提交。根据我们使用 Web 界面选择的内容,该提交将保存README
和/或文件。LICENSE
创建该初始提交实际上会创建分支名称main
。
如果我们现在克隆他们的存储库,我们将获得他们的一个提交,它将在他们的分支名称下main
。我们的 Git 会将它们重命名main
为origin/main
,然后创建一个新的分支名称main
,以匹配它们的名称。所以一切都会好的。
但是,如果我们使用自己创建自己的空Git 存储库,git init
我们的 Git 可能会设置我们,以便我们的第一次提交将创建 name master
。我们不会有main
分支:我们将有一个master
分支。
或者,如果我们没有让 GitHub 创建初始提交,那么 GitHub 存储库将完全是空的。因为它没有提交,所以它没有分支:分支名称只有在指定某个提交时才允许存在。因此,如果我们克隆这个空存储库,我们也将没有分支,并且我们的 Git 不会知道使用main
: 我们的 Git 可能会使用master
. 我们又回到了同样的情况,我们的 Git 认为要创建的第一个名称应该是master
.
因此,在这些不同的情况下,我们进行第一次提交,它们都在一个名为master
. 如果我们现在运行:
git push -u origin main
(有或没有-u
; 我不会在-u
这里详细介绍)我们的 Git 在我们的 Git 存储库中四处寻找一个名为main
. 一个都没有!所以我们的 Git 只是给了我们:
error: src refspec main does not match any
错误信息。
为了解决这个问题,我们可以git push origin master
——发送我们的提交,然后要求 GitHub 在 GitHub 存储库中创建一个新分支,该分支名称为master
——或者将我们重命名为我们master
想要的任何名称,然后使用该名称:
git branch -m master xyzzy
git push -u origin xyzzy
将使我们都使用的(单个)分支名称 be xyzzy
。如果你想main
在这里,将你的重命名master
为main
.
如果你不小心做了两个分支怎么办?
假设我们使用 GitHub 创建了一个新的存储库,其新的默认分支名称main
包括一个初始提交以及通常的 README 和 LICENSE 文件。然后,不假思索地,我们git init
在自己的机器上使用它的默认分支名称创建了自己的新存储库,master
并在我们的master
.
如果我们现在将我们的重命名master
为main
:
git branch -m master main
然后尝试推动:
git push -u origin main
我们得到一个不同的错误:
! [rejected] main -> main (non-fast-forward)
这样做的原因很简单:他们有一个提交,他们发现使用他们的name main
,而我们没有。如果他们更改名称main
以查找我们发送给他们的最后一次提交,他们将丢失他们所做的初始提交,以及 README 和 LICENSE 文件。
你有很多选择:
您可以忽略他们所做的初始提交。毕竟,这只是一个样板提交。你可以告诉他们把它完全扔掉。使用git push --force
许多现有 StackOverflow 答案中的任何一个。
您可以获取他们的初始提交并根据这些提交重新提交您的提交。这可能有点棘手,因为您的第一个提交是root 提交。如果您的第一次提交包含 README 和/或 LICENSE 文件,您将在此处遇到添加/添加冲突。在这种情况下,强制推送可能更简单。
您可以获得他们的初始提交并合并您的提交。在现代 Git 中,这需要使用该--allow-unrelated-histories
选项。与 rebase 方法一样,如果您的提交包含 README 和/或 LICENSE 文件,您将遇到添加/添加冲突。生成的存储库还将有两个根提交。这些都不是严重的问题,但它们可能会有点烦人。
要获得他们的提交,只需运行git fetch origin
. 这将获得 GitHub 的第一次提交,并使用origin/main
您自己的 Git 存储库中的名称来记住它。然后您可以:
git rebase origin/main
或者:
git merge --allow-unrelated-histories origin/main
实现rebase或merge。您可以选择是否将您的分支重命名为main
,如果您尚未这样做,则可以在执行所有这些操作之前或之后的任何时间。