我从branch-1
创建了一个分支master
,然后在上面进行了一堆提交,然后面对从那里分支出来的两个选项,并在原始分支{{1 }},其中一些在新分支branch-1
上。
原始分支branch-2
上的提交被证明是一个死胡同(第二个分支之后的提交),但分支branch-1
上的提交却被保留了。
是否有办法摆脱第一个分支branch-2
并仅保留具有完整历史记录的第二个分支?
答案 0 :(得分:1)
重要的是要意识到,在Git中,分支机构并非历史。 提交是历史。 (并且没有文件历史记录,只有提交。)请注意,每个提交都有一个“真实名称”,即其哈希ID,即丑陋的字符串,包含40个十六进制字符,例如f84b9b09d40408cf91bbc500d9f190a7866c3e0f
。
每个提交都存储源树的完整快照以及一些元数据。在这里,元数据是更有趣的部分。提交中的元数据包括:
在特定情况下,最后一项是最重要的。如果我们使用一个大写字母作为大型丑陋哈希ID的替代,我们可以绘制如下提交:
... <-F <-G <-H
其中H
是最后提交。提交H
会记住G
的哈希ID,因此我们说H
指向 G
。同时G
记住其父项F
,因此G
指向F
,它指向E
,依此类推。
此是存储库中的历史记录。进行 new 提交包括让Git冻结源代码树,添加日志消息等,并提供新的哈希ID I
。新的提交I
将存储H
的哈希ID:
... <-H <-I
现在,历史记录的提交时间更长。
但是:我们怎么知道链中的 last 哪个提交?在这个简化的示例中,使用大写字母很明显,但是使用真正的哈希ID(似乎是随机的)却不是。实际上,只有蛮力地“列出每一次提交,看看哪一个是最后一次”才能发现。因此,Git为我们提供了分支名称,这可以帮助弱小的人(以及Git本身,因为它也不那么聪明)找到 last 提交:>
...--F--G--H <-- master
变为:
...--G--H--I <-- master
我们进行新的提交之后。
尽可能简单地放置一个分支名称仅指向我们和Git应该将其视为 last 提交的(包含其哈希ID)那个分支。
这意味着当您创建一个新分支时,您会选择一些现有的提交,并告诉Git在其上添加另一个名称:
...--F--G--H <-- master, branch1
现在,Git需要一种方法来知道要使用哪个分支名称,因此我们让Git将特殊名称HEAD
附加到以下两个名称之一:
...--F--G--H <-- master, branch1 (HEAD)
当我们进行新的提交时,Git会更新附加了HEAD
的名称 ,如下所示:
...--F--G--H <-- master
\
I <-- branch1 (HEAD)
请注意,提交H
是主站的提示,也是 在分支branch1
上。
如果您创建其他名称,只需在其指向的任何地方绘制即可。如果它指向H
,则将其指向H
。如果它指向I
,例如branch1
,则指向I
。然后添加一些提交,更新附加到名称HEAD
的那个>
J--K <-- branch2 (HEAD)
/
...--F--G--H <-- master
\
I <-- branch1
或:
...--F--G--H <-- master
\
I <-- branch1
\
J--K <-- branch2 (HEAD)
或其他。
让我们说,我们现在有:
...--F--G--H <-- master
\
I--L--M--N <-- branch1 (HEAD)
\
J--K <-- branch2
删除一个分支(名称)仅表示删除该名称。 commits 保持不受干扰-进行一次提交,没有任何可以更改它。如果您不再能够在图中找到提交,则该提交现在很容易被删除。但是,如果您可以从某个现有名称开始,然后再返回以进行提交,则提交本身是引用安全的。因此,如果我们git checkout master
(以便我们可以删除branch1
),我们将得到:
...--F--G--H <-- master (HEAD)
\
I--L--M--N [abandoned]
\
J--K <-- branch2
通过从I
的{{1}}开始并向后工作,提交K
仍可实现可达 :提交branch2
在两个{{ 1}} 和 I
。现在branch1
已经消失了,branch2
仅在branch1
上,但是仍然可以通过Git的“从所有分支名称后退”技巧来达到,
提交I
不受保护。经过一段时间后(通常有至少30天的宽限期),通过Git称为 reflogs 的机制,Git的“垃圾收集器”最终将运行并清理无法访问对象(提交和其他对象)。这些承诺最终将完全消失,而您却没有得到:
branch2
这使得L-M-N
似乎不存在。