我有一个非常大的补丁文件,我正在尝试将其应用到我的代码中。问题是,我的补丁中的一些更改已经存在于代码中。有没有办法让补丁优雅地忽略已经应用的更改?
该-N
选项没有达到我想要的效果。如果它遇到已经应用的块,它将生成一个拒绝文件,并且不会再对该文件应用任何块。我希望它忽略那个大块头并继续应用补丁的其余部分。我唯一希望它生成 .rej 文件的情况是无法应用块并且似乎尚未应用块时。
有没有办法做到这一点?
答案1
为此,您需要安装 patchutils。
该脚本会将一个大补丁分割成较小的单独补丁,每个补丁仅包含一个文件的一个块。然后您可以使用这些补丁来应用这些补丁patch --forward
。
#!/bin/sh -eu
PATCH=$1
OUTDIR=$2
test -f "$PATCH" && test -d "$OUTDIR"
TDIR=$(mktemp -d)
trap 'rm -rf $TDIR' 0
INDEX=0
TEMPHUNK=$TDIR/current_hunk
lsdiff $1 | while read FNAME
do
HUNK=1
while :
do
filterdiff --annotate --hunks=$HUNK -i "$FNAME" "$PATCH" > "$TEMPHUNK"
HUNK=$((HUNK+1))
test -s "$TEMPHUNK" && \
{
mv "$TEMPHUNK" "$OUTDIR/$INDEX.diff"
INDEX=$((INDEX+1))
} || break
done
done
编辑:将脚本保存到hunks.sh
,并调用它:
./hunks.sh path/to/big.diff path/to/output/directory
答案2
我最终使用类似于 artyom 的解决方案解决了这个问题。
步骤1:将补丁分解为许多单独的补丁,每个块对应一个补丁。
我使用这个脚本来执行此操作:
#!/usr/bin/python2
import sys
header = []
writing_header = False
patchnum = 0
patch = open(sys.argv[1], "r")
out = open("/dev/null", "w")
for line in patch.readlines():
if line.startswith("diff"):
header = []
writing_header = True
if line.startswith("@@"):
out.close()
out = open(str(patchnum) + ".diff", "w")
patchnum += 1
writing_header = False
out.writelines(header)
if writing_header:
header.append(line)
else:
out.write(line)
out.close()
用法示例:
$ cd directory_containing_patch
$ mkdir foo
$ cd foo
$ explode.py ../huge_patch.diff
这将使用名为 0.diff 1.diff 等的文件填充当前目录。
第2步:应用每个补丁,丢弃已经应用的补丁。
我使用这个脚本来执行此操作:
#!/bin/bash
if [[ $# -ne 1 || ! -d "${1}/" ]]; then
echo "Usage: $0 dirname"
exit 1
fi
find "$1" -name \*.diff | while read f; do
OUTPUT=$(patch -s -p1 -r- -i"$f")
if [ $? -eq 0 ]; then
rm "$f"
else
if echo "$OUTPUT" | grep -q "Reversed (or previously applied) patch detected!"; then
rm "$f"
fi
fi
done
用法示例:
$ cd directory_containing_code
$ apply_patches.bash directory_containing_patch/foo
这将删除之前生成的任何干净应用或已应用的补丁。留下的任何补丁foo
都是拒绝的,需要手动检查和合并。