So ignorieren Patches bereits angelegte Hunks

14

Ich habe eine sehr große Patch-Datei, die ich auf meinen Code anwenden möchte. Das Problem ist, dass einige der Änderungen in meinem Patch bereits im Code vorhanden sind. Gibt es eine Möglichkeit, Patches so zu gestalten, dass sie die Änderungen, die bereits angewendet wurden, ordnungsgemäß ignorieren?

Die -NOption macht nicht was ich will. Wenn es auf einen bereits angewendeten Block stößt, wird eine Ablehnungsdatei generiert und keine weiteren Blöcke auf diese Datei angewendet. Ich möchte, dass es diesen Teil einfach ignoriert und den Rest des Patches weiter anwendet. Ich möchte nur, dass eine .rej-Datei generiert wird, wenn ein Block nicht angewendet werden kann und noch nicht angewendet zu sein scheint.

Gibt es eine Möglichkeit, dies zu tun?

Shum
quelle

Antworten:

7

Dafür müssen Patchutils installiert sein.

Dieses Skript teilt einen großen Patch in kleinere separate Paches auf, von denen jeder nur einen Block für eine Datei enthält. Sie können diese Patches dann mit anwenden 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

Bearbeiten : Speichern Sie das Skript in hunks.shund rufen Sie es auf:

./hunks.sh path/to/big.diff path/to/output/directory
artyom
quelle
2

Ich löste dies schließlich mit einer Lösung ähnlich der von Artyom.

Schritt 1: Zerlegen Sie den Patch in viele separate Patches, einen für jeden Hunk.

Ich habe dieses Skript verwendet, um dies zu tun:

#!/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()

Beispielverwendung:

$ cd directory_containing_patch
$ mkdir foo
$ cd foo
$ explode.py ../huge_patch.diff

Dies füllt das aktuelle Verzeichnis mit Dateien mit dem Namen 0.diff 1.diff und so weiter.

Schritt 2: Wenden Sie jeden Patch an und verwerfen Sie bereits angewendete Patches.

Ich habe dieses Skript verwendet, um dies zu tun:

#!/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

Beispielverwendung:

$ cd directory_containing_code
$ apply_patches.bash directory_containing_patch/foo

Dadurch werden alle zuvor generierten Patches gelöscht, die ordnungsgemäß angewendet wurden oder bereits angewendet wurden. Verbleibende Patches foosind Ablehnungen, die manuell überprüft und zusammengeführt werden müssen.

Shum
quelle