git hook+expand+unexpand 化解空格与 TAB 之争

发布于 2023-03-19 23:27:24 字数 3874 浏览 57 评论 0

SPACE 与 TAB 之争由来已久,但是有一个观点是两派都公认赞同的,那就是 不能两者混用

TAB_VS_SPACE.jpg

为此,Linux 很贴心的提供了 expandunexpand 命令来帮助我们进行 TABSPACE 之间的相互转换。

使用 expand 将 TAB 转换为 SPACE

使用 expand 将 TAB 转换为 SPACE 的方法很简单,直接执行 expand 文件 就会把 文件 中的所有 TAB 都替换空格(默认按8个空格进行对齐)了。

例如假设我们有下面一个测试文件

cat -T /tmp/test
^Ihello  ^Itest^I

其中 cat-T 选项文件内容其中的 TAB 显示为 ^I,我们现在来用 expand 对其进行转换

expand /tmp/test |cat -T
hello   test    

如果觉得使用8空格对齐太空了,那么可以使用 -t 选项指定对齐的空格数。比如下面命令按4个空格进行对齐:

expand -t 4 /tmp/test |cat -T
hello   test    

另一方面,我们在写代码时可能只需要转换行首的空格,而字符串中的 TAB 是不需要进行转换的,那么就可以使用 -i 选项指定 expand 只对行首的空格进行转换:

expand -i -t 4 /tmp/test |cat -T
hello  ^Itest^I

使用 unexpand 将 SPACE 转换为 TAB

unexpand 从名字上就知道它是 expand 的反操作,即把 SPACE 转换为 TAB,他们的使用方法也很类似,但是有一点不同就是 expand 在默认情况下替换所有的 TAB,当只替换行首的 TAB 时需要指定 -i 选项,而 unexpand 在默认情况下只替换行首的 SPACE,若要替换 SPACE 时需要明确指定 -a 选项.

还是例如假设我们有下面一个测试文件

cat -T /tmp/test.space
hello   test    

我们现在来用 unexpand 对其进行转换

unexpand /tmp/test.space |cat -T
^Ihello   test    

你会发现只替换了前面的8个空格为 TAB

同样我们可以使用 -t 选项指定 TAB 对齐的空格数。比如下面命令按4个空格进行对齐:

unexpand -t 4 /tmp/test.space |cat -T
^I^Ihello^Itest^I

结果的前面是两个 TAB,也就是每四个空格转换为了一个 TAB,若要将所有的空格全部替换,那么需要明确使用 -a 选项进行转换:

unexpand -a -t 4 /tmp/test.space |cat -T
^I^Ihello^Itest^I

使用 git hook 实现代码的自动转换

在确定好规范使用 SPACE 或 TAB 后,我们可以借助 git 的 pre-commit hook 来让我们在代码提交前自动进行规范化的转换。比如,假设我们定义的规范是只使用 SPACE 规范,那么我们可以创建下面的 pre-commit hook

if git rev-parse --verify HEAD >/dev/null 2>&1
then
  against=HEAD
else
  # Initial commit: diff against an empty tree object
  against=$(git hash-object -t tree /dev/null)
fi
# Redirect output to stderr.
exec 1>&2
TMPFILE=$(mktemp)
trap 'rm -f ${TMPFILE}' EXIT
for file in $(git diff --cached --name-only --diff-filter=ACM $against)
do
    # 只对text类文件进行转换
    if file "${file}" |grep 'text' 2>&1 >/dev/null;then
        echo "expanding ${file}"
        expand -i -t 4 "${file}" > "${TMPFILE}"
        cp "${TMPFILE}" "${file}"
        git add "${file}"
    fi
done

将该文件保存为 .git/hooks/pre-commit,然后添加可执行权限后,每次提交就会对文件进行格式化处理了:

lujun9972:a/ (master U:1 ?:3✗) $ cat -T test
^Ihello  ^Itest^I^I
lujun9972:a/ (master U:1 ?:3✗) $ git commit -a -m update
expanding test
[master 88b2f66] update
 1 file changed, 1 deletion(-)
lujun9972:a/ (master ?:3✗) $ cat -T test
    hello  ^Itest^I^I

然后我们再通过 post-commit hook 将转换的文件再转换回 TAB 来:

TMPFILE=$(mktemp)
against="HEAD^1"
trap 'rm -f ${TMPFILE}' EXIT
for file in $(git diff --cached --name-only --diff-filter=ACM $against)
do
    # 只对text类文件进行转换
    if file "${file}" |grep 'text' 2>&1 >/dev/null;then
        echo "unexpanding ${file}"
        unexpand -t 4 "${file}" > "${TMPFILE}"
        cp "${TMPFILE}" "${file}"
        git add "${file}"
    fi
done

类似的,我们还可以通过 post-merge hook(实现跟 post-commit 一样)来将远端仓库中的代码也自动转回 TAB,如此一来 TAB 还好者们就可以安心的在本地使用 TAB,然后由 git 帮你自动进行 SPACE 的转换了。

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。
列表为空,暂无数据

关于作者

文章
评论
25 人气
更多

推荐作者

櫻之舞

文章 0 评论 0

弥枳

文章 0 评论 0

m2429

文章 0 评论 0

野却迷人

文章 0 评论 0

我怀念的。

文章 0 评论 0

    我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
    原文