我可以在不显式指定父级的情况下基于分支的分支点吗?

时间:2018-11-10 00:01:02

标签: git

我经常使用git rebase -i在发布历史之前对其进行清理。通常,我想将提交编辑回当前分支分支的任何位置,而不更改其分支点。我这样做是这样的:git rebase -i $(git show-branch --merge-base $PARENT_BRANCH HEAD)

这是一个难看的命令,我正在尝试寻找一种更好的方法。只要我愿意,我想让git自动找出合适的父母。

思考我想要的是git rebase -i --fork-point $(something)的别名,其中something查找具有当前分支的最近共同祖先的分支。它不需要是防弹的。如果它适用于线性主题分支,那么对我来说已经足够了。

3 个答案:

答案 0 :(得分:3)

首先,--fork-point用于远程跟踪名称。它的工作方式是将reflog用于所提供的上游。有关此的更多信息,请参见例如Git rebase - commit select in fork-point mode

第二个,但也许更重要的是,您可以运行git rebase upstreamgit rebase --onto newbase upstream,甚至仅运行git rebase。使用两个参数形式时,您将获得很多自由:

  • upstream 参数限制要复制的提交。稍后我们将有更多话要说。

  • newbase 参数选择在哪个提交之后添加副本。这里的实际哈希ID非常重要。

也就是说,当您使用使用--onto时,必须为--onto newbase 参数选择一个确切的提交。这意味着您对于用作 upstream 参数的内容可能会非常松懈。但是当您使用--onto时, upstream 会同时用于两个目的,因此 upstream 参数是一个需要非常仔细的精确度的参数。一个目的是宽松而自由的,而另一个目的不是。

这意味着您可以使用两个参数来重新获得想要的(但可能不需要)任何多余的松动,或者使用 no 参数来获得便利。 / p>

(由于问题的更新,下一部分构造很奇怪。)

git show-branch --merge-base X Y = git merge-base X Y

当给定多个参数时,git show-branch命令现在使用--merge-base--independent。仅使用两个参数,它就与git merge-base X Y做同样的事情,即,它找到修订版XY的合并基础。 (git merge-base现在也需要--independent,而不仅仅是假设章鱼策略,但这仅在使用三个或更多提交说明符时适用。)

我在这里更喜欢git merge-base,因为我认为它更明显(当然,键入的时间要短一些)。

没有参数,上游来自您的分支设置

每个分支可以有一个(但只有一个)上游设置。

任何分支 B 的上游设置通常为origin/B,因为我们倾向于将它们推送到GitHub或Bitbucket或某些公司的Web服务器,我们将其URL保留在名称{{ 1}},这样我们就不必一直输入它。如果您在origin上用尽了上游的资源,并且想要设置origin/将自动使用的 second 设置,那么您很不走运(但是继续阅读)。但是,如果您还没有用尽上游设备,只需将上游设备设置为您希望git rebase自动使用的设备。例如,如果您现在在git rebase上并希望它基于feature-X

develop

,现在$ git branch --set-upstream-to=develop feature作为其上游。运行develop(带有或不带有git rebase)将重新设置基础,就像您运行带有-i作为其 develop 参数的命令一样。

如果您已经用完了一个上游,则可以创建自己的别名:

upstream

(选择一些名称):这使您可以使用alias.name = !git rebase "$@" $(git config --get branch.$(git symbolic-ref --short HEAD).base) # git config配置一个额外的名称branch.feature-X.basedevelop提取当前分支名称,$(git symbolic-ref --short)获取设置,然后rebase将其用作其上游参数。

单个限制器和目标/ newbase参数的缺点

这里的缺点是,给定形式的图形:

git config --get

您将获得 o--o <-- develop / ...--o--o--o \ A--B--C <-- feature-X (HEAD) 开头之后的副本:

develop

当您要将副本保留在同一位置时,只需大惊小怪地提交它们的提交文本,或者将两个压缩在一起或类似的东西:

                  A'-B'-C'  <-- feature-X (HEAD)
                 /
             o--o   <-- develop
            /
...--o--o--o
            \
             A--B--C   [abandoned]

使用 o--o <-- develop / ...--o--o--o--A'-B'-C' <-- feature-X (HEAD) \ A--B--C [abandoned]

采用两参数形式,--onto参数选择目标提交:

--onto

现在副本将位于 o--o <-- develop or whatever / ...--o--o--* [pick this commit as target] \ A--B--C <-- feature-X (HEAD) 之后。实际上,将使用*确定要复制的提交集:即,从upstream..feature-X开始并向后工作可获得的提交,但不包括从 { {1}} 并向后工作。

现在,您只需要查找提交feature-X。如果您有两个名称,例如upstream*,则可以使用gitrevisions three-dot syntaxfeature-Xdevelop(当只有两个名称时,语法是对称的一个像这样的合并库),以指定提交develop...feature-X。这仅在相当新的Git版本中起作用:在较旧的版本中,请使用feature-X...develop*(带有两个提交哈希ID的行为都相同)。

