Git 一次又一次地合并提交

Git is merging commits over and over

我有一个包含两个分支的 Git 存储库:masterRelease/v1.0。在 master 上有一个分支策略,我不能直接推送给它,我只能通过 Pull Requests 做出贡献。

现在,我正在修复 Release/v1.0 上的一个错误,并想将其合并到 master 中。 因此,我执行以下操作:

// create a new branch from master where I merge the changes from Release/v1.0
git checkout -b merge-to-master

// start the merge
git merge origin/Release/v1.0

// merge gets committed automatically, so I just need to push (to upstream if the branch doesn't exist remotely)
git push

现在我正在发出从 merge-to-mastermaster 的合并请求。 PR 完成后,我在 master.

中进行了所有更改

合并按预期进行。但是,当我再次开始合并时,我希望这些提交不会再次出现,因为它们已经被合并了。但是提交在合并视图中一次又一次地出现。

我假设合并信息没有写正确? 现在我的问题是:我做错了什么吗?如何避免重复出现相同的提交?

@更新:

另外,当我想删除一个本地分支(git branch -d v1.0/212760-wrong-status - 这是一个功能分支)时,它告诉我:

error: The branch 'v1.0/212760-wrong-status' is not fully merged.
If you are sure you want to delete it, run 'git branch -D v1.0/212760-wrong-status'.

但是,我已经向 Release/v1.0 提交了 PR(并完成了),所以我认为它已完全合并。但是为什么 Git 有不同的意见呢? :)

认为,但无法根据提供的信息确定这就是关键:

I can [only] contribute through Pull Requests

当您向其他人 发送拉取请求时,您是在要求他们 采取一些行动。我们需要知道他们是谁。他们是谁?让我们看看他们到底在做什么!

让我们从这个开始:

v1.0/212760-wrong-status

我认为这意味着你已经完成了:

git checkout -b v1.0/212760-wrong-status v1.0

或您自己的存储库中的等效项,然后在此处进行一两次提交以修复错误。然后你做:

git checkout -b merge-to-master master
git merge origin/Release/v1.0
git push

步。 (如果你画出实际的步骤和实际的提交哈希 ID 以及这里涉及的分支名称,这将有很大帮助,这样一切都是具体的实际哈希 ID。)请注意,git push 会将实际提交推送到一些其他存储库,例如您称为 origin 的存储库或您称为 upstream 的(可能不同/独立的)存储库;每次推送都会要求 other Git 设置一些分支名称以指向特定的提交。


在这一点上,让我们也给每个人起个名字,这样我们就知道谁在采取什么行动。我会称你为 Dave 并谈论 Dave 的提交,它具有你可以在你的一个或多个存储库中看到的特定哈希 ID(运行 git log --all --decorate --oneline --graph 以查看缩写的哈希 ID 和图表)。我不知道操作上游存储库的人的名字;让我们称她为 Ursula,以 U 开头代表 Upstream。

此外,如今,"pull request" 通常意味着像 GitHub 或 Bitbucket 这样的托管服务。 GitHub 特别提供了一个可点击的按钮 "merge pull request",并附有一个下拉菜单。单击下拉菜单而不是 "merge pull request" 按钮会提供三个选项,这些选项会更改单击按钮的操作:

  • 合并。这是一个直接合并:Ursula 将添加到 Ursula 的(上游)存储库,Dave 从 Dave 的 web-hosted 存储库副本中进行的一个或多个提交。 Dave 的提交将具有 Dave 提交的哈希 ID,因为它们 Dave 的提交。 Ursula 将使用一个新的唯一哈希 ID 创建一个新提交。

  • 变基并合并。这使得戴夫的提交 副本 。 Ursula 会将这些副本添加到 Ursula 的存储库,此后 Dave 的提交基本上已失效——Dave 应该用 Ursula 的副本替换它们。

  • 压缩并合并。这使得一个单独的新提交,专门属于 Ursula,与 Dave 的 N 提交相同的 changes(但是 N 很大 是,即使它只是 1)。如果 N = 1 这与 "rebase and merge" 非常相似,尽管默认的提交日志消息不同。在任何一种情况下,Ursula 的新单次提交都会避免 Dave 的所有原始提交,就像 rebase-and-merge 模式一样。

一旦 Ursula 完成,您 (Dave) 就可以 git fetch 她的提交——总是至少有一个她的提交——来自您使用单词 upstream 拼写的地址。如果她的是真正的合并,她将合并您在 v1.0/212760-wrong-status 上所做的提交(我相信)。也就是说,具有相同哈希 ID 的 精确提交 现在出现在 Ursula 的存储库中。她合并到她的 master 中有一个 不同的 哈希 ID 来自你合并到 你的 master 中,但它确实使用你的原始提交。

然后,如果您在计算机上自己的存储库中(不是 GitHub 或其他网站上的 origin),请检查您的 master 和 fast-forward 它到她的合并提交(现在显示 git log --all --decorate --oneline --graph,在你的 upstream/master 上)然后 运行:

git branch -d v1.0/212760-wrong-status

您的 Git 将看到作为您的 v1.0/212760-wrong-status 尖端的提交已 合并到您当前的分支 master。也就是说,通过查看 Ursula 的合并提交的第二个父级,您的 Git 可以追踪从您的 master 到该特定提交的直线。因此该提交包含在 master 中,并且 Git 将很乐意从您的本地存储库中删除 name v1.0/212760-wrong-status

既然不是这种情况,我们可以得出结论,乌苏拉一定是使用了点击按钮的"rebase and merge"或"squash and merge"模式来制作您提交的 副本。如果副本足够好——如果你对 Ursula 复制你的提交的方式感到满意——你可以安全地强行删除你的分支名称,丢失你的原始提交(最终永远永远,尽管你的 reflogs 可能会再保留它 30 天左右,如果你改变主意了)。

换句话说,如果 Ursula 复制了 你对一个新的、据称改进的提交的提交,它避免了你原来的提交,现在由你——Dave——决定是否应丢弃 Dave 的原始提交以支持此新副本。这就是你的 Git 告诉你的。

如果你像这样丢弃你自己的提交,你的下一个拉取请求可以——取决于你如何构建它 ��re-introduce 这个提交。是否会像往常一样取决于实际的提交图。提交图——git log --graph 绘制的图——才是最重要的。您通过拉取请求提供实际提交,这些提交与实际图段一起提供。 如果他们接受了你的实际提交,你的图表片段就会被添加,现在你和他们共享图表。但是如果他们接受你的提交,他们将添加一些 other 具有不同图段的提交。您的 Git 会将 他们的 提交添加到 您的 图表中,从而为您提供一个包含大量提交副本的 ever-bigger 图表。这取决于您决定如何处理它。