在git中合并拉取请求会导致上游分支超越源分支。

5
术语:
1. 本地分支称为主分支(master) 2. Github上的存储库称为origin/master 3. 我派生的根存储库称为upstream/master 假设我的 origin/master 比 upstream/master 多一次提交。那么我会为 upstream/master 创建一个拉取请求,假设上游存储库的所有者接受了拉取请求并将其合并。这将在 upstream 存储库中创建一个 +1 提交,并显示消息“从 githubuser/branchname 合并的拉取请求”。现在在 Github 上显示:“此分支(origin/master)比 upstream/master 多 1 次提交,落后 1 次提交。” 实际上,这些分支中的代码几乎相同,它们应该是平等的。
我曾尝试通过访问以下链接解决这个问题: cleaning the branch without pushing,但这似乎更像是一个技巧。是否有办法将内容推送到上游而不向 upstream 做额外的提交? 只需合并拉取请求即可使 upstream/master 和 origin/master 分支变得平等吗?

使用命令 git merge --ff-only featurebranch 在本地合并,然后再进行推送(push)。这只有在 master 分支没有与你的特性分支发生分歧时才有效。 - Tobias K.
1
代码相同并不重要,如果历史记录不同,那么分支也不同。 - Ian Miller
@TobiasK。我的问题不在于我派生的本地或远程存储库(位于MYusername/repo中的存储库完全正常)。问题在于,当我的分支更改被添加到父分支(远程上游分支)后,因为原始所有者决定接受拉取请求,所以我会收到我在问题中提到的粗体消息。 - Hemal Mamtora
1
可能是如何避免在GitHub/BitBucket上陷入合并提交地狱的重复问题。 - Tobias K.
2
我之前提到“本地”,因为当合并一个PR时,GitHub总是会创建一个合并提交(no-ff),所以你无法在GitHub上干净地完成它,需要从其他地方推送分支。 - Tobias K.
@IanMiller 正确,那么历史记录可以相同吗?因为在拉取请求被接受之前,“我们甚至(两个分支都是平等的)”,然后我的朋友使用拉取请求从我的存储库中将其拉到他的存储库中,现在我“领先1次提交,落后1次提交”。 - Hemal Mamtora
1个回答

6
问题的核心在于GitHub内部。(稍后我将详细解释。)因此,对于你的问题,《指环王》项目中的答案既是“否”又是“是”

有没有办法推入上游而不向上游进行额外提交。只合并拉取请求,使上游主和原点主分支平等?

这里涉及到四组人:

  1. 编写GitHub本身的人。他们控制着出现在您网页浏览器中的内容,即您在页面上看到的那个绿色按钮,“Merge this pull request”(合并该拉取请求),该按钮边缘有一个小下拉箭头,如果单击,则可以选择三种类型的合并。

    这三种类型的合并不包括您想要执行的操作。因此,如果他们更改此以添加第四种合并类型,或更改其中一种现有的合并类型,或采取类似的措施,那么就可以让第3组中的每个人都能够做到您想要的事情。

  2. 具有上游存储库管理访问权限的人。他们可以直接git push到上游存储库。这意味着他们可以使用命令行Git(根本不涉及GitHub)执行您想要的操作,然后运行git push来更新GitHub上的存储库。

  3. 通过GitHub提供的接口具有写访问权限,但没有管理访问权限的人。他们无法做到你想要的事情,至少在第1组的人将其添加为选项之前是这样。

  4. 没有写访问权限的人(包括您自己):他们无法做到这一点。

现在,就那些GitHub的点击按钮而言——或者说,三种模式的按钮:提供的三种模式标记如下:

  • 合并。

    你可能认为这可以完成任务,但实际上并不是这样,因为它运行的等效命令是git checkout branch && git merge --no-ff -m message hash。其中,branch很明显,message部分是Merge pull request #number from repository。而hash部分则更加复杂:它是在refs/pull/number/head下找到的哈希值。这是你提交的特定提交的提交ID,通过你点击“比较和拉请求”的按钮提交的。

    如果GitHub使用等效的命令git checkout branch && git merge --ff-only hash,与相同的branchhash,你将获得你想要的内容。当然,就不会有包含文本Merge pull request ...的提交了。但这没事。(这是我希望他们添加的新模式。他们可以称之为无额外提交的合并或快进,也许。)

  • 变基合并

    这将添加不在分支上的拉取请求提交(可能有多个)到该分支。它运行的等效命令是git checkout branch && git rebase --force-rebase hash(也许还带有--merge--strategy merge)。最终结果是,从拉请求中复制的提交被复制到新的提交中,具有新的和不同的哈希ID。合并请求完成后,不会添加合并提交,因此没有Merged pull request ...消息。

    你可能会认为,在要复制的提交或提交已经在正确的位置的情况下,即在点击按钮之前的分支尖端刚刚过去的情况下,GitHub不会复制提交,而是像在没有--force-rebase--no-ff的情况下运行git rebase一样使用它们。但事实并非如此。我不知道是否有某些好的(GitHub内部)原因。

  • 压缩合并。

    这相当于执行git checkout branch && git merge --no-commit --squash hash && git commit -m message。(这里的--no-commit是多余的:--squash意味着--no-commit。这是git merge --squash命令行Git实现的一个不必要的特殊功能,因为如果你真的希望使用--no-commit,你可以直接指定它。)

    由于这将创建一个与引入效果的提交没有任何关联的新提交,因此此方法显然完全不适合实现您想要的内容。

摘要

那些有权写入上游存储库的人可以将您的拉取请求合并到他们控制的计算机上的Git存储库中,并手动合并结果,然后将其推回GitHub上游存储库。这就是Tobias K.在评论中提到的内容。这样就可以实现您想要的目标。

如果GitHub添加了我希望它添加的合并模式,当前使用Web UI合并按钮合并您的拉取请求的用户将能够一步完成,而不需要涉及自己的计算机和Git命令行命令。但是如果没有额外的模式,他们就不能这样做。

他们现在实际使用的是变基合并模式。我们可以看到这一点:

所以现在在github上显示“此分支(origin/master)领先于上游/主分支1个提交,落后于上游/主分支1个提交。

如果他们使用合并模式,您会看到自己落后一个提交,但不会领先一个提交。这对您来说更友好,但在某些方面,对他们(以及其它使用他们存储库的用户)来说不太好。当他们使用变基合并时,他们最终会复制您的所有提交,因此如果您之前领先了k次提交,那么您将突然领先k并且落后k次:您领先的k次是您的提交,带有您的哈希ID,而您落后的k次是他们的副本您的提交,带有他们的哈希ID。

从上游的变基合并中恢复

请注意,您可以通过在自己的计算机上执行以下操作来从中恢复:

git fetch upstream
git checkout $branch
git rebase upstream/$branch
git push --force-with-lease origin $branch

(这里的$branch代表你的分支名称)。 fetch获取它们自己的提交副本。 checkout将您定位到rebase,而rebase执行rebase操作。1 git push将新提交发送到您的fork(如果它们还没有在那里),然后请求GitHub更改您的fork对于$branch指向最后一个已复制的提交,即使这会删除某些提交(就像使用--force一样)也会成功,但如果要删除的提交不完全符合预期,则会失败(使用--force-with-lease)。


1实际上,您可以在一步中完成此操作,因为git rebase允许您在开始rebase之前检出分支,但我认为以这种方式更清晰。 要在一步中完成操作,请使用git rebase origin/$branch $branch


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接