以下sed解决方案对我来说有效,如果直接从命令行中使用。它不使用任何临时字符串来切换\和/,而是依靠sed的y命令。但原始答案无效,请转到编辑以获取有效版本。
$ git --no-pager log --all --graph --decorate --oneline --color=always | tac | sed 'h
s!\( *[0-9a-z]\{7\} .*\)\{0,1\}$!\1!
y/\\\/_¯/\/\\¯_/
x
s!\(.*\)\( *[0-9a-z]\{7\} .*\)\{0,1\}$!\2!
x
G
s/\n//' | less -X +G -r
它假设SHA代码长度为7个字符,并使用它来“识别”不是前导序列的\,/,|,_,*和,这些我无法放在第一个s命令的搜索模式开头以及第二个s命令中第一个.的位置。 我不知道为什么当所有sed命令都放在使用sed的-f选项调用的脚本中时,我不能让它工作。正如@user1902689所指出的那样,sed脚本可能使任何人的眼睛流血,包括我自己,因为它们极其晦涩难懂。
在我看来,如果不使用
--color=always
参数,任务将很容易完成,这种情况下从
git log
中传出的文本与我们在屏幕上看到的相同;相反,使用
--color=always
参数会在文本中插入控制序列(例如
^[[33m
),以控制着色(不同分支使用不同颜色...)。
但是有彩色输出很好,所以我将git log --color=always ...
的输出重定向到文件,并查看了其中的内容,发现哈希总是出现在^[[33m
和^[[m
之间,其中^[
是通过按Ctrl+V然后按Esc得到的单个字符。这些基本上是由bash解释为设置颜色为黄色,然后返回白色的转义序列(link)。
哈希值是该行中不止一个7个字母数字字符的字符串(例如,提交主消息中可能有
thiswrd
),几乎肯定是
第一个,因此可以在其后安全使用贪婪表达式({{link1:
sed
没有非贪婪表达式}}),但
不能在其前使用(在哈希匹配正则表达式之前加上
.*
会使该正则表达式匹配该行上最后的7个字母数字字符字符串,这可能是
anytext
,并且哈希值将在
.*
中丢失)。为了允许以不会吞噬哈希值的方式使用贪婪的
.*
,我们可以用
s
命令在换行符
\n
之间包含哈希值,
这些换行符\n
不会被.*
中的.
匹配(因此必须明确输入),从而可以通过在搜索模式中显式使用一些
\n
来使用后续的
s
命令限制
.*
的贪婪性。
我认为以下代码(稍后会解释)并不是最终版本,因为它硬编码了用于获取彩色哈希字符串的颜色转义序列,但只要我尝试过,它就可以工作。
$ git --no-pager log --all --graph --decorate --oneline --color=always | tac | sed '
s/\(\(^[\[33m\)\([0-9a-z]\{7\}\)\(^[\[m\)\(.*\)\)/\2\n\3\n\4\5/
h
s/^.*\(\n[a-z0-9]\{7\}\n.*\|$\)/\1/
x
s/\n[a-z0-9]\{7\}\n.*$//
y/\\\/_¯/\/\\¯_/
G
s/\n\([a-z0-9]\{7\}\)\n/\1/
s/\n//' | less -X +G -r
每行包含三个部分
图形 开始颜色标签 哈希 结束颜色标签 消息
,或者只有第一个部分
图形
。
sed
字符串由9个命令组成,它们以我原来的答案为基础,但是以稍微不同的方式实现(特别是某些命令的顺序被倒转,以节省一个
x
命令)。
- 第一个
s
命令在 Hash
字符串 [0-9a-z]\{7\}
的每一侧放置一个换行符 \n
(如果此行中没有哈希,则不执行任何操作;请注意,在合并/分叉之前/之后的行中没有哈希或消息跟随它们)。这样做的目的是“隔离” Hash
。请注意,捕获组 \(...\)
根据开头标记 \(
的出现顺序进行编号,因此在替换字符串 \2\n\3\n\4\5
中:†
\2
指的是 ^[\[33m
,即 OpeningColorTag
(注意:^[
是通过按下 Ctrl+V,然后按下 Esc 获得的单个字符,而“真正的” [
必须用反斜杠 \
转义);
\3
指的是 Hash
,即 [0-9a-z]\{7\}
\4
指的是 ClosingColorTag
,即 ^[\[m
(这里对于 \2
所说的也适用);
\5
是后面的任何内容,即 .*
(隐含到行尾)。
现在模式空间(当前编辑的行)包含原始行和哈希标记两侧各有两个嵌入换行符的内容(
Graph OpeningColorTag\nHash\nClosingColorTag Message
),如果原始行中不包含哈希,则为未修改的原始行(
Graph
)。
第二点:
h
命令将模式空间“保存”到保持空间中(可以将其视为抽屉)。
现在,模式空间和保持空间具有相同的内容(
Graph OpeningColorTag\nHash\nClosingColorTag Message
或
Graph
)。
- 第二个
s
命令捕获并替换自身(/\1/
),丢弃它之前的所有内容(^.*
,即Graph OpeningColorTag
),使用\|
将备选项分隔在一个捕获组\(...\)
中,
- 换行符包含哈希和其后的所有内容(即提交主消息)
\n[a-z0-9]\{7\}\n.*
,
- 或行尾
$
,
现在模式空间包含\nHash\nClosingColorTag Message
,如果没有哈希,则为空字符串。
4.
x
命令交换模式空间和保持空间的内容,以便将多行
\nHash\nClosingColorTag Message
(或空字符串)保存在保持空间中,并且多行
Graph OpeningColorTag\nHash\nClosingColorTag Message
位于模式空间中,准备重新编辑。
5. 第三个
s
命令从模式空间中删除
\nHash
及其后面的所有内容。
现在,模式空间包含
Graph OpeningColorTag
。
6.
y
命令用第一个和第二个非转义
/
之间的每个字符替换第二个和第三个非转义
/
之间的对应字符。在这里,反斜杠和正斜杠都必须用反斜杠进行转义。(这应该是安全的,因为
OpeningColorTag
不应包含任何已翻译的字符。)
现在,模式空间包含
Hparg OpeningColorTag
,其中
Hparg
是
Graph
的“反转”版本(或仅为
Hparg
)。
现在,模式空间包含“Hparg OpeningColorTag\n\nHash\nClosingColorTag Message”(或仅为“Hparg \n”),我们从现在起不再关心保持空间。第四个“s”命令捕获“\n Hash \n”部分,并将其替换为“Hash”。现在,模式空间包含“Hparg OpeningColorTagHashClosingColorTag Message”或“Hparg \n”。最后一个“s”命令删除剩余的换行符“\n”。最终,模式空间包含“Hparg OpeningColorTagHashClosingColorTag Message”或“Hparg”。
步骤8和9不能合并在一起(<例如> <代码>s/\n\n\([a-z0-9]\{7\}\)\n/\1/),因为两个包含哈希的<代码>\n仅在该行包含哈希时存在(如果没有哈希,则第1点的第一个<代码>s无效),而第一个<代码>\n始终存在,因为它随着<代码>G命令一起出现。
†实际上,最外层的组\(
...\)
是不需要的(事实上也没有使用),因此可以将其删除,并且所有对其他捕获组的数字引用都可以减少1,例如s/\(\(^[\[33m\)\([0-9a-z]\{7\}\)\(^[\[m\)\(.*\)\)/\2\n\3\n\4\5/
可以更改为s/\(^[\[33m\)\([0-9a-z]\{7\}\)\(^[\[m\)\(.*\)/\1\n\2\n\3\4/
;但是我会在答案中保留不必要的组,因为它提供了提及捕获组编号并不是如此广泛知晓的机会。
git log --reverse
这个命令了吗? - jub0bs