【问题标题】:Git - Re-attach to master and branch branchGit - 重新附加到主分支和分支分支
【发布时间】:2018-10-15 10:45:19
【问题描述】:

我从master 创建了一个分支branch-1,然后在上面做了一堆提交,然后面临两个选项,所以从那里分支并在原始分支branch-1 上做了一堆提交,一些在新分支branch-2.

原来分支 branch-1 上的提交被证明是一个死胡同(第二个分支之后的那些),但分支 branch-2 上的提交注定要留下来。

有没有办法摆脱第一个分支 branch-1 并只保留第二个具有完整历史记录的分支?

【问题讨论】:

  • 为什么不直接删除第一个分支并继续处理另一个分支?

标签: git branch git-branch


【解决方案1】:

重要的是要意识到在 Git 中,分支并不是历史。 Commits 是历史。 (而且没有文件历史记录——只有提交。)请注意,每个提交都有一个“真实名称”,即其哈希 ID,即由 40 个十六进制字符组成的大而丑陋的字符串,例如 f84b9b09d40408cf91bbc500d9f190a7866c3e0f

每次提交都会存储您的源代码树的完整快照,以及一些元数据。在这里,元数据是更有趣的部分。提交中的元数据包括:

  • 您的姓名和电子邮件地址以及时间戳;
  • 您的日志消息;和
  • 其前任或提交的哈希ID。

在这个特定的上下文中,最后一项是最重要的。如果我们用一个大写字母代替丑陋的大哈希 ID,我们可以画出这样的提交:

... <-F  <-G  <-H

Hlast 提交。提交H 记住G 的哈希ID,所以我们说H 指向 G。同时G 记得它的父F,所以G 指向F,它指向E,依此类推。

存储库中的历史。 new 提交包括让 Git 冻结你的源代码树,添加日志消息等,并提出一个新的哈希 ID I。新的提交 I 将存储 H 的哈希 ID:

... <-H  <-I

现在历史是一个更长的提交。

但是:我们如何知道哪个提交是链中的最后一个?在这个简化的例子中,大写字母很明显,但是对于看起来随机的真实哈希 ID,它不是。实际上,除了蛮力“列出每个提交,看看哪个是最后一个”之外,别无他法。所以 Git 给了我们分支名称,这有助于弱小的人类(以及 Git 本身,因为它也不是那么聪明)find last 提交:

...--F--G--H   <-- master

变成:

...--G--H--I   <-- master

在我们做出新的提交之后。

尽可能简单地说,branch name 只是指向(包含哈希 ID)last 提交,我们——和 Git——应该算作其中的一部分那个分支。

这意味着当你创建一个新的分支时,你会选择一些现有的提交并告诉 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,它是master的提示,也是在分支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 仍然可达,从K 开始,从branch2 向后工作:提交Ibranch1 和上>branch2。现在branch1 消失了,I 只在branch2 上,但它仍然可以通过 Git 的“从所有分支名称向后走”技巧到达,

但是,提交 L-M-N 已不受保护。经过一段时间后——通常有至少 30 天的宽限期,通过 Git 调用 reflogs 的机制——Git 的“垃圾收集器”最终将运行并清理 无法访问的对象(提交和其他对象)。这些提交最终将完全消失,只剩下:

...--F--G--H   <-- master (HEAD)
            \
             I
              \
               J--K   <-- branch2

这使它看起来像 branch1 从未存在过。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2020-10-11
    • 2021-08-20
    • 1970-01-01
    • 2022-11-09
    • 1970-01-01
    • 2014-09-19
    • 1970-01-01
    • 2011-06-02
    相关资源
    最近更新 更多