已经将提交git show-branch指定为git merge-base目标,您可以再次允许分支的上游充当限制器。也就是说,您可以省略显式的 * ,因为它默认为实际的上游。而且,由于可以使用--ontoupstream语法,因此可以像在自己的答案中那样做一个非常简短的别名。

如果要保留单独的上游(@{upstream})和基础,则可以回到为每个分支名称配置额外值的想法。在这种情况下,您需要使用它两次,因此您可能需要一个完整的脚本来代替别名,而在脚本中可以执行错误检查:

@{u}

将此名称命名为origin/feature-X,放在您的路径中,现在您可以运行#! /bin/sh # git-base - rebase on the current branch's base setting . git-sh-setup branch=$(git symbolic-ref --short HEAD) || exit base=$(git config --get branch.$branch.base) || die "branch.$branch.base is not set" mbase=$(git merge-base $base HEAD) || die "there is no merge base" git rebase --onto $mbase "$@" $base

答案 1 :(得分:2)

在插入一个小时左右后,我想到了足够好的东西。如果分支中有一个上游集,并且如果所说的上游是我要与之进行比较的分支,则此命令会执行我想要的操作。

$ git rebase -i --onto @{upstream}...HEAD

那些三点与git-log和类似命令的作用不同。来自git-rebase documentation

  

在特殊情况下,您可以使用“ A ... B”作为合并基础的快捷方式   如果合并基数恰好是A和B。

因此,这就是说“找到HEAD及其上游的合并基础,并以此为基础”。通常,本地分支没有上游,但是可以设置,并且有一个gitconfig选项(autoSetupMerge)将为新分支自动执行。因此:

$ git config --global branch.autoSetupMerge always
$ git config --global alias.fixup 'rebase -i --onto @{upstream}...HEAD'
$ git branch childbranch -u parentbranch  # Repeat for other branches as needed.

之后,我可以使用以下命令轻松地将历史记录编辑回分支点:

git fixup

它适用于将来的所有分支机构。

(注意:请参见torek's answer,了解此处的详细信息)

答案 2 :(得分:2)

使用Git 2.24(2019年第四季度)时,不再git rebase -i --onto @{upstream}...HEAD

新的“ git rebase --keep-base <upstream>”会尝试查找要重新设置主题的原始基础,并在同一基础上重新构建基础,这在运行“ {{1} }”(及其有限变体形式“ git rebase -i”)。

该命令还学会了在更多情况下可以快速转发,而不必重播以重新创建相同的提交。

请参见commit 414d924commit 4effc5bcommit c0efb4ccommit 2b318aa(2019年8月27日)和commit 793ac7ecommit 359eceb(2019年8月25日)由Denton Liu (Denton-L)
帮助者:Eric Sunshine (sunshineco)Junio C Hamano (gitster)Ævar Arnfjörð Bjarmason (avar)Johannes Schindelin (dscho)
请参见commit 6330209commit c9efc21commit 4336d36(2019年8月27日)和Ævar Arnfjörð Bjarmason (avar)(2019年8月25日)。
帮助者:Eric Sunshine (sunshineco)Junio C Hamano (gitster)Ævar Arnfjörð Bjarmason (avar)Johannes Schindelin (dscho)
(由Junio C Hamano -- gitster --commit 640f9cd中合并,2019年9月30日)

  

重新设置基准:教导重新设置git rebase -x

     

常见的情况是,如果用户正在主题分支上,并且希望对中间提交或自动挤压进行一些更改,则他们将运行诸如

--keep-base
     

以保留合并库
  当向Git邮件列表贡献补丁系列时,这很有用,一个补丁系列通常始于当前的'git rebase -i --onto master... master '上。
  在开发补丁程序时,还进一步开发了“ master”,有时并不是将基准保持在“ master”之上的最佳方法,而是保持基本提交不变。

     

除此之外,希望测试主题分支中的单个提交但不进行任何更改的用户可能会运行

master
     

由于基于分支和上游合并基础的情况很常见,因此请引入git rebase -x ./test.sh master... master 选项作为快捷方式。

     

这使我们可以将上面的内容重写为

--keep-base
     

和:

git rebase -i --keep-base master
     

分别。

git rebase man page now includes

  

git rebase -x ./test.sh --keep-base master

     

设置将新提交提交到--keep-base的合并基础的起点。
  运行'<upstream> <branch>'等同于运行'git rebase --keep-base <upstream> <branch>'。

     

在正在上游分支上开发功能的情况下,此选项很有用。
  在使用该功能时,上游分支可能会前进,并且最好还是继续在上游之上重新部署,而是保持基本提交不变。

     

尽管此选项和git rebase --onto <upstream>... <upstream>都找到了两者之间的合并基础   --fork-point,此选项使用合并基础作为将在其上创建新提交的起点,而<upstream> and <branch>使用合并基础确定提交的集合,它将被重新设置。