【问题标题】:How to hide one remote's commit history from other remotes?如何向其他遥控器隐藏一个遥控器的提交历史?
【发布时间】:2020-08-19 12:07:46
【问题描述】:

假设我有多个遥控器用于单个存储库。大多数时候,我使用一个 git 帐户进行开发,完成后,我将最终版本推送到另一个远程。现在,如何从第二个远程隐藏第一个远程的提交历史?

【问题讨论】:

    标签: git github gitlab git-commit git-remote


    【解决方案1】:

    我会告诉你如何按照你的要求去做,然后告诉你为什么这是一个坏主意。 :-)

    历史,在任何 Git 存储库中,只是该存储库中的 commits 集,由该存储库中的 names 集找到。这个查找过程是反向工作的,因为 Git 总是反向工作。我们稍后会看到更多关于此的内容。

    背景

    请记住,每个 commit 都有一个唯一的哈希 ID。这实际上是提交的真实名称。要查看带有git log 的提交,您必须以某种方式将 Git 提示到提交的哈希 ID。然后 Git 可以从存储库数据库中检索该提交,前提是它首先在数据库中。

    每次提交都有你所有文件的完整快照——这是提交中的主要数据——加上一些关于提交本身的元数据:信息,例如谁做了它,什么时候(日期-和时间戳),以及为什么(日志消息)。大多数元数据只是 Git 用git log 向你展示的东西。但是元数据中的一条重要信息,Git 本身需要的,也在这里。每个提交都有一个其 parent 提交的原始哈希 ID 列表。大多数提交在此列表中只有一个条目,因为它们只有一个父节点。

    这个哈希 ID 意味着如果我们以某种方式找到一些开始提交哈希H,我们可以获取提交本身并显示它,并使用它来查找其父(早期)提交。我们称该提交为G。我们说 commit H 指向 commit G:

          ... G <-H
    

    但 G 也指向一个较早的提交——我们称之为F——就像这样:

      ... F <-G <-H
    

    当然F 也向后指向:

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

    所以我们真正需要的只是告诉 Git:last 提交的哈希 ID 是 _____(用哈希 ID 填空)。

    这就是分支名称的作用:它提供了 last 提交的哈希 ID。分支名称​​指向一个提交,就像每个提交指向一个较早的提交一样。这样,我们就不必记住人类无法处理的大而丑陋的哈希 ID。我们只需要记住分支名称。 names 记住了大而丑陋的哈希 ID:

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

    ...当我完成[做出新的提交]...

    让我们看看进行新提交的过程。现在让我们创建一个 分支名称,例如feature。分支名称​​必须指向某个现有的提交——这是 Git 中的规则:分支名称指向某个提交。在...--F--G--H 系列中,最明显的一个是……最后一个:

    ...--F--G--H   <-- feature (HEAD), master
    

    我们需要一种方法来记住我们正在使用的分支名称,因此我将特殊名称 HEAD 附加到新名称 feature 上。如果我们这样做,这就是我们得到的:

    git checkout -b feature master
    

    我们仍在使用提交H,但现在我们是on branch feature,正如git status 所说。特殊名称HEAD 现在附加到feature,而不是master

    当我们进行新的提交时,它会获得一个新的、从未使用过的其他地方、从未使用过的任何地方再次提交哈希I。新提交 I 指向现有提交 H

    ...--F--G--H   <-- master
                \
                 I   <-- feature (HEAD)
    

    重复几次,你就有了:

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

    最终,您完成了提交。您现在可以git push 到某个远程,例如origin。这样做的方式是,您的 Git 调用另一个 Git — 存储在远程名称 origin 下的 URL 上的 Git — 并通过哈希 ID 向它们提供一些提交

    他们在 他们的 存储库中查看他们是否具有该哈希 ID。如果您向他们提供提交K,他们将不会拥有它。这迫使你的 Git 也向他们提供提交 J,因为 JK 的父级,这也是 Git 规则的一部分。他们没有那个,所以你的 Git 会提供I,他们不会有那个,所以你的 Git 会提供H。在这里,他们很可能有H!假设他们这样做。这让您的 Git 停止提供哈希 ID。

    现在你的 Git 必须打包新的提交,I-J-K,然后发送它们。您会在此处看到有关计数和压缩的消息,然后您的 Git 会发送提交。

    git push 现在进入最后阶段:它向他们发送一个礼貌的请求:如果没问题,请将您的分支名称 ______ 设置为指向提交 K 只要这 添加 提交到他们的一个分支,而不从该分支中​​删除任何提交,他们很可能会服从这个请求。如果是全新的分支名称,他们更有可能服从这个要求。

    最终结果是现在他们他们的分支名称指向提交链中的最后一个提交K。从K,他们会找到J,然后是I,然后是H,以此类推。 这是他们现在存储库中的历史记录。

    你想要什么

    ...如何从第二个远程隐藏第一个远程的提交历史?

    你不能,或者,不完全是。但是,您可以创建 新的 次提交,是不同的历史,然后发送这些

    假设您在自己的存储库中创建一个新的不同的分支名称,使用:

    git checkout -b other-guy master
    

    这会在您的 Git 存储库中为您提供这一系列名称和提交:

    ...--F--G--H   <-- master, other-guy (HEAD)
                \
                 I--J--K   <-- feature
    

    您当前的提交现在是提交H。您当前的分行名称现在是other-guy

    您现在可以进行 new 提交——使用全新的、从未见过的哈希 ID,我们将其称为 L——其中包含您喜欢的任何快照。让我们不用担心如何你这样做,然后画出结果:

                 L   <-- other-guy (HEAD)
                /
    ...--F--G--H   <-- master
                \
                 I--J--K   <-- feature
    

    您现在可以使用:

    git push other-remote other-guy:feature
    

    这会让你的 Git 调用存储在远程名称 other-remote 下的 Git,并为他们提供提交 L。他们不会拥有它,所以你的 Git 也会提供提交 H。他们可能有那个——它已经存在了一段时间——所以你的 Git 可能会停在那里,捆绑L,然后发送出去。

    现在你的 Git 向他们的 Git 发送了以下形式的礼貌请求:如果没问题,请设置或创建你的名字 feature 指向提交 L 如果他们接受,那么 他们他们的存储库中有:

    ...--H--L   <-- feature
    

    (他们可能还有一些别的名字,比如他们的master,指向H,只是这里没有画出来)。因此,他们的 提交在 他们的 存储库中是从他们的名字feature 开始的,它标识提交L。他们将显示提交L。然后他们会回到L的父H,并显示H,以此类推。

    请注意他们如何从不显示I-J-K。他们不能,因为他们没有。现在或将来,如果他们想要并有权访问,他们可以从您和/或您发送给他们的任何其他 Git 或任何与您发送给他们的 Git 具有 Git-sex 的 Git 获取它们,从而选择他们起来,依此类推;但现在,他们没有感染提交I-J-K

    (一般来说,Git 真的很喜欢接受新的提交。一般来说,Git 不喜欢放弃提交。很容易像感染一样传播提交。)

    提交的简单方法L

    我答应告诉你如何做你想做的事。在提交I-J-K 之后,有一个简单的方法可以提交L,那就是使用git merge --squash

    鉴于此:

    ...--F--G--H   <-- master, other-guy (HEAD)
                \
                 I--J--K   <-- feature
    

    您可以运行git merge --squash feature,然后运行git commitgit merge --squash 告诉 Git:为真正的合并做你想做的一切,然后停止而不提交。当我进行提交时,将其作为常规的日常单亲提交,而不是与其两个父级的合并提交。

    Git 现在结合了从提交 H 到提交 H 的差异(根本没有变化)与从 HK 的差异,并将所有这些更改应用到 H 中的快照,从而在K 的快照中。此快照尚未提交,但您运行git commit,随心所欲地填写提交消息,现在是:

                 L   <-- other-guy (HEAD)
                /
    ...--F--G--H   <-- master
                \
                 I--J--K   <-- feature
    

    你已经准备好 git push 提交 L 并让其他人称之为 feature

    为什么你可能不应该这样做

    一旦您完成此操作,您在自己的存储库中的下一个起始位置是:

                 L   <-- other-guy (HEAD)
                /
    ...--F--G--H   <-- master
                \
                 I--J--K   <-- feature
    

    您的两个遥控器中的一个具有相同的设置,只是它完全没有提交L。如果你想在那里发送提交L,这次你需要使用feature以外的名字:他们的名字feature记住提交K。你可以告诉他们强行放弃I-J-K 以支持L,但如果你这样做,你已经放弃了你要求的事情:现在其他两个遥控器只有可以找到提交L(至少,通过他们的名字feature)。

    如果你想开发更多的东西,你现在有一个问题:你是从commit K开始,还是从commit L开始?如果您从L 开始,您自己的新工作历史记录没有I-J-K 历史记录。毕竟,历史是通过某个名称找到并向后工作的提交集合

    所以你最终要做的是两件事之一:

    • 制造很多你忽略的历史(你自己的feature 分支,在这种情况下,你通过从提交L 开始下一个分支而放弃),或者
    • 当您执行 git merge --squash 时,开始必须执行 git merge --squash

    让我们看看后者是如何工作的:

    git checkout feature
    

    现在结果:

                 L   <-- other-guy
                /
    ...--F--G--H   <-- master
                \
                 I--J--K   <-- feature (HEAD)
    

    我们做出更多的承诺:

                 L   <-- other-guy
                /
    ...--F--G--H   <-- master
                \
                 I--J--K--M--N   <-- feature (HEAD)
    

    现在我们进行 squash-merge:

    git checkout other-guy
    git merge --squash feature
    

    这合并工作——例如,比较 HL 以找到“我们的”更改,并比较 HN 以找到“他们的”更改,并组合更改。这通常可以正常工作...但是如果我们在 M-N 中所做的任何事情 un-doesI-J-K 中做某事,或者触及与我们在 @ 中所做的事情相同的 987654439@,我们遇到了合并冲突

    有办法解决这个问题,最后我们得到:

                 L--O   <-- other-guy
                /
    ...--F--G--H   <-- master
                \
                 I--J--K--M--N   <-- feature (HEAD)
    

    其中O 具有组合MN 的压缩结果。您现在可以git push 将两个不同的历史记录到两个不同的地方。

    这真的可以工作。随着时间的推移,它只会变得痛苦。还有其他“类似感染”的问题:您已将提交 I-J-K-M-N 发送到其他 Git。这些提交很有可能会传播到更多的 Git 克隆中,并从那里到达您试图保密的克隆。即使这没有发生,你也很容易自己搞砸,通过 git push other-guy feature (虽然幸运的是在第一轮之后,这通常会被拒绝为“不是快进”错误)。

    简而言之,秘密——隐藏的提交——通常一旦共享就不会持续。通常有一个更简单的选择。不过,我不知道你想要这一切的动机,所以很难确定。

    【讨论】:

    • 非常感谢您的详细解释:)
    猜你喜欢
    • 2023-03-18
    • 2014-08-11
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2014-10-28
    • 2012-08-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多