Как сделать, чтобы патч игнорировал уже примененные ханки

14

У меня есть очень большой файл патча, который я пытаюсь применить к своему коду. Проблема в том, что некоторые изменения в моем патче уже существуют в коде. Есть ли способ заставить патч изящно игнорировать уже примененные изменения?

-NВариант не делать то , что я хочу. Если он встречает уже примененный блок, он сгенерирует отклоненный файл и больше не будет применять блок к этому файлу. Я хочу, чтобы он просто проигнорировал этот кусок и продолжил применять оставшуюся часть патча. Единственный раз, когда я хочу, чтобы он сгенерировал файл .rej, - это если ханк не может быть применен и, кажется, не применяется.

Есть ли способ сделать это?

Shum
источник

Ответы:

7

Для этого вам понадобятся 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
Artyom
источник
2

В конце концов я решил эту проблему, используя решение, похожее на решение Артема.

Шаг 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являются отклонениями, которые необходимо вручную проверить и объединить.

Shum
источник