且构网

分享程序员开发的那些事...
且构网 - 分享程序员编程开发的那些事

git中的合并拉取请求导致上游分支超前于原点

更新时间:2022-05-11 04:58:33

问题的核心在于GitHub. (稍后我会详细介绍.)因此,您的问题的答案是都是和不是:

The core of the problem lies inside GitHub. (I'll go into detail in a moment.) The answer to your question is thus both no and yes:

是否有任何方法可以推入上游,而无需对上游进行额外的提交. 是否仅合并拉取请求,以使上游/母版和原始/母版分支均匀?

这里有四类人:

  1. 那些由GitHub自己编写的程序.它们控制在Web浏览器中显示的内容,即,您在页面上看到的合并此请求"绿色按钮,该按钮的边缘有一个小下拉箭头,如果单击该按钮,则可以选择以下三种类型之一合并.

  1. Those that program GitHub itself. They control what appears in one's web browser, i.e., that green button you see on the page that says "Merge this pull request", which has a small dropdown arrow on the edge that, if clicked, let you select one of three types of merge.

三种合并类型包括您想要的操作.因此,如果他们更改以添加第四种类型的合并,或更改现有三种类型的合并中的一种,或者按照这些方式进行更改,则可以使第3组中的每个人都可以执行您想要的操作.

The three types of merge do not include the action you would like. So if they changed this to add a fourth type of merge, or changed one of the existing three, or something along those lines, that could give everyone in group 3 the ability to do what you want.

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

Those with administrative access to the upstream repository. They can git push straight to the upstream repository. This means they can use command-line Git (not GitHub at all) to perform the action you would like, then run git push to update the repository on GitHub.

具有通过GitHub提供的界面对上游存储库的写访问权,但对上游存储库具有不是管理权限的人.他们不能做您想做的事情-至少要等到第1组的人将其添加为选项时,才能这样做.

Those with write access, but not administrative access, to the upstream repository, through the GitHub-provided interface. They cannot do what you want—at least, not until and unless the Group 1 folks add it as an option.

那些没有写访问权限(可能包括您自己)的用户:他们无法做到这一点.

Those with no write access (presumably including yourself): they cannot do it.

现在,对于那些GitHub clicky按钮-或更确切地说, button 单数,具有三种模式:提供的三种模式以这种方式标记:

Now, as to those GitHub clicky buttons—or rather, button singular, with three modes: the three offered modes are labeled this way:

  • 合并.

您可能会认为这样做可以完成任务,但不会这样做,因为它运行的是与git checkout branch && git merge --no-ff -m message hash等效的命令. branch 很明显, message 部分是Merge pull request #number from repository. hash 部分比较棘手:这是在refs/pull/number/head下找到的哈希ID.这是您通过单击比较并提取请求" clicky按钮单击的提交的特定提交的提交ID.

You might think this would do the job, but it does not, because it runs the equivalent of git checkout branch && git merge --no-ff -m message hash. The branch is obvious enough, and the message part is Merge pull request #number from repository. The hash part is trickier: it's the hash ID found under refs/pull/number/head. This is the commit ID of the particular commit you submitted, through your clicking of the "compare and pull request" clicky buttons.

如果GitHub使用与git checkout branch && git merge --ff-only hash等效的 branch hash ,您将获得所需的内容.当然,将不会包含文本Merge pull request ...的提交.但这没关系. (这是我希望他们添加的新模式.也许可以将其称为 Merge而无需额外的提交快速转发.)

If GitHub were to use the equivalent of git checkout branch && git merge --ff-only hash, with the same branch and hash, you would get just what you wanted. Of course, there would be no commit containing the text Merge pull request .... But that would be fine. (This is the new mode I wish they would add. They could call it Merge without additional commit or Fast-forward, perhaps.)

重新合并并合并.

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

This adds the pull-request commits—there might be more than one—that are not currently on the branch, to the branch. It runs the equivalent of git checkout branch && git rebase --force-rebase hash (perhaps with --merge or --strategy merge as well). The end result is that the commits from the pull request are copied, not merged, to new commits with new and different hash IDs. The merge request is completed without adding a merge commit, so there is no Merged pull request ... message.

您可能会认为,在要复制的提交或提交已经位于正确位置的情况下(即,在单击按钮之前刚过去分支的尖端),GitHub不会复制提交,而是按原样使用它们,如果它们运行了git rebase without --force-rebase--no-ff的等效项,则会发生这种情况.但这种情况并非如此.我不知道是否有一些很好的理由(在GitHub内部).

You might think that, in the case where the commit or commits to be copied are already in the correct position—i.e., just past the tip of the branch before clicking the button—GitHub would not copy the commits, and would instead just use them as is, as would happen if they ran the equivalent of git rebase without --force-rebase or --no-ff. But this is not the case. Whether there is some good (internal to GitHub) reason for this, I do not know.

压缩并合并.

这等效于git checkout branch && git merge --no-commit --squash hash && git commit -m message. (这里的--no-commit是多余的:--squash表示--no-commit.这是git merge --squash的命令行Git实现的不必要的特性,因为如果您真的想要 --no-commit可以指定它.)

This does the equivalent of git checkout branch && git merge --no-commit --squash hash && git commit -m message. (The --no-commit here is redundant: --squash implies --no-commit. This is an unnecessary peculiarity of the command line Git implementation of git merge --squash, since if you really want --no-commit, you could just specify it.)

因为这产生了一个新的提交,而该新的提交与带来其效果的提交没有任何关系,所以这显然完全不适合实现您想要的.

Because this makes a new commit that is not tied in any way to the commits whose effect is brought in, this is clearly totally unsuited to achieve what you want.

对上游存储库具有写访问权的用户可以将您的拉取请求放入他们控制的计算机上的Git存储库中,手动合并,然后将结果推回到GitHub上的上游存储库中.这就是 Tobias K.在评论中引用.那将实现您想要的.

Those who have write access to the upstream repository can take your pull request into a Git repository on a computer they control, merge it manually, and push the result back to the upstream repository on GitHub. This is what Tobias K. refers to in a comment. That would achieve what you want.

如果GitHub要添加我希望添加的合并模式,则当前将您的拉取请求与Web-UI合并按钮合并的用户将能够一步完成此操作,而无需涉及自己的计算机和Git命令行命令.但是如果没有这种额外的模式,他们将无法实现.

If GitHub were to add the merge-mode I wish they would add, the users who currently merge your pull request with the Web-UI merge button would be able to do it in one step, without involving their own computers and Git command-line commands. But without that additional mode, they cannot.

他们现在实际使用的是 Rebase and merge 模式.我们可以这样判断:

What they are actually using right now is the Rebase and merge mode. We can tell because of this:

所以现在在github上显示"此分支(源/主节点)在前面提交1次,在上游/主节点后面进行1次提交."

如果他们使用 Merge 模式,您会发现自己落后于一个提交,而不是领先于一个提交.这对您会更友好,但是在某些方面对他们自己(可能还有他们存储库的其他用户)不太友好.当他们使用 Rebase和merge 时,他们最终会复制所有提交,因此如果您之前是 k 个提交,那么您突然会成为 k k 后面:您处于领先位置的 k 您的提交,而您的哈希ID,后面的 k 是提交的副本,带有哈希ID.

If they were to use the Merge mode, you would see yourself being one commit behind, but not one commit ahead. This would be more friendly to you, but in some ways, less nice to themselves (and perhaps other users of their repository). When they use Rebase and merge they wind up copying all of your commits, so if you were k commits ahead before, you will suddenly be k ahead and k behind: the k that you are ahead are your commits, with your hash IDs, and the k that you are behind are their copies of your commits, with their hash IDs.

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

Note that you can recover from this by doing, on your own computer, the following:

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

(其中$branch代表您的分支名称). fetch获得他们的提交副本. checkout为您定位要由rebase执行的基准. 1 git push将新提交发送到您的fork(如果它们尚未存在),然后请求GitHub更改您的前叉$branch的想法指向最后一个这样的复制提交,即使此删除某些提交也成功(就像通过--force一样),但是如果提交是--force-with-lease,则失败(--force-with-lease)掉落的东西与预期的不完全一样.

(where $branch represents your branch name). The fetch obtains their copies of your commits. The checkout positions you for the rebase, which the rebase performs.1 The git push sends the new commits to your fork (if they are not already there) and then requests that GitHub change your fork's idea of $branch to point to the last such copied commit, succeeding (as if by --force) even if this drops some commits, but failing (--force-with-lease) if the commits being dropped are not exactly those expected.

1 实际上,您可以一步完成此操作,因为git rebase允许您在开始重新设置基准之前签出一个分支,但是我认为这种方式更清楚.要一步完成,请使用git rebase origin/$branch $branch.

1You can actually do this in one step as git rebase lets you check out a branch before starting the rebase, but I think it is clearer this way. To do it in one step, use git rebase origin/$branch $branch.