4

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

 3 years ago
source link: https://www.lujun9972.win/blog/2020/04/29/git-hook+expand+unexpand%E5%8C%96%E8%A7%A3%E7%A9%BA%E6%A0%BC%E4%B8%8Etab%E4%B9%8B%E4%BA%89/index.html
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.
neoserver,ios ssh client

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

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 的转换了.


Recommend

About Joyk


Aggregate valuable and interesting links.
Joyk means Joy of geeK