Subject: Re: How to split a patch

From: Boaz Harrosh <[email-masked]>
Date: Mon, 28 Jan 2008 12:37:59 +0200

On Mon, Jan 28 2008 at 11:32 +0200, "Paolo Ciarrocchi" <[email-masked]> wrote:
> On Jan 28, 2008 10:25 AM, Junio C Hamano <[email-masked]> wrote:
>> "Paolo Ciarrocchi" <[email-masked]> writes:
>>
>>> I know ho to do the opposite process, rebase -i and squash is something
>>> I'm really used to do but this time that trick is not going to help me.
>>>
>>> What is the preferred way to split a big patch in a series of
>>> smaller patches?
>>
>> I personally found the procedure described there a bit on the
>> sketchy side, but does "SPLITTING COMMITS" section of git-rebase
>> manual help?
> 
> Yes it helps but I still wonder whether thereis a "simpler" way to achive that.
> Is it possible to split a patch selecting the hunk in git gui or any
> other graphical
> tool?
> 
> That would be a good starting point for a newbie (like me).
> 
> Thanks!
> 
> Ciao,
What I do is edit the patch, let me explain.
- I create a new branch based at the base of the big patch. Now
  I have the original branch for reference. Lets say the original
  branch is called ALL, and this new branch SPLIT. and BASE is the base.
- # git-checkout -b SPLIT BASE
- # git-diff -R ALL >edit-the-patch-001.patch
- now I open the patch file with an editor. I use kwrite because of
  the good color highlighting.
- I remove all the hunks that I don't need, and am left with only the
  parts that I want to be in the first patch.
- I save the patch.
- If at the edit stage I have changed a big hunk and only used part
  of it I need to run fixpatch script attached below. If I only removed
  complete hunks then I'm good to go.
- I now use:
  # patch -p 1 < edit-the-patch-001.patch
- # git-commit -a
- and git-commit --amend until the first patch is good
- now do the 
  # git-diff -R ALL >edit-the-patch-002.patch
  and so on until there is nothing left. It is nice how
  every time it gets smaller and smaller.

[fixpatch command line]
usage: fixpatch inputfile outputfile
what I do is just
# fixpatch edit-the-patch-001.patch{,}

Boaz

#!/bin/sh

src="$1"
dest="$2"
tmp=/tmp/`basename $0`.tmp.$$

if [ -z "$dest" ]; then
	dest="/dev/fd/1"
elif [ "$src" == "$dest" ]; then
	cp "$src" "$src.orig" || exit 1
fi

awk '
function dump_hunk()
{
	if (!hunk) {
		return;
	}

	if (!hsrc_line)
		foffset = 1;

#	if (hsuffix !~ /\n$/) {
#		hsuffix = hsuffix "\n";
#	}
	printf("@@ -%d,%d +%d,%d %s\n", -hsrc_line, hsrc_count,
		-hsrc_line + foffset, hdest_count, hsuffix);

	if (hunchanged + hdel + hadd != hlines) {
		fflush();
		printf("%s %d: Warning: Unchanged %d deleted %d added %d != lines %d\n",
			FILENAME, FNR, hunchanged, hdel, hadd, hlines) > "/dev/stderr";
	}

	if (hunchanged + hdel != hsrc_count) {
		fflush();
		printf("%s %d: Warning: Unchanged %d deleted %d != hsrc_count %d\n",
			FILENAME, FNR, hunchanged, hdel, hsrc_count) > "/dev/stderr";
	}

	if (hunchanged + hadd != hdest_count) {
		fflush();
		printf("%s %d: Warning: Unchanged %d added %d != hdest_count %d\n",
			FILENAME, FNR, hunchanged, hadd, hdest_count) > "/dev/stderr";
	}

	for (i = 0; i < hlines; i++) {
		print hline[i];
		delete hline[i];
	}

	foffset += hdest_count - hsrc_count;
	hsrc_line = 0;
	hsrc_count = 0;
	hdest_line = 0;
	hdest_count = 0;
	hsuffix = "";

	hunchanged = hadd = hdel = 0;
	hlines = 0;
	hunk = 0;
}

/^(diff|====)/ {
	dump_hunk();
	print;
	foffset = 0;
	next;
}

/^@@/ {
	dump_hunk();
	n = split($2, a, /,/);
	hsrc_line = a[1]+0;
	hsrc_oldcount = a[2]+0;
	hsrc_count = 0;
	if (n != 2 || hsrc_line > 0 || hsrc_oldcount < 0) {
		fflush();
		printf("%s %d: Error: Corrupt hunk header (n %d hsrc_line %d hsrc_oldcount %d)\n",
			FILENAME, FNR, n, hsrc_line, hsrc_count) > "/dev/stderr";
	}

	n = split($3, a, /,/);
	hdest_line = a[1]+0;
	hdest_oldcount = a[2]+0;
	hdest_count = 0;
	if (n != 2 || hdest_line < 0 || hdest_oldcount < 0) {
		fflush();
		printf("%s %d: Error: Corrupt hunk header (hdest_line %d hdest_oldcount %d)\n",
			FILENAME, FNR, hdest_line, hdest_oldcount) > "/dev/stderr";
	}

	hsuffix = $0;
	sub(/^@@.*@@/, "@@", hsuffix);

	hlines = 0;
	hunk = 1;
	next;
}

(!hunk) || /^#/ {
	print;
	next;
}

/^-/ {
	hdel++;
	hsrc_count++;
}

/^+/ {
	hadd++;
	hdest_count++;
}

/^ / {
	hunchanged++;
	hsrc_count++;
	hdest_count++;
}

/^$/ || /^[^-+ ]/ {
	fflush();
	printf("%s %d: Warning: badly formatted line\n",
		FILENAME, FNR) > "/dev/stderr";
	exit(255);
##	hadd++;
##	hdest_count++;
#	next;
}

{
	hline[hlines++] = $0;
}

END {
	dump_hunk()
}
' "$src" > "$tmp" && mv "$tmp" "$dest"