如果每个分支都带有对其初始基提交(例如branch@{base}
)的引用,git 上游变基"硬情况"问题不会得到解决吗?
这个初始基本提交(例如,存储在配置文件中的branch.<name>.base
下)将首先是分支最初创建时指向的提交。
然后,任何git rebase new_base_commit branch
实际上都可以在将branch@{base}
更新为new_base_commit
之前执行git rebase --onto new_base_commit branch@{base} branch
。
它只会自动执行文档的"困难案例"解决方案。
我想,如果这样一个简单的解决方案还没有实施,应该有充分的理由不这样做。既然我看不到任何东西,那一定意味着我误解了什么。
那么如果有,这些原因是什么?
>EDIT:阅读 bk2204 的答案让我意识到这种行为对于跟踪分支的特殊用例才有用且预期(我应该更早意识到,因为它是关于上游变基的),所以初始基础应该只记录用于跟踪分支,并且仅用于使用隐式@{upstream}
的命令, 就像没有争论的git rebase
一样。
>EDIT:我刚刚发现,实际上,git pull --rebase
和git rebase
已经使用git merge-base --fork-point
算法做了类似的事情,但后者使用可以垃圾收集的 reflog 来计算分叉点。
所以我仍然想知道:为什么不简单地将其存放在branch.<name>.remote
旁边并branch.<name>.merge
呢?
例如,当用户开始跟踪另一个分支*时,可以使用git merge-base --fork-point upstream local
计算分叉点并存储在git config branch.local.forkPoint
(或任何其他名称)下,以及git config branch.local.remote
和git config branch.local.merge
.
然后,当用户执行git pull --rebase
或git rebase
时,它可以执行**:
git rebase --onto local@{upstream} `git config branch.local.forkPoint` local
如果用户尝试执行git pull
或git merge
,它可以首先检查local@{upstream}
是否未变基,如下所示:
git merge-base --is-ancestor `git config branch.local.forkPoint` local@{upstream}
如果它被重定基址,它可能会中止,并建议改为变基或编写完整的合并命令来强制它(例如)。
EDIT:我认为,为了能够正确处理文档此页面中"变基的危险"中描述的情况,当通过合并而不是变基将分支"同步"到其上游时,应该检查最后一个"同步点"以验证上游从那时起也没有变基。
因此,每个git pull
或git merge
也应该在应用合并后将上游分支中的合并父提交存储在某个地方(例如branch.local.lastSyncPoint
可能)。 在应用合并之前,还应检查:
git merge-base --is-ancestor `git config branch.local.lastSyncPoint` local@{upstream}
实际上,它可能会使对分叉点的检查毫无用处。
>EDIT:此外,我认为变基应该丢弃从最后一个"同步点"访问的所有提交,这些提交不包括在(变基)上游(local@{upstream}..`git config branch.local.lastSyncPoint`
)中。在丢弃提交的情况下,它将使其根据预期工作。
<小时 />*,带git switch --create local --track upstream
或git checkout -b local upstream
或git branch --track local upstream
或git branch --set-upstream-to upstream local
** 而不是即时:
git rebase --onto local@{upstream} `git merge-base --fork-point local@{upstream} local` local
首先:branch
不会有一个单一的branch@base
:"基础"不会相同,例如对于git rebase master
和git rebase develop
。
第二:你仍然需要分析提交列表:
假设另一个开发人员(我们叫他戴夫)致力于分支develop
?如果戴夫在他的一次提交中修复了与您相同的错误怎么办?他挑选了你的一个提交?
git
专注于存储内容。当发生"合并"或"变基"等操作时,它会应用"通常有效"(并且运行良好)的规则,但验证内容是否正确始终留给用户。
首先,Git 不会以你想到的方式跟踪分支"开始"的位置。 分支只是指向提交的指针,每个提交都包含指向一个或多个先前提交的指针。 因此,如果我做类似git checkout -b topic-branch
的事情,Git 不会记录从中创建此分支的提交,并且该提交在任何方面都不是特殊的。
其次,Git 不会优先考虑任何一个分支而不是另一个分支。 从现有分支创建新分支并不意味着原始分支与我刚刚创建的分支特殊或不同,Git 也不假设我将新分支合并到旧分支中。 例如,我可能没有一个主分支,而是以版本命名的分支:v1
、v2
、v3
等。 因此,从v3
创建v4
与从主分支创建topic-branch
没有任何不同。 跟踪v4
的基础是没有意义的,因为它永远不会合并到v3
中。
第三,Git 明确不将分支作为一个概念来跟踪。 有意使提交不包含分支名称或分支点。 分支旨在成为对现有提交的轻量级引用。 旨在两个分支可以指向同一个提交,这对于打包效率很重要。 如果我想创建一个分支major-feature
,其中包含和扩展topic-branch
而又基于main
,我要么必须在我的提交中公开我把一个小主题变成主要功能的历史记录,要么我必须在major-feature
重写所有提交。
因此,虽然跟踪这些信息将有助于某些用例,但它会为许多其他用例添加一堆无趣的元数据,并且会增加一堆复杂性。