Q

有的软件更新频繁,有的软件年久失修。一味的追求新特性,往往不是稳定的方案,有时也想修改一部分代码来定制一下特殊功能。

我的设想是使用某个tag的纯源码包,把自己的patch打上去,再手动编译。

~

以vim为例,先从官方仓库下载某个tag源码包。

curl https://codeload.github.com/vim/vim/tar.gz/refs/tags/v9.1.2127 -o vim-91.2127.tar.gz
tar xzf vim-91.2127.tar.gz

这个源码包是去除了.git的,在里面的修改不会被记录。理论上我们需要另一份原始的副本用于对比,接着用diff生成patch就行了。

diff - compare files line by line

生成patch的方法如下:

cp -r vim-9.1.2127 vim-9.1.2127-patch
... # 在vim-9.1.2127-patch里进行一些修改
diff -aruN vim-9.1.2127 vim-9.1.2127-patch > 0001-xxx.patch

# 参数说明
diff -aruN A B  # form A to B
-a treat all files as text
-r recursively compare any subdirectories found
-u output NUM (default 3) lines of unified context #patch格式
-N treat absent files as empty

diffgit识别变更的行为不太一样,开启-Ndiff,会把空文件当做无文件,而git的空文件就是一个object,会视作一个变更:

# diff
copy -r A B
touch A/new_file

diff -aruN A B # exit 0, no different

# git
touch git_dir/new_file
git status # repo has diff

新增空文件理论上不会影响编译,所以影响应该也不大。

diff也没法像git一样快速地管理文件对象,如果源码过与庞大,用diff -r生成patch的过程会很慢(比如kernel的)。如果已经完成构建了,还会在目录下产生很多.o和自动生成的文件影响识别,diff不会自动ignore。

还是写个脚本好。

生成patchdiff -rNq A B识别到有哪些文件发生了变更用户自行选择需要diff的文件将文件列表放到patch的开头更新patch读取patch开头的文件列表diff -uN A/xxx B/xxx生成该文件的diff合并到patch遍历文件列表遍历结束

反向操作可以使用patch

patch - apply a diff file to an original

patch -p1 < ../xxx.patch
patch -p1 -R < ../xxx.patch

-pnum表示忽略diff中的前num级目录路径。如-p1,即是把a/some/path忽略成some/path

参考资料:

生成patch

一篇老文,讲述diff的三种格式

using the output of diff to create patch

diff用于文件名对比

patch/diff的实用用法

我也是挺落后的,这些文章都很早了,在AI时代,还在补这种老知识。

A

genp() {
    if [ $# -eq 2 ]; then
        diff -rNq $1 $2 |awk '{print $2}' |awk '{sub("^[^/]+/", "")}1'
    elif [ $# -eq 3 ]; then
        if [ ! -d "$1" ] || [ ! -d "$2" ] || [ ! -f "$3" ]; then
            return 1
        fi
        ori=$(cat $3)
        echo -n > $3
        for file in $ori; do
            if [[ "${file}" == "@@@" ]]; then
                break
            fi
            echo $file >> $3
        done
        echo "@@@" >> $3
        for file in $ori; do
            if [[ "${file}" == "@@@" ]]; then
                break
            fi
            diff -uN "$1/$file" "$2/$file" >> $3
        done
        return 0
    else
        return 1
    fi
}

使用示范:

# 出patch
genp A B > tmp.patch
vim xxx.patch # 删除不需要识别差异的文件
genp A B tmp.patch

# 打patch
cp -r A C
cd C
patch -p1 < ../tmp.patch

# 反patch
patch -p1 -R < ../tmp.patch

Pray to God you don't have to use it again.

Pray to God you don't used to not using it again.

It's on your back, even when it's off your back.

行尸走肉 S5E13