一开始这可能会让人很困惑,而您需要的是对 Git 如何实现分支的正确介绍;但此时我们将使用改造方法。 :-) 理解这一切的诀窍在于 Git 的 commits 是永久不变的,但它的 分支——或者更准确地说,分支 names——是暂时的,实际上大多是无关紧要的。
在构建 new 提交时,有三件事很重要(它们是 HEAD、index 和 work-tree em>),但是一旦您构建并提交了提交,它就非常永久,并且很难让 Git 完全失去它。不过,不小心放错位置很容易,所以让我们尽量避免这种情况。 :-)
如果我们完全忽略分支名称,我们可以为您的存储库中存在的提交绘制一个图表。鉴于你所做的——创建两个新的提交——让我们像这样绘制它们,其中圆形 os 代表提交,A 和 B 是你的两个 new 提交:
...--o--o--o
\
A
\
B
我们可以将它们全部画在一条线上,但我想在右边留出空间来写标签。提交A 是您的“哎呀”,B 是您的“更改”。
关于这个图形绘制的主要值得注意的事情是每个提交指向(存储哈希ID)它的前一个提交。这意味着提交B 指向提交A。提交 A 指向下一个最近的提交,该提交指向更远的地方,依此类推。
现在我们添加标签——分支名称。最后一个无聊的提交o 仍然可能有一个标签origin/master。提交A 有标签master,提交B 有标签new_branch,所以让我们把它们画进去:
...--o--o--o <-- origin/master
\
A <-- master
\
B <-- new_branch (HEAD)
这就是分支名称和为您所做的:它们是提交的指针;他们会为您记住每个提交的大而丑陋的哈希 ID。
当您在某个分支上并进行 new 提交时,分支 name 会随之而来。特殊名称 HEAD 会记住您所在的分支,以便 Git 知道将哪个名称 移动 到新提交。 (我们至少暂时需要这个,当master 和new_branch 都短暂地指向提交A。)
您现在要做的是将master back 移动到最后一个无聊的o 提交。为此,您可以使用git reset,它可以让您以任意方式移动名称:
git checkout master
git reset --hard origin/master
这假设(参见下面的最后一节)origin/master 确实确实指向了最后一个无聊的 o 提交。 git reset --hard 说:清除我当前的索引和工作树,并根据HEAD 移动我的当前分支,以便它指向我在这里命名的提交。我们必须@987654351 @first,所以 HEAD 命名为 master。然后git reset 这样做:
...--o--o--o <-- master (HEAD), origin/master
\
A
\
B <-- new_branch
所以现在您的两个新提交 A 和 B 只能通过 new_branch 而不是通过 master 找到。
(分支名称还可以为您做更多的事情。特别是,它们保护提交不会被 Git 的“垃圾收集器”删除。如果提交有任何我们可以找到的名称它,它是受保护的。如果它有 no 名称,它就不再受保护。有一些半隐藏的名称可以保护所有内容一段时间(默认情况下至少 30 天)以确保提交不会不会被意外丢弃,但是通过这些 reflog 名称找到它们很烦人,所以我们尽量不要太依赖它。
分支名称也用于git push,因此它们很重要。)
(我在上面提到“破坏”索引和工作树,这并不完全正确。git reset 命令,使用我们在这里使用它的方式,它可以做三个工作:
它总是做第一个,可选地添加第二个工作,然后可选地添加第三个工作。 --hard 模式执行所有三个,--mixed 模式执行前两个,--soft 模式仅执行一个。为了正确理解它们,我们必须仔细查看 index 和 work-tree 的定义,我将把它留给其他 SO 问题/答案。不过,这里的关键是您不想要git reset --hard,直到您将所有内容都保存在提交中。)
如果没有origin/master(或者它指向太远)怎么办?
我们假设,上面有一个方便的标签——一个所谓的远程跟踪分支——标识我们想要git reset 和master 指向的提交。如果我们没有这个标签,或者它指向更早的提交,我们必须以其他方式定位该提交。
有很多方法可以做到这一点。最直接的方法是通过它的哈希 ID。如果你在某个分支上运行git log,你会看到每个提交都“打开”或“包含在”该分支中,通常按照 Git 通常的向后顺序。例如,我们可能会在git log 看到提交 B 及其大而丑陋的哈希 ID,然后提交 A 及其哈希 ID,然后是无聊的提交 o 及其大而丑陋的哈希 ID。
我们可以使用原始哈希 ID:
git checkout master && git reset --hard <hash-id>
如果我们没有标签。如果我们确实有标签,我们可能应该只使用它。
您可能记得通过git log 向“A DOG”寻求帮助:
git log --all --decorate --oneline --graph
all 使 Git 显示所有分支和所有远程跟踪分支(以及其他所有内容:标签、“存储”、注释等)。 decorate 选项将标签名称附加到提交。 oneline 选项使每次提交的输出仅显示一行,而 graph 选项使 Git 尝试绘制提交图。