这是一个多部分答案,因为这里有两个独立的问题现在纠缠在一起了。以下是我们将要涵盖的内容概述:
- main与master
- error: src refspec main does not match any
- 协调单独的main和master分支
每个部分都有自己的章节。
main与master
Git本身没有特殊的分支名称。你可以使用main、master、trunk或任何其他名称作为第一个分支的名称。Git传统上使用master名称,但有一个项目使其可配置,因此如果您是法国人或西班牙人,则可以使用principal、première或primero等名称,或者如果您更喜欢毛利语,则可以使用matua或tuatahi。目前,您可以在git init期间或之后手动执行此操作,但是该项目使Git自动执行此操作,而无需进行第二步操作:如果由于任何原因您想要使用默认情况下的任何其他名称,则可以对其进行配置。
同时,GitHub已经选择超前并将其默认初始分支名称从master更改为main。但是,这会使您的Git和GitHub的Git不同步。有关GitHub变更的更多信息,请参见
Difference Between Main Branch and Master Branch in Github?。
1这种说法存在一些技术上的缺陷。我们知道,技术上正确是最好的正确,所以让我在这个脚注中添加一些警告:
当你在分支Y
上运行git merge X
时,合并会自动生成一个形如merge branch X into Y
的消息。然而,当你在master
上时,Git传统上只生成一个形如merge branch X
的消息。
通过git init
创建的新空仓库没有提交,因此也没有分支(因为分支只能通过有提交来存在)。但是,在这个新的空仓库中,你必须在某个分支上。所以 Git 在符号引用HEAD
中存储了某个名称。即使该分支名称尚不存在,你也在该分支上。长期以来,Git 已经将分支名称master
硬编码到其中。(这实际上就是 GitHub 所做的改变)
还有很多源代码和文档中的其他字符串字面量都包含master
;它们正在转换为使用配置设置,但这需要时间。
2如果你安装了 Git 2.28 或更高版本,可以运行git init --initial-branch=name
,并使用git config
在系统或全局配置中设置init.defaultBranch
。如果你安装的是早期版本的 Git,或者已经运行了git init
,只需使用git branch -m
将master
重命名为你喜欢的任何名称即可。
错误:src refspec main does not match any
这是Git的错误信息,对新手来说可能有些晦涩,但实际上很简单。问题在于它充斥着术语(webster; wikipedia),并将“source”缩写为“src”。
Git的全部内容都围绕着提交(commit)展开。当我们克隆一个仓库时,我们的Git会连接到另一个Git。那个Git查找一个仓库,而那个仓库充满了提交。然后我们的Git在本地创建一个新的仓库,将所有提交传输到其中,并将所有分支名称转换为远程跟踪名称。然后我们的Git在这个新仓库中创建一个分支名称,基于他们的一个分支名称。至少,这是正常的过程。(如果你知道所有这些术语的含义,那太好了!如果不知道,现在也不用太担心。这里需要记住的是,我们得到了所有他们的提交和没有他们的任何分支,然后我们通常让我们的Git创建一个与他们匹配的分支)。
由于Git的全部内容都围绕着提交,因此这个过程——复制所有他们的提交,但只复制一个他们的分支名称到我们自己的仓库中拼写相同的名称——就是我们所需要的。我们的Git重命名了所有他们的分支名称——因此除了一个例外,我们根本没有任何分支——通常并不是很重要。如果必要,我们自己的Git会稍后自动处理这个问题。
当我们使用git push
时,我们正在请求我们的Git程序(它正在读取我们自己的Git仓库)连接到一些其他的Git程序——通常在运行服务器机器上——然后可以将数据写入其他的Git仓库。我们希望我们的Git向他们的Git发送我们的一些提交。特别是,我们想要发送我们的新提交:我们刚刚创建的那些。毕竟,那里是我们放置所有好东西的地方。(Git的全部内容都围绕着提交展开,所以那是我们唯一能放置任何东西的地方。)
一旦我们发送了这些提交,我们需要让他们的Git将其中一个分支名称设置为“remember”我们的新提交。这是因为Git查找提交的方式是使用分支名称。每个提交的真实名称都是大而丑陋的哈希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's answer中的
HEAD:main
(尽管出于技术原因,在许多情况下,我们可能要使用
HEAD:refs / heads / main
)。但在简单情况下,我们只需使用一个分支名称:
git push origin main
。简单的分支名称是Refspec的简单形式。
为了使其工作,源名称必须是我们自己的Git存储库中现有分支的名称。这就是事情出错的地方。
(另请参见
Message 'src refspec master does not match any' when pushing commits in Git)
3Git可以使用任何名称,而不仅仅是分支名称。例如,标签名称也可以正常工作。但本答案关于分支名称,因为问题是关于分支名称的,并且在这里使用分支名称是最常见的。
如果我们的 Git 只创建了 master 分支会怎样?
假设我们正在使用 GitHub,并要求 GitHub 为我们创建一个新的存储库。他们运行了一种形式的 git init
,将名称 main
作为新存储库的初始分支名称提供。他们可能也会创建一个提交。假设我们让他们创建这一个提交。那个提交将保存基于我们在 web 界面上选择的 README
和/或 LICENSE
文件。创建该初始提交实际上创建了分支名称 main
。
如果我们现在克隆他们的存储库,我们将获得他们的一个提交,该提交将位于他们的分支名称 main
下。我们的 Git 将重命名他们的 main
为 origin/main
,然后创建一个新的分支名称 main
,以匹配他们的分支名称。所以一切都好。
但是,如果我们使用 git init
自己创建一个空的 Git 存储库,我们的 Git 可能会设置我们的第一个提交以创建名称为 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 在其仓库中创建一个名为
master
的新分支;或者我们可以将我们的
master
重命名为任何我们想要的名称,然后使用该名称。
git branch -m master xyzzy
git push -u origin xyzzy
我們將使用的(單一)分支名稱更改為
xyzzy
。如果您想在這裡使用
main
,請將您的
master
重命名為
main
。
如果您不小心創建了兩個分支怎麼辦?
假設我們使用GitHub創建了一個新存儲庫,其中包含一個初始提交,其中包括通常的README和LICENSE文件,使用他們的新默認分支名稱
main
。然後,在沒有考慮的情況下,我們在自己的計算機上使用
git init
創建了自己的新存儲庫,其預設分支名稱為
master
,並在
master
上進行了一兩次提交。
如果我們現在將
master
重命名為
main
:
git branch -m master main
然后尝试推送:
git push -u origin main
我们得到一个不同的错误:
! [rejected] main -> main (non-fast-forward)
这是因为很简单:他们有一个提交,使用他们的名称“main”,我们没有。如果他们更改他们的名称“main”以查找我们发送给他们的最后一次提交,他们将失去他们所做的初始提交,其中包含README和LICENSE文件。
你有几个选择:
- 你可以忽略他们所做的初始提交。毕竟,它只是一个样板提交。你可以告诉他们完全放弃它。按照任何现有的StackOverflow答案中概述的使用git push --force。
- 你可以获取他们的初始提交并在这些提交上进行rebase。这可能有点棘手,因为你的第一个提交是根提交。如果你的第一个提交包含README和/或LICENSE文件,则会出现add/add冲突。在这种情况下,强制推送可能更简单。
- 你可以获取他们的初始提交并合并你的提交。在现代Git中,这需要使用--allow-unrelated-histories选项。与rebase方法一样,如果您的提交包含README和/或LICENSE文件,则会出现add/add冲突。生成的存储库还将具有两个根提交。这些都不是严重的问题,但可能会稍微有点烦人。
要获取他们的提交,只需运行git fetch origin。这将获取GitHub的第一个提交,并在你自己的Git存储库中使用名称origin/main来记住它。然后你可以:
git rebase origin/main
或者:
git merge --allow-unrelated-histories origin/main
为了实现变基或合并,您可以选择在任何时候在此之前或之后将分支重命名为main
。
[git]
,然后输入各种关键字,SO将使用原始问题上带有[tag:git]标签的这些关键字搜索他们自己的问题和答案。 - torekgit commit -m“Initial commit”
就为我解决了这个问题。我在这里添加这个步骤,以防其他人像我一样忽略了这个简单的步骤。 - Brady