原来的答案,这不起作用,所以转到工作版本的编辑
如果直接从命令行使用,以下sed 解决方案对我有用。它不使用任何临时字符串通过seds 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 个字符,并使用它来“识别”不是\、/、|、_、 * 和 <space>,我无法将它们放在第一个 s 命令的搜索模式的开头,并在第二个 s 命令中代替第一个 .。
我不知道为什么当所有 sed 命令都放在使用 seds -f 选项调用的脚本中时,我无法让它工作。
EDIT(上面的代码其实有问题)
正如@user1902689 所指出的,sed 脚本可以让任何人(包括我自己)眼睛流血,因为它们非常神秘。
在我看来,如果不使用--color=always,则任务将很容易完成,在这种情况下,文本从git log 输出
会和我们在屏幕上看到的一样;使用--color=always,相反,插入像^[[33m这样的控制序列穿插在文本中来控制着色(不同的分支颜色不同,...)。
但是有一个彩色输出很好,所以我将git log --color=always ... 的输出定向到文件,并查看它,发现哈希总是出现在^[[33m 和^[[m 之间,其中^[ 是按 Ctrl+V,然后按 Esc 可获得单个字符。这些本质上是 bash 解释为将颜色分别设置为黄色和变回白色的转义序列 (link)。
哈希值,它不是该行中唯一的 7 个字母数字字符串(eg thiswrd 可以在提交主消息中),几乎可以肯定是 first 一个,所以贪心表达式 (sed has no non-greedy expressions) 可以安全地在 之后 使用,而 不能在之前 (.* 在哈希匹配正则表达式之前该正则表达式匹配该行的最后一个 7 字母数字字符串,例如,它可能是 anytext,而哈希值会在 .* 的某处丢失)。为了允许以不吞噬散列的方式使用贪婪的.*,我们可以将散列括在换行符\n 这不匹配. 中的 .* (因此,它们必须显式键入) 使用 s 命令,以便我们可以在连续的 s 中“限制”.* 的贪婪通过在搜索模式中显式使用一些\n 命令。
我认为以下代码(稍后解释)不是确定的,因为它对用于获取彩色哈希字符串的着色转义序列进行硬编码,但只要我尝试过,它就可以工作。
$ 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
每一行包含三个部分Graph OpeningColorTagHashClosingColorTag Message,或者只包含第一部分Graph。
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/) 并丢弃它之前的所有内容 (^.*, ie Graph OpeningColorTag),或者 (\| 分隔捕获组中的替代品\(...\))
- 换行符封闭的散列及其后面的所有内容(即提交主消息)
\n[a-z0-9]\{7\}\n.*,
- 或行尾
$,
现在模式空间包含\nHash\nClosingColorTag Message,如果没有散列,则为空字符串。
-
x命令交换pattern和hold space的内容,使得多行\nHash\nClosingColorTag Message(或空字符串)保存在hold space,多行Graph OpeningColorTag\nHash\nClosingColorTag Message在pattern space,准备就绪重新编辑。
- 第三个
s 命令从模式空间中去除\nHash 及其后面的所有内容。
现在模式空间包含Graph OpeningColorTag。
-
y 将前两个非转义 / 之间的每个字符替换为第二个和第三个非转义 / 之间的对应字符。这里反斜杠和正斜杠都必须用反斜杠转义。 (这应该是安全的,因为OpeningColorTag 不应包含任何已翻译的字符。)
现在模式空间包含Hparg OpeningColorTag,其中Hparg 是Graph 的“反转”版本(或仅Hparg)。
-
G 命令获取保留空间的内容并将其附加到(因此大写的G;小写的g 将复制到 而不是附加到)模式空间,中间有一个换行符\n。
现在模式空间包含Hparg OpeningColorTag\n\nHash\nClosingColorTag Message(或仅Hparg\n),从现在开始我们不再关心保持空间。
- 第四个
s 命令捕获\nHash\n 部分并将其替换为Hash。
现在模式空间包含Hparg OpeningColorTag\nHashClosingColorTag Message 或Hparg\n。
- 最后一个
s 命令删除剩余的换行符\n。
最后,模式空间包含Hparg OpeningColorTagHashClosingColorTag Message 或Hparg。
步骤 8. 和 9. 不能融合在一起(eg s/\n\n\([a-z0-9]\{7\}\)\n/\1/),因为只有当行包含哈希时,包含哈希的两个 \n 才存在(第一个 @987654436第 1 点的@。如果没有哈希,则不执行任何操作),而第一个 \n 始终存在,因为它带有 G 命令。
† 实际上最外部的组\(...\) 是不需要的(确实没有使用),因此可以将其删除,并且所有对其他捕获的数字引用组可以减1,eg 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/;但我会在答案中保留不必要的组,因为它有机会提及不那么广为人知的捕获组编号。