gpt4 book ai didi

git - 远程git rebase如此邪恶的详细原因

转载 作者:行者123 更新时间:2023-12-04 16:08:02 25 4
gpt4 key购买 nike

因此,我来​​自集中的VCS背景,并试图在Git(新公司,年轻的代码库)中完善我们的工作流程。我找不到一个简单而详细的答案的问题是,基于远程分支的确切作用是什么。我了解它会重写历史记录,并且通常只应限于本地分支机构。

我目前正在尝试的工作流涉及一个远程协作分支,每个开发人员“拥有”一个共享代码的目的。 (在可预见的将来,如果有2个开发人员和最多3个开发人员,则每个项目和功能请求的功能分支似乎过多且开销超过获得的收益。)

然后,我遇到了this answer并进行了尝试,它实现了我想要的功能-一个开发人员提交并经常推送到他自己的collab分支,当他知道批准发布哪些内容以供分期使用时,他可以远程进行基础调整(挤压和可能进行重组),然后再合并到开发中。

输入原始问题-如果远程分支是出于协作目的,则肯定会有其他人迟早将其拉出。如果没有“来宾开发者”提交到该collab分支是一个过程/培训问题,那么分支所有者将该远程分支重新设基实际上会发生什么?

最佳答案

这不是真正的邪恶,是实现和期望的问题。

我们从一系列事实开始:


每个Git哈希代表一个唯一的对象。出于我们的目的,我们只需要考虑提交对象。每个哈希都是对对象的内容应用加密哈希函数(对于Git,具体来说是SHA-1)的结果。对于提交,内容包括源树的ID;作者和提交者的姓名和电子邮件地址以及时间/日期;提交消息;最关键的是父提交的ID。
即使仅更改内容中的单个位,也会产生新的,完全不同的哈希ID。哈希函数的加密属性(用于验证和验证每个提交(或其他对象))还意味着,无法使某些不同的对象具有相同的哈希ID。 Git也依靠此在存储库之间传输对象。
Rebase通过将提交复制到新提交来(必要)工作。即使没有其他更改(通常,与新副本相关联的源代码也不同于原始源代码),该基础的整个目的是重新建立某些提交链的父级。例如,我们可以从以下开始:

...--o--*--o--o--o   <-- develop
\
o--o <-- feature


其中,分支 feature在提交 develop时与分支 *分开,但是现在我们希望 featuredevelop的最尖端提交下降,因此我们对其进行了重新设置。结果是:

...--o--*--o--o--o        <-- develop
\ \
\ @--@ <-- feature
\
o--o abandoned [used to be feature, now left-overs]


其中两个 @是原始两个提交的副本。
分支名称(如 develop)只是指向(单个)提交的指针。我们倾向于认为是“分支”的事物,就像两个提交 @--@,是通过从每个提交向其父级进行反向工作而形成的。
总是期望分支增加新的提交。找到 developmaster添加了一些新的提交是完全正常的,因此名称现在指向一个提交(或许多提交中的最后一个),并指向该名称所指向的位置。
每当您让Git与其他Git及其其他存储库进行同步(以某种程度)时,您的Git及其Git就会交换ID,尤其是哈希ID。确切的ID取决于传输的方向,以及您要求Git使用的任何分支名称。
远程跟踪分支实际上是您的Git存储的实体,与您的存储库相关联。实际上,您的远程跟踪分支 origin/master是您的Git记住“我们上次交谈时 origin的Git所说的他的 master是什么”的地方。


因此,现在我们来看这七个项目,并研究 git fetch的工作原理。例如,您可以运行 git fetch origin。此时,您的Git在 origin上调用Git并询问其分支。他们说诸如 master = 1234567branch = 89abcde之类的东西(尽管哈希值正好都是40个字符长,而不是7个字符)。

您的Git可能已经具有这些提交对象。如果是这样,我们快完成了!如果不是,它将要求其Git发送那些提交对象,以及Git需要使它们有意义的任何其他对象。附加对象是与那些提交一起发送的任何文件,以及那些您尚未使用的那些提交使用的父提交,加上父提交的父母,依此类推,直到我们得到一些提交对象为止你有。这样可以获取所有新历史记录所需的所有提交和文件。1

一旦您的Git安全地存储了所有对象,您的Git便会使用新的ID更新您的远程跟踪分支。他们的Git刚刚告诉您他们的 master1234567,因此现在您的 origin/master设置为 1234567。他们的 branch也是如此:它成为您的 origin/branch,而您的Git保存了 89abcde哈希。

如果现在使用 git checkout branch,则Git使用 origin/branch制作一个新的本地标签,指向 89abcde。让我们画一下:

...--o--*--o--1   <-- master, origin/master
\
o--8 <-- branch, origin/branch


(为了简化它们,我在这里将 1234567缩短为 1,并且将 89abcde缩短为 8。)

为了使事情真正有趣,我们也对 branch进行自己的新提交。假设它被编号为 aaaaaaa...

...--o--*--o--1    <-- master, origin/master
\
o--8 <-- origin/branch
\
A <-- branch


(我将 aaaaaaa...缩短为 A)。

那么,有趣的问题是,如果它们(您从中获取的Git)重新建立基础,将会发生什么。例如,假设它们将 branch重新基于 master。这将复制一定数量的提交。现在您运行 git fetch,您的Git会看到他们说 branch = fedcba9。您的Git会检查您是否具有此对象;如果没有,您将得到它(及其文件)和父文件(以及该提交的文件),依此类推,直到我们达到某个共同点为止,实际上,这将是提交 1234567

现在您有了:

...--o--*--o--1        <-- master, origin/master
\ \
\ o--F <-- origin/branch
\
o--8--A <-- branch


在这里,我已经为提交 F编写了 fedcba9,现在一个 origin/branch指向了。

如果您稍后遇到这个问题而又没有意识到上游人员重新调整了他们的 branch(您的 origin/branch),您可能会看到这个并认为您必须在 o--8--A链中写了所有三个提交,因为它们在您的 branch而不是 origin/branch上。但是它们之所以不在 origin/branch上,是因为上游放弃了它们,而选择了新副本。很难说这些新副本实际上是副本,您也应该放弃这些提交。



1如果分支以“正常”,“预期”的方式增长,那么Git及其Git确实很容易找出哪些Git满足了他们的需求:您的 origin/master告诉您上次看到它们的 master的位置,现在,他们的 master点在更长的链条上更进一步。您需要的提交恰好是在 master提示之后的 origin/master上的提交。

如果分支以不太典型的方式改组,则难度会更大。在最一般的情况下,他们只需要用哈希ID枚举所有对象,直到您的Git告诉他们它们已经达到您已经拥有的对象为止。浅克隆会导致具体细节更加复杂。



并非不可能

这并不是没有可能,而且自Git 2.0左右以来,现在有内置工具可以让Git为您解决。 (具体来说,由 git merge-base --fork-point调用的 git rebase --fork-point使用您的 origin/branch引用日志来确定 o--8链曾经位于 origin/branch上。这仅适用于时间段保留了这些reflog条目,但是默认情况下至少要保留30天,这使您有一个月的时间可以赶上进度。这就是您的时间轴上的30天:从运行 git fetch开始的30天后,无论上游进行了基准调整。)

真正可以归结为的是,如果您和上游事先同意重新定义某些特定的分支集,则您可以安排每次执行此操作时在存储库中执行所需的任何操作。但是,在更典型的开发过程中,您将不会期望它们重新建立基础,如果它们不能重新构建基础(如果他们从未“放弃”您已经获取的已发布的提交),那么您就无需恢复。

关于git - 远程git rebase如此邪恶的详细原因,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/39154794/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com