gpt4 book ai didi

git - Git初学者:分离Git提交

转载 作者:行者123 更新时间:2023-12-02 08:31:38 26 4
gpt4 key购买 nike

初学者问题:

我最近一直在本地进行大量开发,然后今天进行了git pull(我知道我应该做得更多),并且引入了许多更改和不同的冲突。我解决了冲突,并将所有提交压缩为1(拉出的提交穿插了)。现在,当我将拉出的提交的更改发送出去进行审核时,我的 promise 也很大。我试图找到一种方法来解决这个问题,并将我的提交与那些提交分开。

例:

我的 promise :

原始-> A1-> A2-> A3

远程提交:

原始-> B1-> B2-> B3

合并:

原始-> A1-> B1-> A2-> B2-> A3-> B3

使用Git Rebase,我将提交压缩为1个提交C1:

原始-> C1

现在我的提交涵盖了从A1到A3和B1到B3的所有更改。

任何想法如何区分出更改或解决此问题?

最佳答案

作为Andrew C noted in a comment,您可以通过显示您使用的实际命令来帮助回答者。不过,在这种情况下,我可以猜到您做了什么。

您从本地存储库开始与origin同步,如下所示:

...- o   <-- HEAD=develop, origin/develop

这个分支提示 o是标记为 original的内容。 (我不得不在这里猜测该分支的名称为 develop并跟踪 origin/develop,因此这些名称可能与您使用的名称不同。)

随着时间的流逝,您进行了更改,对生成的工作文件进行 git add编码,然后对 git commit进行编码,以生成以下内容:
         A1 - A2 - A3   <-- HEAD=develop
/
...- o <-- origin/develop

请注意,这里的“提交指向另一个提交”箭头应全部指向左方,而不是向右: A3指向 A2A2指向 A1,而 A1指向 o。原因很简单:“指向”是通过将先前提交的SHA-1 ID存储在新提交中来完成的。一旦将提交实际存储在存储库中,就无法再更改。这意味着在创建 A1时, A2不能指向尚不存在的提交(例如 A1)。它只能指向确实存在的提交(例如上面的 o)。稍后,当创建 A2时,它可以指向 A1,因为它现在已经存在,但是 A1无法更改为指向 A2 .1。

永不更改提交的事实对于您的恢复至关重要。 我们待会儿再讲。

接下来,您运行了 git pull,您没有以任何方式对其进行重新配置,因此 git pull运行了 git fetch(始终如此),然后运行了 git merge(如果您不告诉它重新设置基准,也是如此)。 fetch步骤从 origin获得了一些新的提交:2
         A1 - A2 - A3   <-- HEAD=develop
/
...- o - B1 - B2 - B3 <-- origin/develop

然后 merge步骤在当前分支( develop)上添加了合并提交,将“他们的东西”与“您的东西”组合在一起:
         A1 - A2 - A3 - M  <-- HEAD=develop
/ /
...- o - B1 - B2 - B3 <-- origin/develop

如果您在不使用 git log的情况下运行 --graph,则它喜欢按日期顺序对提交进行排序,因此根据时间,您可能会看到以下内容:
M    merged origin/develop into develop
B3 their message for B3
A3 your message for A3
B2 [etc]
A2
B1
A1
o

这就是您描述它们的方式(但箭头再次指向错误的方向)。但是,实际上,父/子关系是由提交图确定的。如果您将 git log--graph一起使用,则 log命令会首先根据图形进行排序,并且将以更明智的方式(无论如何以图形方式)显示提交,而不是“提交日期/时间”顺序。

然后,您可能(再次,我必须猜想)使用了 git rebase -i,并将很多 pick命令更改为 squash。虽然rebase通常被描述为“更改”或“重写”提交,但其真正作用是复制提交。它必须,因为不能更改提交。因此,对于每个提交,rebase都从复制该提交所做的操作开始(但没有完全提交),然后进行一些更改(通常是很小的更改,但也可以是非常大的更改),然后才从结果中进行新的提交。当您将rebase告诉 squash时,它将延迟3先前的提交,直到还包括要压榨的提交的更改。通过压缩所有提交,新副本仅是一个提交,它包含每个提交完成的所有工作( A1通过 A3加上 B1通过 B3加上合并 M)。

