Git: 如何更新 merge-base 创建的分支

Git: how to update branch made by merge-base

假设我有 2 个分支:v1.0development。 我们的过程是使用以下方法创建本地分支:

git merge-base v1.0 development
git checkout <commit-hash>
git checkout -b <new-branch-name>

假设我的一位同事遵循相同的流程并最近进行了更改:

git checkout v1.0
git merge <his-local-branch-name>
git push
git checkout development
git merge <his-local-branch-name>
git push

我的问题是,如何使用他最近的更改轻松地更新我的本地分支?

我所做的是使用 merge-base 创建另一个包含最近更改的分支,并将其与我在本地所做的更改合并。

但是否存在一些简单的方法?我在考虑 git merge <last-commit-hash> 之类的东西,但它会产生很多冲突。

好吧...所以听起来 development 是代表以前版本的长期分支 - 很像 gitflow 中的 master

听起来 v1.0 是一个长期存在的分支,您可以在其中组装下一个版本,很像 gitflow 中的 develop

并且给定的本地分支可能类似于功能分支(在这种情况下,您会将其合并到 v1.0)或类似于修补程序(在这种情况下,您将其合并到两者 v1.0development)。奇怪的是,您似乎总是创建本地分支,以便它们 可以 合并到两者。 (所以你不知道,在创建分支时,你是否会合并到 development?因为如果不是这种情况,那么在合并基础上使每个分支 "start over" 似乎都有一些不必要的合并解决成本...但我离题了。)

让我们通过图片逐步了解您的场景。您从

开始
A -- x <--(development)
 \
  Z <--(v1.0)

然后你创建一个本地分支

A -- x <--(development)
|\
| Z <--(v1.0)
 \
  B -- C <--(feature)

并且您的同事创建了本地分支机构

A -- x <--(development)
|\
| x -- O <--(hotfix)
|\
| Z <--(v1.0)
 \
  B -- C <--(feature)

(请耐心等待;我意识到可能永远不会有一个包含所有这些分支的回购协议,但无论如何我们只看一下 "big picture"...)

所以你的同事合并到两个长期存在的分支

A -- x -- M <--(development)
|\       /
| x --- O <--(hotfix)
|\       \
| Z ----- M <--(v1.0)
 \
  B -- C <--(feature)

请注意,从现在开始,Odevelopmentv1.0 的合并基础。但是您的分支是在合并基础 A 时创建的,所以现在我们来回答您的问题:如何将 hotfix 放入您的分支。

到目前为止 hotfix 是共享历史不可或缺的一部分,因此您可能不想做任何重写 and/or 复制其提交的更改的事情。

您可能不想将 v1.0 合并到您的分支中,因为将 Z 混合到您的分支中似乎 运行 与在合并基地。

所以你真的只想将 O 合并到你的分支中。现在让我们换个角度,看看你的本地仓库会如何看待事物,如果我按字面意思理解你的术语 "local branches" (意味着你没有 hotfix 分支):

A -- x -- M <--(development)
|\       /
| x --- O
|\       \
| Z ----- M <--(v1.0)
 \
  B -- C <--(feature)

现在,鉴于 feature 也是 也是 本地的(仅存在于您的存储库中),一种选择是将其重新设置为新的合并基础 - 这似乎就像它保留在您的工作流程中一样。

git rebase $(git merge-base development v1.0) feature

会给你

A -- x -- M <--(development)
|\       /
| x --- O -- B' -- C' <--(feature)
 \       \
  Z ----- M <--(v1.0)

此时B'C'都是代码的未测试状态。理想情况下,您应该同时测试它们并解决任何问题(不过,如果 B' 中存在问题,那说起来容易做起来难),这样您仍然会有一个干净的历史记录。

另一个选项可以避免 "untested commits" 问题,但会创建 "messier"(虽然可以说更准确)历史记录,是简单地将合并基础合并到您的分支中。

git checkout feature
git merge $(git merge-base v1.0 development)

这给你类似的东西

A -- x -- M <--(development)
|\       /
| x --- O -----------
|\       \           \
| Z ----- M <--(v1.0) \
 \                     \
  B -- C -------------- M <--(feature)

其中,在走了很长一段路要说 "why" 之后,意味着我们基本上做了您已经做过的事情,只是跳过了为合并创建分支的步骤,因为我们可以只引用合并基础直接。

这是有道理的。您已经弄清楚要与您的分支合并的更改 - 您真的 不想 更改您正在合并的提交。所以我们能做的就是找到一种更简单的方法来引用这些更改。

What I did, was to create another branch with recent changes using merge-base and merge it with my changes made locally.

这是一种方法 (Mark illustrates the rebase approach )

但并非如此,有了 Git 2.22(2019 年第 2 季度),您将不必做:

git merge-base v1.0 development
git checkout <commit-hash>
git checkout -b <new-branch-name>

相反,你会这样做:

git checkout -b <new-branch-name> v1.0...development

参见 commit e3d6539, commit 27434bf (27 Apr 2019) by Denton Liu (Denton-L)
Helped-by: Junio C Hamano (gitster).
(由 Junio C Hamano -- gitster -- in commit 4ac8371 合并,2019 年 5 月 19 日)

branch: make create_branch accept a merge base rev

When we ran something like

$ git checkout -b test master...

it would fail with the message

fatal: Not a valid object name: 'master...'.

This was caused by the call to create_branch where start_name is expected to be a valid rev.
However, git checkout allows the branch to be a valid merge base rev (i.e. with a "...") so it was possible for an invalid rev to be passed in.

Make create_branch accept a merge base rev so that this case does not error out.

As a side-effect, teach git-branch how to handle merge base revs as well.