这一切都很正常。真的没有什么可做的(嗯,除了“在 Git 中习惯这种事情”)。
详细说明为什么这是正常的以及这意味着什么
我初始化了一个 git repo ...
让我们在这里非常清楚。我假设你是这样做的,或者是相当等价的:
$ mkdir newrepo
$ cd newrepo
$ git init
Initialized empty Git repository in ...
如果是这种情况,那么你的处境很有趣:
$ git status
On branch master
No commits yet
nothing to commit (create/copy files and use "git add" to track)
$ git branch
$
也就是说,虽然你是 on branch master,正如 git status 所说,但分支 master 实际上并不存在!你在一个还不是分支的分支上!
所以我使用了这个命令序列:
$ git checkout -b dev
$ git add .
$ git commit -m "some message..."
这一切都很好,但是让我们看看git checkout -b之后会发生什么:
$ git checkout -b dev
Switched to a new branch 'dev'
$ git status
On branch dev
No commits yet
nothing to commit (create/copy files and use "git add" to track)
$ git branch
$
换句话说,唯一改变的是我们已经从不存在的分支master变成了不存在的分支dev。
现在我们将一些文件添加到存储库并提交,我们会看到这个输出(由于各种原因,我的输出与你的会有所不同):
$ echo example > README
$ git add README
$ git commit -m initial
[dev (root-commit) 8ab55c8] initial
1 file changed, 1 insertion(+)
create mode 100644 README
$
此时git status 和git branch 的输出发生变化:
$ git status
On branch dev
nothing to commit, working tree clean
$ git branch
* dev
$
由于这个 Git 相当现代,git status 已从(新的)No commits yet 输出(用于新的空存储库)切换到更典型的 nothing to commit, working tree clean 消息,这是 Git 自 Git 1.6 以来(如果不是更早)使用的消息(尽管随着时间的推移有轻微的措辞变化)。我们在分支dev 和分支dev 存在。如果我们使用所谓的管道命令,我们可以看到名称 dev 标识的哈希 ID:
$ git rev-parse dev
8ab55c84b79cad21440187b4f95ce7c3b947064b
这是我们在git commit 输出中看到的长版本,当它说:
[dev (root-commit) 8ab55c8]
这告诉我们我们刚刚创建了一个新的提交,这个新的提交具体是一个 root 提交(没有父级),这个新提交的缩写哈希 ID 是 8ab55c8,并且新的提交导致更新——或者在这种情况下,创建——分支名称dev。
分支名称包含哈希 ID
至少在 Git 中,分支名称只是哈希 ID 的人类可读名称,并具有其他特殊属性。定位提交的是哈希 ID,而不是名称:name 用于查找哈希 ID。在相当真实的意义上,哈希 ID 是 提交;只有一些数据与该哈希 ID 相关联,我们可以在这里看到:
$ git cat-file -p 8ab55c8 | sed 's/@/ /'
tree 5c7082135e61da9ffc72ae2cd7d29fe702315004
author Chris Torek <chris.torek gmail.com> 1517087854 -0800
committer Chris Torek <chris.torek gmail.com> 1517087854 -0800
initial
这些数据为我们提供了——或者更确切地说是 Git——Git 需要找到与提交相关的文件(通过一个稍微漫长而曲折的过程)所需的一切:
$ git cat-file -p 5c70821
100644 blob 33a9488b167e4391ad6297a1e43e56f7ec8a294e README
$ git cat-file -p 33a9488
example
但这里的关键是一切都通过哈希 ID 起作用; dev 这个名字只是用来定位第一个——或者我们应该说last——哈希ID。 (Git 喜欢逆向工作:一切都是最新的或最新的,如果需要,我们会从那里找到更早的东西。这不仅对我们 使用 Git 更方便,而且也是必需 em> 因为所有内容一旦存储,就是完全只读的。)
添加一个 new 提交包括写出提交(这需要首先收集其数据并写出其树),然后使当前分支名称指向新提交。新提交一经创建,就会包含提交的哈希 ID, 是分支的尖端。 (新提交的哈希 ID 是在现场创建的,来自进入新提交的所有数据。)这是分支名称的另一个特殊功能:当你“打开”一个特定的分支,添加一个新提交告诉 Git 将新提交的哈希 ID 写入分支名称。
这意味着要存在一个分支名称,它必须包含一个哈希 ID
此时您尝试执行git checkout master,但没有名为 master 的分支。所以你跑了:
git checkout -b master
告诉 Git 继续并创建名称master,指向当前提交。
当前提交是存储库中的(一个,单个)提交,并且名称 dev 已经指向那个提交。所以现在你有两个分支名称,dev 和 master,both 都指向那个提交:
o <-- dev, master (HEAD)
git checkout 部分将 Git 的“哪个分支是当前分支”的概念转换为 master。 commit 已经存在; 分支名称是新的(由-b创建); HEAD 现在附加到新的分支名称。
如果您现在进行新的提交,Git 将构造新的提交,它会获得一个新的哈希 ID,以便新的提交记住——“指向”——当前的提交。然后它将新提交的哈希 ID 写入master:
o <-- dev
\
o <-- master (HEAD)
现在master 将有两个提交,dev 将有一个。
为了合并分支(稍后),两个分支应该有一些共同的提交。现代 Git 不会在没有 --allow-unrelated-histories 的情况下合并不相关的分支。合并不相关的历史也可能有点棘手。这不是您第一次合并时想要做的事情。旧版本的 Git 会在没有警告的情况下合并不相关的历史记录(create 仍然有点棘手)。所以虽然有可能,但这不是你应该做的事情。