如您所述,结果是一个新的提交 C1。但是,由于这是一个新提交,并且git默认将旧提交保留一个月左右,因此旧提交仍在其中。 git所做的是使您的 develop分支名称指向新提交:
         A1 - A2 - A3 - M  <-- [invisible, but still there]
/ /
...- o - B1 - B2 - B3 <-- origin/develop
\
C1 <-- HEAD=develop

根据您的问题,您想还原 develop以指向 MA3(目前尚不清楚)。只要它们仍在您的存储库中,就很容易做到:唯一的技巧就是找到 MA3(无论您要还原的是什么)的SHA-1。

有时,SHA-1仍在回滚窗口中,因此您可以向后滚动并复制它。

如果不是,则可以使用git的“reflogs”。

您的每个分支都有一个reflog,并且 HEAD本身还有一个附加的reflog。命令 git reflog将为您显示特定reflog的内容,或者默认情况下为 HEAD:
git reflog develop

输出非常类似于 git log的输出(实际上 git reflog只是使用几个选项调用 git log,包括 -g,这是 --walk-reflogs的简短版本)。这将使您找到所需的SHA-1。

一旦确定您具有正确的SHA-1,并且您的工作树是干净的(没有任何要提交的内容),请检查要重新设置的分支-您可能已经在其上,但是 git checkout develop,假设分支是 develop,不会伤害任何东西,在这种情况下只会说 Already on branch 'develop' -使用 git reset --hard sha1:
git reset --hard 1234567

(当然,假设是 1234567)。这将使您当前确定为 develop的当前分支指向commit 1234567。也就是说,现在不是 M不可见了,而是假定 1234567M的ID,而 C1是不可见的:
         A1 - A2 - A3 - M  <-- HEAD=develop
/ /
...- o - B1 - B2 - B3 <-- origin/develop
\
C1 <-- [invisible]

现在只有reflog中的是 C1,而不是 M

如果将 reset --hard标识为 A3的ID,则 develop将指向 A3,从而使 MC1均不可见:
                   A3      <-- HEAD=develop
/ \
A1 - A2 M <-- [invisible]
/ /
...- o - B1 - B2 - B3 <-- origin/develop
\
C1 <-- [invisible]

这是和以前一样的图。我们要做的就是更改 develop指向的位置。 ( HEAD在所有情况下都只包含名称 develop。在每条命令中,git都会打开文件 HEAD,看到它说为“develop”,然后立即忽略 HEAD并直接使用 develop。)

一旦恢复了原来的状态,就由您决定如何从那里继续。对于代码审查,通常的建议是将您的工作 git rebase到新开发分支的尖端。和以前一样, rebase只是复制;让我们通过 A1复制 A3(这次不可见的 M完全不可见):
         A1 - A2 - A3
/
...- o - B1 - B2 - B3 <-- origin/develop
\
A1' - A2' - A3' <-- HEAD=develop

在此, '等中的“prime”或 A1'标记表示它们是副本(需要进行任何更改,首先将其应用于 B3而非 o,其次,指向 B3,然后指向 A1' , 等等)。

但是,当代码分支“差异太大”时,最好检查合并建议,即检查以合并 M结尾的序列。这不是一个单一正确答案的问题:这取决于您,以及谁正在审查/接受代码,以及如何做到这一点。 (复数形式也取决于您,即“差异太大”的含义是什么。)

1要真正完整地说明为什么箭头必须指向“向后”,请注意,提交的SHA-1 ID是该提交内容的低温校验和,包括提交的时间戳。因此,仅在提交完成后才知道该ID:如果不创建该ID,就无法预测将来的提交ID。

2此图假定您具有较新版本的git。在所有版本中, git pull实际上确实使用 git fetch,但是在较旧的版本中, git pull调用 git fetch的方式告诉 git fetch不要更新 origin/develop远程跟踪分支。如果您手动运行 git fetch,它会更新远程分支;在1.8.4或更高版本中,即使从 git pull运行,它也会更新远程分支。

3从技术上讲, rebase实际上进行中间提交,然后将其复位一次,因此您获得了一堆中间提交。看起来好像延迟了提交。这符合git尽可能多地提交的内部哲学。 :-)

关于git - Git初学者:分离Git提交,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/26172787/

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