0

我创建了一个测试别名,在这个别名中,我希望能够只记录我所在的当前分支(请记住,这是日志的简化版本,最后一个有更多细节、颜色和很快)。

我的别名如下所示:

test = "!git log \"$(git rev-parse --abbrev-ref HEAD)\""

但是当我输入时,git test我得到了分支上的 2 个提交以及来自不同分支的所有先前提交(我不想要)。

任何想法?谢谢

4

1 回答 1

1

此处显示的别名没有错误,这是您的期望(您对 Git 的“在分支上”的含义的看法)是错误的:也就是说,您所说的“在分支上”是什么意思,以及Git的“在一个分支上”的意思是什么分支”,根本不同意。

基本问题是 Git 分支并不意味着人们期望它们的意思。(有人可能会争辩说这意味着 Git 是错误的。其他一些 VCS,例如 Mercurial 以您希望 Git 定义它们的方式定义分支。)在 Git 中,分支名称仅指向一个提交,Git 称之为提示提交那个分支。

然而,每个提交都指向某个数量(通常是一个)的先前或提交。Git 使用它来将提交串在一起用于多种目的,包括用git log. 我们可以通过在纸上或白板上或在 StackOverflow 答案中绘制它,绘制带有箭头的分支名称,指向分支中包含的最后一个提交,然后进行该提交——其“真实名称” " 是那些大而丑陋的提交哈希 ID 之一,但我们将在这里使用单个字母 - 有一个箭头,指向它的父级,等等:

... <-F <-G <-H   <-- master

什么git log是从分支名称指向的提交开始,并显示它。然后它移动到提交的父级,并显示出来。然后它会进一步向后移动(向左)并显示该提交,依此类推。1

所有 Git 内部链接总是向后的,所以只要我们将较新的提交放在右侧,我们就不需要绘制内部箭头。我们只知道他们倒退了。所以让我们画一个更复杂的设置:

...--F--G--H   <-- master
            \
             I--J   <-- feature

名称feature指向 commit J,因此 commitJ位于功能分支上。提交J指向I,哪个指向H,哪个指向G,等等。所以每个提交都在分支上feature,即使提交H也是分支尖端提交master。向上提交H全部打开master,因此提交通过H两个分支上。

你想要在这里做的,而不是记录当前分支中包含的所有提交——这很简单git log——是让 Git 记录包含在当前分支中包含在其他一些分支中的提交. 棘手的部分在于弄清楚如何排除这些提交。

一种方法是列出每个分支名称,然后去掉当前分支名称,然后告诉git log为我列出当前分支中包含的每个提交,从 开始HEAD,但在到达任何其他分支中包含的任何提交时停止列出。 为此,您可以获取当前分支名称(就像您现在所做的那样,或以其他方式)并将其从所有分支的列表中排除(您会以某种方式获得):

git log HEAD --not br1 br2 br3 br4

(如果其他四个分支通过 命名br1br4

不过,这通常不是必需的。一般来说,每当你在某个分支上工作时,你会指定一些其他名称——有时是另一个分支名称,有时是一个远程跟踪名称,例如origin/master——作为当前分支的upstream。每个分支可以只有一个上游设置(或根本没有设置),一旦你有上游设置,你可以使用符号表示法@{upstream}或短版本@{u}来引用它:

git log HEAD --not @{u}

有一个更短的语法,因为它经常很有用:在提交说明符前加上帽子^字符意味着“不是”,所以你可以写:

git log HEAD ^@{u}

然后还有一个更短的语法,因为很常见:

git log @{u}..HEAD

字面意思是从当前 HEAD 提交可以到达的所有提交,除了从当前分支的上游可以到达的所有提交。

所以你可能想要的只是@{u}..HEAD符号。这与明确排除所有其他分支不同。例如,假设我们有一个部分看起来像这样的图:

       M   <-- origin/br2
      /
...--H   <-- origin/master, origin/br1
      \
       I--J   <-- br1
           \
            K--L   <-- br2 (HEAD)

进一步假设上游br2origin/br2。询问origin/br2..br2(ie, @{u}..HEAD) 中的提交意味着您将选择提交L, K,JI. 请求包含br2没有其他分支(即 not br1)的提交只会得到Land K。如果那——得到公正LK——是你想要的,那么你实际上需要列举所有的分支。

(枚举所有分支的技巧是使用git for-each-ref前缀。如果您要编写大量脚本或花哨的别名,refs/heads/您也应该考虑使用读取当前分支名称。这些命令和, 是什么Git 调用管道命令,用于编写脚本和复杂的别名。它们的行为方式更加严格定义,针对计算机使用的方式,而不是像or之类的“面向用户”命令。称那些“面向用户”有点有点可笑,但它们显然比例如,面向用户。)git symbolic-refgit for-each-refgit symbolic-refgit loggit diffgit diff-tree


1这稍微简化了一点。在查看多个分支名称的情况下,或者在向多个父级合并提交之后,git log必须以某种方式线性化图拓扑。它通过优先级队列执行此操作,显示下一个“最高优先级”提交并将该提交的父级添加到队列中。但是,对于简单的线性链,Git 在历史中倒退的想法就足够了。

于 2018-01-04T18:03:54.360 回答