我创建了一个测试别名,在这个别名中,我希望能够只记录我所在的当前分支(请记住,这是日志的简化版本,最后一个有更多细节、颜色和很快)。
我的别名如下所示:
test = "!git log \"$(git rev-parse --abbrev-ref HEAD)\""
但是当我输入时,git test
我得到了分支上的 2 个提交以及来自不同分支的所有先前提交(我不想要)。
任何想法?谢谢
此处显示的别名没有错误,这是您的期望(您对 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
(如果其他四个分支通过 命名br1
)br4
。
不过,这通常不是必需的。一般来说,每当你在某个分支上工作时,你会指定一些其他名称——有时是另一个分支名称,有时是一个远程跟踪名称,例如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)
进一步假设上游br2
为origin/br2
。询问origin/br2..br2
(ie, @{u}..HEAD
) 中的提交意味着您将选择提交L
, K
,J
和I
. 请求包含br2
但没有其他分支(即 not br1
)的提交只会得到L
and K
。如果那——得到公正L
和K
——是你想要的,那么你实际上需要列举所有的分支。
(枚举所有分支的技巧是使用git for-each-ref
前缀。如果您要编写大量脚本或花哨的别名,refs/heads/
您也应该考虑使用读取当前分支名称。这些命令和, 是什么Git 调用管道命令,用于编写脚本和复杂的别名。它们的行为方式更加严格定义,针对计算机使用的方式,而不是像or之类的“面向用户”命令。称那些“面向用户”有点有点可笑,但它们显然比例如,更面向用户。)git symbolic-ref
git for-each-ref
git symbolic-ref
git log
git diff
git diff-tree
1这稍微简化了一点。在查看多个分支名称的情况下,或者在向多个父级合并提交之后,git log
必须以某种方式线性化图拓扑。它通过优先级队列执行此操作,显示下一个“最高优先级”提交并将该提交的父级添加到队列中。但是,对于简单的线性链,Git 在历史中倒退的想法就足够了。