[PATCH 1/2] Allow git-apply to fix up the line counts

Subsystems: documentation, the rest

DORMANTno replies

13 messages, 3 authors, 2016-06-15 · open the first message on its own page

[PATCH 1/2] Allow git-apply to fix up the line counts

From: Johannes Schindelin <hidden>
Date: 2016-06-15 22:44:41

Sometimes, the easiest way to fix up a patch is to edit it directly, even
adding or deleting lines.  Now, many people are not as divine as certain
benevolent dictators as to update the hunk headers correctly at the first
try.

So teach the tool to do it for us.

Signed-off-by: Johannes Schindelin <redacted>
---
 Documentation/git-apply.txt |    6 ++++-
 builtin-apply.c             |   55 +++++++++++++++++++++++++++++++++++++++---
 2 files changed, 56 insertions(+), 5 deletions(-)
diff --git a/Documentation/git-apply.txt b/Documentation/git-apply.txt
index 2dec2ec..ba3dba7 100644
--- a/Documentation/git-apply.txt
+++ b/Documentation/git-apply.txt
@@ -12,7 +12,7 @@ SYNOPSIS
 'git-apply' [--stat] [--numstat] [--summary] [--check] [--index]
 	  [--apply] [--no-add] [--build-fake-ancestor <file>] [-R | --reverse]
 	  [--allow-binary-replacement | --binary] [--reject] [-z]
-	  [-pNUM] [-CNUM] [--inaccurate-eof] [--cached]
+	  [-pNUM] [-CNUM] [--inaccurate-eof] [--fixup-line-counts] [--cached]
 	  [--whitespace=<nowarn|warn|fix|error|error-all>]
 	  [--exclude=PATH] [--verbose] [<patch>...]
 
@@ -169,6 +169,10 @@ behavior:
 	correctly. This option adds support for applying such patches by
 	working around this bug.
 
+--fixup-line-counts::
+	Fix up the line counts (e.g. after editing the patch without
+	adjusting the hunk headers appropriately).
+
 -v, --verbose::
 	Report progress to stderr. By default, only a message about the
 	current patch being applied will be printed. This option will cause
diff --git a/builtin-apply.c b/builtin-apply.c
index c497889..3fd80e8 100644
--- a/builtin-apply.c
+++ b/builtin-apply.c
@@ -153,6 +153,7 @@ struct patch {
 	unsigned int is_binary:1;
 	unsigned int is_copy:1;
 	unsigned int is_rename:1;
+	unsigned int fixup:1;
 	struct fragment *fragments;
 	char *result;
 	size_t resultsize;
@@ -882,6 +883,41 @@ static int parse_range(const char *line, int len, int offset, const char *expect
 	return offset + ex;
 }
 
+static int fixup_counts(char *line, int size, struct fragment *fragment)
+{
+	if (size < 1)
+		return -1;
+
+	fragment->oldlines = fragment->newlines = -1;
+
+	for (;;) {
+		int len = linelen(line, size);
+		if (!len)
+			break;
+
+		switch (*line) {
+		case ' ':
+			fragment->oldlines++;
+			/* fall through */
+		case '+':
+			fragment->newlines++;
+			break;
+		case '-':
+			fragment->oldlines++;
+			break;
+		default:
+			/* Probably "diff ..." */
+			return 0;
+		}
+
+		size -= len;
+		line += len;
+		if (size < 2 || !prefixcmp(line, "@@"))
+			break;
+	}
+	return 0;
+}
+
 /*
  * Parse a unified diff fragment header of the
  * form "@@ -a,b +c,d @@"
@@ -1013,6 +1049,9 @@ static int parse_fragment(char *line, unsigned long size,
 	offset = parse_fragment_header(line, len, fragment);
 	if (offset < 0)
 		return -1;
+	if (offset > 0 && patch->fixup &&
+			fixup_counts(line + offset, size - offset, fragment))
+		return -1;
 	oldlines = fragment->oldlines;
 	newlines = fragment->newlines;
 	leading = 0;
@@ -2912,7 +2951,8 @@ static void prefix_patches(struct patch *p)
 	}
 }
 
-static int apply_patch(int fd, const char *filename, int inaccurate_eof)
+static int apply_patch(int fd, const char *filename, int inaccurate_eof,
+		int fixup)
 {
 	size_t offset;
 	struct strbuf buf;
@@ -2929,6 +2969,7 @@ static int apply_patch(int fd, const char *filename, int inaccurate_eof)
 
 		patch = xcalloc(1, sizeof(*patch));
 		patch->inaccurate_eof = inaccurate_eof;
+		patch->fixup = fixup;
 		nr = parse_chunk(buf.buf + offset, buf.len - offset, patch);
 		if (nr < 0)
 			break;
@@ -2998,6 +3039,7 @@ int cmd_apply(int argc, const char **argv, const char *unused_prefix)
 	int i;
 	int read_stdin = 1;
 	int inaccurate_eof = 0;
+	int fixup = 0;
 	int errs = 0;
 	int is_not_gitdir;
 
@@ -3015,7 +3057,8 @@ int cmd_apply(int argc, const char **argv, const char *unused_prefix)
 		int fd;
 
 		if (!strcmp(arg, "-")) {
-			errs |= apply_patch(0, "<stdin>", inaccurate_eof);
+			errs |= apply_patch(0, "<stdin>", inaccurate_eof,
+					fixup);
 			read_stdin = 0;
 			continue;
 		}
@@ -3118,6 +3161,10 @@ int cmd_apply(int argc, const char **argv, const char *unused_prefix)
 			inaccurate_eof = 1;
 			continue;
 		}
+		if (!strcmp(arg, "--fixup-line-counts")) {
+			fixup = 1;
+			continue;
+		}
 		if (0 < prefix_length)
 			arg = prefix_filename(prefix, prefix_length, arg);
 
@@ -3126,12 +3173,12 @@ int cmd_apply(int argc, const char **argv, const char *unused_prefix)
 			die("can't open patch '%s': %s", arg, strerror(errno));
 		read_stdin = 0;
 		set_default_whitespace_mode(whitespace_option);
-		errs |= apply_patch(fd, arg, inaccurate_eof);
+		errs |= apply_patch(fd, arg, inaccurate_eof, fixup);
 		close(fd);
 	}
 	set_default_whitespace_mode(whitespace_option);
 	if (read_stdin)
-		errs |= apply_patch(0, "<stdin>", inaccurate_eof);
+		errs |= apply_patch(0, "<stdin>", inaccurate_eof, fixup);
 	if (whitespace_error) {
 		if (squelch_whitespace_errors &&
 		    squelch_whitespace_errors < whitespace_error) {
-- 
1.5.6.rc1.181.gb439d

[PATCH 2/2] git-add: introduce --edit (to edit the diff vs. the index)

From: Johannes Schindelin <hidden>
Date: 2016-06-15 22:44:41

With "git add -e [<files>]", Git will fire up an editor with the current
diff relative to the index (i.e. what you would get with "git diff
[<files>]").

Now you can edit the patch as much as you like, including adding/removing
lines, editing the text, whatever.  Make sure, though, that the first
character of the hunk lines is still a space, a plus or a minus.

After you closed the editor, Git will adjust the line counts of the
hunks if necessary, thanks to the --fixup-line-counts option of apply,
and commit the patch.  Except if you deleted everything, in which case
nothing happens (for obvious reasons).

Signed-off-by: Johannes Schindelin <redacted>
---

	This was too useful to let slip by.  I even committed it using 
	"git add -e <files>" several times!

	Anyway, bed time.

 Documentation/git-add.txt |    9 ++++++-
 builtin-add.c             |   49 ++++++++++++++++++++++++++++++++++++++++++++-
 2 files changed, 55 insertions(+), 3 deletions(-)
diff --git a/Documentation/git-add.txt b/Documentation/git-add.txt
index 1afd0c6..dd744f1 100644
--- a/Documentation/git-add.txt
+++ b/Documentation/git-add.txt
@@ -8,8 +8,8 @@ git-add - Add file contents to the index
 SYNOPSIS
 --------
 [verse]
-'git-add' [-n] [-v] [-f] [--interactive | -i] [--patch | -p] [-u] [--refresh]
-	  [--ignore-errors] [--] <filepattern>...
+'git-add' [-n] [-v] [-f] [--interactive | -i] [--patch | -p] [--edit | -e]
+	  [-u] [--refresh] [--ignore-errors] [--] <filepattern>...
 
 DESCRIPTION
 -----------
@@ -70,6 +70,11 @@ OPTIONS
 	bypassed and the 'patch' subcommand is invoked using each of
 	the specified filepatterns before exiting.
 
+-e, \--edit::
+	Open the diff vs. the index in an editor and let the user
+	edit it.  After the editor was closed, adjust the hunk headers
+	and apply the patch to the index.
+
 -u::
 	Update only files that git already knows about, staging modified
 	content for commit and marking deleted files for removal. This
diff --git a/builtin-add.c b/builtin-add.c
index 1da22ee..05ae40d 100644
--- a/builtin-add.c
+++ b/builtin-add.c
@@ -19,7 +19,7 @@ static const char * const builtin_add_usage[] = {
 	"git-add [options] [--] <filepattern>...",
 	NULL
 };
-static int patch_interactive = 0, add_interactive = 0;
+static int patch_interactive = 0, add_interactive = 0, edit_interactive = 0;
 static int take_worktree_changes;
 
 static void prune_directory(struct dir_struct *dir, const char **pathspec, int prefix)
@@ -186,6 +186,50 @@ int interactive_add(int argc, const char **argv, const char *prefix)
 	return status;
 }
 
+int edit_patch(int argc, const char **argv, const char *prefix)
+{
+	static struct lock_file lock;
+	struct child_process child;
+	int ac;
+	struct stat st;
+
+	memset(&child, 0, sizeof(child));
+	child.argv = xcalloc(sizeof(const char *), (argc + 5));
+	ac = 0;
+	child.git_cmd = 1;
+	child.argv[ac++] = "diff-files";
+	child.argv[ac++] = "--no-color";
+	child.argv[ac++] = "-p";
+	child.argv[ac++] = "--";
+	if (argc) {
+		const char **pathspec = validate_pathspec(argc, argv, prefix);
+		if (!pathspec)
+			return -1;
+		memcpy(&(child.argv[ac]), pathspec, sizeof(*argv) * argc);
+		ac += argc;
+	}
+	child.argv[ac] = NULL;
+	child.out = hold_lock_file_for_update(&lock, git_path("EDIT_PATCH"), 1);
+
+	if (run_command(&child))
+		return 1;
+	free(child.argv);
+
+	launch_editor(lock.filename, NULL, NULL);
+
+	if (stat(lock.filename, &st))
+		return 1;
+	if (!st.st_size) {
+		fprintf(stderr, "Empty patch. Aborted.\n");
+		return 0;
+	}
+
+	execl_git_cmd("apply", "--fixup-line-counts", "--cached",
+			lock.filename, NULL);
+
+	return 1;
+}
+
 static struct lock_file lock_file;
 
 static const char ignore_error[] =
@@ -200,6 +244,7 @@ static struct option builtin_add_options[] = {
 	OPT_GROUP(""),
 	OPT_BOOLEAN('i', "interactive", &add_interactive, "interactive picking"),
 	OPT_BOOLEAN('p', "patch", &patch_interactive, "interactive patching"),
+	OPT_BOOLEAN('e', "edit", &edit_interactive, "super-interactive patching"),
 	OPT_BOOLEAN('f', NULL, &ignored_too, "allow adding otherwise ignored files"),
 	OPT_BOOLEAN('u', NULL, &take_worktree_changes, "update tracked files"),
 	OPT_BOOLEAN( 0 , "refresh", &refresh_only, "don't add, only refresh the index"),
@@ -226,6 +271,8 @@ int cmd_add(int argc, const char **argv, const char *prefix)
 
 	argc = parse_options(argc, argv, builtin_add_options,
 			  builtin_add_usage, 0);
+	if (edit_interactive)
+		return(edit_patch(argc, argv, prefix));
 	if (patch_interactive)
 		add_interactive = 1;
 	if (add_interactive)
-- 
1.5.6.rc1.181.gb439d

Re: [PATCH 1/2] Allow git-apply to fix up the line counts

From: Johannes Sixt <hidden>
Date: 2016-06-15 22:44:41

Johannes Schindelin schrieb:
+--fixup-line-counts::
+	Fix up the line counts (e.g. after editing the patch without
+	adjusting the hunk headers appropriately).
This sort of implies that there is some kind of output that tells the
correct line counts. But that isn't the case (if I read the patch
correctly). So I suggest to name the option --ignore-line-counts.

-- Hannes

Re: [PATCH 1/2] Allow git-apply to fix up the line counts

From: Johannes Schindelin <hidden>
Date: 2016-06-15 22:44:41

Hi,

On Thu, 5 Jun 2008, Johannes Sixt wrote:
Johannes Schindelin schrieb:
quoted
+--fixup-line-counts::
+	Fix up the line counts (e.g. after editing the patch without
+	adjusting the hunk headers appropriately).
This sort of implies that there is some kind of output that tells the
correct line counts. But that isn't the case (if I read the patch
correctly). So I suggest to name the option --ignore-line-counts.
But there is some kind of output: the hunks themselves.  And the line 
counts are not ignored, but they are actively rewritten.  But if you have 
a suggestion which keeps the spirit, I am very interested...

Ciao,
Dscho

Re: [PATCH 1/2] Allow git-apply to fix up the line counts

From: Johannes Sixt <hidden>
Date: 2016-06-15 22:44:41

Johannes Schindelin schrieb:
Hi,

On Thu, 5 Jun 2008, Johannes Sixt wrote:
quoted
Johannes Schindelin schrieb:
quoted
+--fixup-line-counts::
+	Fix up the line counts (e.g. after editing the patch without
+	adjusting the hunk headers appropriately).
This sort of implies that there is some kind of output that tells the
correct line counts. But that isn't the case (if I read the patch
correctly). So I suggest to name the option --ignore-line-counts.
But there is some kind of output: the hunks themselves.
Is there? I did this (it rewrites all line counts to 1):

$ git diff ..HEAD~1 |
	sed -e '/^@@/s/,[0-9]+ /,1 /g' |
	./git-apply --fixup-line-counts

and there was no output. Instead, the patch was applied.
 And the line 
counts are not ignored, but they are actively rewritten.
Of course, internally there is some sort of "output" from the fixup
routine, and the line counts are rewritten and then are not ignored. But
the user doesn't care about this internal procedure. From the user's
perspective, the line counts of the input patch are ignored.

Apart from this color of the bikeshed I like your patch.

-- Hannes

Re: [PATCH 1/2] Allow git-apply to fix up the line counts

From: Johannes Schindelin <hidden>
Date: 2016-06-15 22:44:41

Hi,

On Thu, 5 Jun 2008, Johannes Sixt wrote:
Johannes Schindelin schrieb:
quoted
On Thu, 5 Jun 2008, Johannes Sixt wrote:
quoted
Johannes Schindelin schrieb:
quoted
+--fixup-line-counts::
+	Fix up the line counts (e.g. after editing the patch without
+	adjusting the hunk headers appropriately).
This sort of implies that there is some kind of output that tells the 
correct line counts. But that isn't the case (if I read the patch 
correctly). So I suggest to name the option --ignore-line-counts.
But there is some kind of output: the hunks themselves.
Is there?
Yes!
I did this (it rewrites all line counts to 1):

$ git diff ..HEAD~1 |
	sed -e '/^@@/s/,[0-9]+ /,1 /g' |
	./git-apply --fixup-line-counts

and there was no output. Instead, the patch was applied.
As I said, the data is in the _hunks_, but I maybe should have added _not 
in the hunk headers_.

So in a very real sense, you edit the hunks, and the hunk headers are 
adjusted to that.  You did not adjust the hunks, so they got applied.

It seems that you think the hunk header's line counts are heeded, and the 
hunk adjusted, with --fixup-line-counts?  Sorry, I find that rather 
counterintuitive.
quoted
 And the line counts are not ignored, but they are actively rewritten.
Of course, internally there is some sort of "output" from the fixup 
routine, and the line counts are rewritten and then are not ignored. But 
the user doesn't care about this internal procedure. From the user's 
perspective, the line counts of the input patch are ignored.
But they are not!

There are _two_ things that are the line counts.  Those numbers in the 
hunk header, and the real line counts of the hunks.

Now, if you say they are _ignored_, would that not imply in plain English 
that they are left unchanged (in limbo, because those two types of numbers 
contradict each other)?

Okay, how about shikebedding this to --adjust-line-counts?

Ciao,
Dscho

Re: [PATCH 1/2] Allow git-apply to fix up the line counts

From: Johannes Sixt <hidden>
Date: 2016-06-15 22:44:41

Johannes Schindelin schrieb:
Hi,

On Thu, 5 Jun 2008, Johannes Sixt wrote:
quoted
Johannes Schindelin schrieb:
quoted
On Thu, 5 Jun 2008, Johannes Sixt wrote:
quoted
Johannes Schindelin schrieb:
quoted
+--fixup-line-counts::
+	Fix up the line counts (e.g. after editing the patch without
+	adjusting the hunk headers appropriately).
This sort of implies that there is some kind of output that tells the 
correct line counts. But that isn't the case (if I read the patch 
correctly). So I suggest to name the option --ignore-line-counts.
But there is some kind of output: the hunks themselves.
Is there?
Yes!
quoted
I did this (it rewrites all line counts to 1):

$ git diff ..HEAD~1 |
	sed -e '/^@@/s/,[0-9]+ /,1 /g' |
	./git-apply --fixup-line-counts

and there was no output. Instead, the patch was applied.
As I said, the data is in the _hunks_, but I maybe should have added _not 
in the hunk headers_.
Yes, of course.
So in a very real sense, you edit the hunks, and the hunk headers are 
adjusted to that.  You did not adjust the hunks, so they got applied.
Yes, of course.

But the example pretends that the hunks have been edited so heavily that
they in no way match the line counts in the hunk headers.
It seems that you think the hunk header's line counts are heeded, and the 
hunk adjusted, with --fixup-line-counts?
NO, of course *NOT*.
 Sorry, I find that rather 
counterintuitive.
So would I.
quoted
quoted
 And the line counts are not ignored, but they are actively rewritten.
Of course, internally there is some sort of "output" from the fixup 
routine, and the line counts are rewritten and then are not ignored. But 
the user doesn't care about this internal procedure. From the user's 
perspective, the line counts of the input patch are ignored.
But they are not!
There are _two_ things that are the line counts.  Those numbers in the 
hunk header, and the real line counts of the hunks.
And I was always talking about the numbers in the hunk headers.
Now, if you say they are _ignored_, would that not imply in plain English 
that they are left unchanged (in limbo, because those two types of numbers 
contradict each other)?
That you *internally* rewrite those numbers and then do *not* ignore them
is totally pointless for the user. It's an implementation detail. The user
doesn't see what is going on nor should he care. From the user's
perspective, the hunk header line counts are _ignored_ (because if they
were not ignored, then there would be an error message in the
contradicting case).
Okay, how about shikebedding this to --adjust-line-counts?
From the user's perspective, nothing is "adjusted"; the hunk header line
counts are ... you guess it ... *ignored*.

-- Hannes

Re: [PATCH 1/2] Allow git-apply to fix up the line counts

From: Johannes Schindelin <hidden>
Date: 2016-06-15 22:44:41

Hi,

On Thu, 5 Jun 2008, Johannes Sixt wrote:
quoted
Now, if you say they are _ignored_, would that not imply in plain 
English that they are left unchanged (in limbo, because those two 
types of numbers contradict each other)?
That you *internally* rewrite those numbers and then do *not* ignore 
them is totally pointless for the user. It's an implementation detail. 
The user doesn't see what is going on nor should he care. From the 
user's perspective, the hunk header line counts are _ignored_ (because 
if they were not ignored, then there would be an error message in the 
contradicting case).
quoted
Okay, how about shikebedding this to --adjust-line-counts?
From the user's perspective, nothing is "adjusted"; the hunk header line 
counts are ... you guess it ... *ignored*.
Oh... I start to see what you mean.  It's just that for me, the line 
counts are the actual line counts, not what is recorded in the hunk 
header.

In any case, I really do not feel strongly about it, since I do not want 
to use it, except with git add -e.  Which I really grew fond of in these 
last hours ;-)

So how about --ignore-hunk-headers?  I think this is much more 
descriptive, and catches your complaint, IMHO.

Ciao,
Dscho

Re: [PATCH 1/2] Allow git-apply to fix up the line counts

From: Johannes Sixt <hidden>
Date: 2016-06-15 22:44:41

Johannes Schindelin schrieb:
So how about --ignore-hunk-headers?  I think this is much more 
descriptive, and catches your complaint, IMHO.
Yes, that's good as well. :-)

-- Hannes

[PATCH v2 0/2] git add --edit

From: Johannes Schindelin <hidden>
Date: 2016-06-15 22:44:41

Changes relative to the first version:

- rename the apply option to --ignore-hunk-headers

- add a test

Johannes Schindelin (2):
  Allow git-apply to ignore the hunk headers
  git-add: introduce --edit (to edit the diff vs. the index)

 Documentation/git-add.txt   |    9 +++-
 Documentation/git-apply.txt |    7 +++-
 builtin-add.c               |   47 +++++++++++++++++++++++-
 builtin-apply.c             |   57 ++++++++++++++++++++++++++--
 t/t3702-add-edit.sh         |   86 +++++++++++++++++++++++++++++++++++++++++++
 5 files changed, 198 insertions(+), 8 deletions(-)
 create mode 100755 t/t3702-add-edit.sh

[PATCH v2 2/2] git-add: introduce --edit (to edit the diff vs. the index)

From: Johannes Schindelin <hidden>
Date: 2016-06-15 22:44:41

With "git add -e [<files>]", Git will fire up an editor with the current
diff relative to the index (i.e. what you would get with "git diff
[<files>]").

Now you can edit the patch as much as you like, including adding/removing
lines, editing the text, whatever.  Make sure, though, that the first
character of the hunk lines is still a space, a plus or a minus.

After you closed the editor, Git will adjust the line counts of the
hunks if necessary, thanks to the --fixup-line-counts option of apply,
and commit the patch.  Except if you deleted everything, in which case
nothing happens (for obvious reasons).

Signed-off-by: Johannes Schindelin <redacted>
---
 Documentation/git-add.txt |    9 ++++-
 builtin-add.c             |   47 ++++++++++++++++++++++++-
 t/t3702-add-edit.sh       |   86 +++++++++++++++++++++++++++++++++++++++++++++
 3 files changed, 139 insertions(+), 3 deletions(-)
 create mode 100755 t/t3702-add-edit.sh
diff --git a/Documentation/git-add.txt b/Documentation/git-add.txt
index 1afd0c6..dd744f1 100644
--- a/Documentation/git-add.txt
+++ b/Documentation/git-add.txt
@@ -8,8 +8,8 @@ git-add - Add file contents to the index
 SYNOPSIS
 --------
 [verse]
-'git-add' [-n] [-v] [-f] [--interactive | -i] [--patch | -p] [-u] [--refresh]
-	  [--ignore-errors] [--] <filepattern>...
+'git-add' [-n] [-v] [-f] [--interactive | -i] [--patch | -p] [--edit | -e]
+	  [-u] [--refresh] [--ignore-errors] [--] <filepattern>...
 
 DESCRIPTION
 -----------
@@ -70,6 +70,11 @@ OPTIONS
 	bypassed and the 'patch' subcommand is invoked using each of
 	the specified filepatterns before exiting.
 
+-e, \--edit::
+	Open the diff vs. the index in an editor and let the user
+	edit it.  After the editor was closed, adjust the hunk headers
+	and apply the patch to the index.
+
 -u::
 	Update only files that git already knows about, staging modified
 	content for commit and marking deleted files for removal. This
diff --git a/builtin-add.c b/builtin-add.c
index 1da22ee..216f331 100644
--- a/builtin-add.c
+++ b/builtin-add.c
@@ -19,7 +19,7 @@ static const char * const builtin_add_usage[] = {
 	"git-add [options] [--] <filepattern>...",
 	NULL
 };
-static int patch_interactive = 0, add_interactive = 0;
+static int patch_interactive = 0, add_interactive = 0, edit_interactive = 0;
 static int take_worktree_changes;
 
 static void prune_directory(struct dir_struct *dir, const char **pathspec, int prefix)
@@ -186,6 +186,48 @@ int interactive_add(int argc, const char **argv, const char *prefix)
 	return status;
 }
 
+int edit_patch(int argc, const char **argv, const char *prefix)
+{
+	static struct lock_file lock;
+	struct child_process child;
+	int ac;
+	struct stat st;
+
+	memset(&child, 0, sizeof(child));
+	child.argv = xcalloc(sizeof(const char *), (argc + 5));
+	ac = 0;
+	child.git_cmd = 1;
+	child.argv[ac++] = "diff-files";
+	child.argv[ac++] = "--no-color";
+	child.argv[ac++] = "-p";
+	child.argv[ac++] = "--";
+	if (argc) {
+		const char **pathspec = validate_pathspec(argc, argv, prefix);
+		if (!pathspec)
+			return -1;
+		memcpy(&(child.argv[ac]), pathspec, sizeof(*argv) * argc);
+		ac += argc;
+	}
+	child.argv[ac] = NULL;
+	child.out = hold_lock_file_for_update(&lock, git_path("EDIT_PATCH"), 1);
+
+	if (run_command(&child))
+		return 1;
+	free(child.argv);
+
+	launch_editor(lock.filename, NULL, NULL);
+
+	if (stat(lock.filename, &st))
+		return 1;
+	if (!st.st_size)
+		die ("Empty patch. Aborted.");
+
+	execl_git_cmd("apply", "--ignore-hunk-headers", "--cached",
+			lock.filename, NULL);
+
+	return 1;
+}
+
 static struct lock_file lock_file;
 
 static const char ignore_error[] =
@@ -200,6 +242,7 @@ static struct option builtin_add_options[] = {
 	OPT_GROUP(""),
 	OPT_BOOLEAN('i', "interactive", &add_interactive, "interactive picking"),
 	OPT_BOOLEAN('p', "patch", &patch_interactive, "interactive patching"),
+	OPT_BOOLEAN('e', "edit", &edit_interactive, "super-interactive patching"),
 	OPT_BOOLEAN('f', NULL, &ignored_too, "allow adding otherwise ignored files"),
 	OPT_BOOLEAN('u', NULL, &take_worktree_changes, "update tracked files"),
 	OPT_BOOLEAN( 0 , "refresh", &refresh_only, "don't add, only refresh the index"),
@@ -226,6 +269,8 @@ int cmd_add(int argc, const char **argv, const char *prefix)
 
 	argc = parse_options(argc, argv, builtin_add_options,
 			  builtin_add_usage, 0);
+	if (edit_interactive)
+		return(edit_patch(argc, argv, prefix));
 	if (patch_interactive)
 		add_interactive = 1;
 	if (add_interactive)
diff --git a/t/t3702-add-edit.sh b/t/t3702-add-edit.sh
new file mode 100755
index 0000000..be2f4da
--- /dev/null
+++ b/t/t3702-add-edit.sh
@@ -0,0 +1,86 @@
+#!/bin/sh
+#
+# Copyright (c) 2007 Johannes E. Schindelin
+#
+
+test_description='add -e basic tests'
+. ./test-lib.sh
+
+
+cat > file << EOF
+LO, praise of the prowess of people-kings
+of spear-armed Danes, in days long sped,
+we have heard, and what honor the athelings won!
+Oft Scyld the Scefing from squadroned foes,
+from many a tribe, the mead-bench tore,
+awing the earls. Since erst he lay
+friendless, a foundling, fate repaid him:
+for he waxed under welkin, in wealth he throve,
+till before him the folk, both far and near,
+who house by the whale-path, heard his mandate,
+gave him gifts:  a good king he!
+EOF
+
+test_expect_success 'setup' '
+
+	git add file &&
+	test_tick &&
+	git commit -m initial file
+
+'
+
+cat > patch << EOF
+diff --git a/file b/file
+index b9834b5..ef6e94c 100644
+--- a/file
++++ b/file
+@@ -3,1 +3,333 @@ of spear-armed Danes, in days long sped,
+ we have heard, and what honor the athelings won!
++
+ Oft Scyld the Scefing from squadroned foes,
+@@ -2,7 +1,5 @@ awing the earls. Since erst he lay
+ friendless, a foundling, fate repaid him:
++
+ for he waxed under welkin, in wealth he throve,
+EOF
+
+cat > expected << EOF
+diff --git a/file b/file
+index b9834b5..ef6e94c 100644
+--- a/file
++++ b/file
+@@ -1,10 +1,12 @@
+ LO, praise of the prowess of people-kings
+ of spear-armed Danes, in days long sped,
+ we have heard, and what honor the athelings won!
++
+ Oft Scyld the Scefing from squadroned foes,
+ from many a tribe, the mead-bench tore,
+ awing the earls. Since erst he lay
+ friendless, a foundling, fate repaid him:
++
+ for he waxed under welkin, in wealth he throve,
+ till before him the folk, both far and near,
+ who house by the whale-path, heard his mandate,
+EOF
+
+echo "#!$SHELL_PATH" >fake-editor.sh
+cat >> fake-editor.sh <<\EOF
+mv "$1" orig-patch &&
+mv patch "$1"
+EOF
+
+test_set_editor "$(pwd)/fake-editor.sh"
+chmod a+x fake-editor.sh
+
+test_expect_success 'add -e' '
+
+	cp fake-editor.sh file &&
+	git add -e &&
+	test_cmp fake-editor.sh file &&
+	git diff --cached > out &&
+	test_cmp out expected
+
+'
+
+test_done
-- 
1.5.6.rc1.181.gb439d

[PATCH v2 1/2] Allow git-apply to ignore the hunk headers

From: Johannes Schindelin <hidden>
Date: 2016-06-15 22:44:41

Sometimes, the easiest way to fix up a patch is to edit it directly, even
adding or deleting lines.  Now, many people are not as divine as certain
benevolent dictators as to update the hunk headers correctly at the first
try.

So teach the tool to do it for us.

Signed-off-by: Johannes Schindelin <redacted>
---
 Documentation/git-apply.txt |    7 ++++-
 builtin-apply.c             |   57 ++++++++++++++++++++++++++++++++++++++++---
 2 files changed, 59 insertions(+), 5 deletions(-)
diff --git a/Documentation/git-apply.txt b/Documentation/git-apply.txt
index 2dec2ec..e4c5530 100644
--- a/Documentation/git-apply.txt
+++ b/Documentation/git-apply.txt
@@ -12,7 +12,7 @@ SYNOPSIS
 'git-apply' [--stat] [--numstat] [--summary] [--check] [--index]
 	  [--apply] [--no-add] [--build-fake-ancestor <file>] [-R | --reverse]
 	  [--allow-binary-replacement | --binary] [--reject] [-z]
-	  [-pNUM] [-CNUM] [--inaccurate-eof] [--cached]
+	  [-pNUM] [-CNUM] [--inaccurate-eof] [--ignore-hunk-headers] [--cached]
 	  [--whitespace=<nowarn|warn|fix|error|error-all>]
 	  [--exclude=PATH] [--verbose] [<patch>...]
 
@@ -169,6 +169,11 @@ behavior:
 	correctly. This option adds support for applying such patches by
 	working around this bug.
 
+--ignore-hunk-headers::
+	Do not trust the line counts in the hunk headers, but infer them
+	by inspecting the patch (e.g. after editing the patch without
+	adjusting the hunk headers appropriately).
+
 -v, --verbose::
 	Report progress to stderr. By default, only a message about the
 	current patch being applied will be printed. This option will cause
diff --git a/builtin-apply.c b/builtin-apply.c
index c497889..b357e35 100644
--- a/builtin-apply.c
+++ b/builtin-apply.c
@@ -153,6 +153,7 @@ struct patch {
 	unsigned int is_binary:1;
 	unsigned int is_copy:1;
 	unsigned int is_rename:1;
+	unsigned int ignore_hunk_headers:1;
 	struct fragment *fragments;
 	char *result;
 	size_t resultsize;
@@ -882,6 +883,41 @@ static int parse_range(const char *line, int len, int offset, const char *expect
 	return offset + ex;
 }
 
+static int fixup_counts(char *line, int size, struct fragment *fragment)
+{
+	if (size < 1)
+		return -1;
+
+	fragment->oldlines = fragment->newlines = -1;
+
+	for (;;) {
+		int len = linelen(line, size);
+		if (!len)
+			break;
+
+		switch (*line) {
+		case ' ':
+			fragment->oldlines++;
+			/* fall through */
+		case '+':
+			fragment->newlines++;
+			break;
+		case '-':
+			fragment->oldlines++;
+			break;
+		default:
+			/* Probably "diff ..." */
+			return 0;
+		}
+
+		size -= len;
+		line += len;
+		if (size < 2 || !prefixcmp(line, "@@"))
+			break;
+	}
+	return 0;
+}
+
 /*
  * Parse a unified diff fragment header of the
  * form "@@ -a,b +c,d @@"
@@ -1013,6 +1049,9 @@ static int parse_fragment(char *line, unsigned long size,
 	offset = parse_fragment_header(line, len, fragment);
 	if (offset < 0)
 		return -1;
+	if (offset > 0 && patch->ignore_hunk_headers &&
+			fixup_counts(line + offset, size - offset, fragment))
+		return -1;
 	oldlines = fragment->oldlines;
 	newlines = fragment->newlines;
 	leading = 0;
@@ -2912,7 +2951,8 @@ static void prefix_patches(struct patch *p)
 	}
 }
 
-static int apply_patch(int fd, const char *filename, int inaccurate_eof)
+static int apply_patch(int fd, const char *filename, int inaccurate_eof,
+		int ignore_hunk_headers)
 {
 	size_t offset;
 	struct strbuf buf;
@@ -2929,6 +2969,7 @@ static int apply_patch(int fd, const char *filename, int inaccurate_eof)
 
 		patch = xcalloc(1, sizeof(*patch));
 		patch->inaccurate_eof = inaccurate_eof;
+		patch->ignore_hunk_headers = ignore_hunk_headers;
 		nr = parse_chunk(buf.buf + offset, buf.len - offset, patch);
 		if (nr < 0)
 			break;
@@ -2998,6 +3039,7 @@ int cmd_apply(int argc, const char **argv, const char *unused_prefix)
 	int i;
 	int read_stdin = 1;
 	int inaccurate_eof = 0;
+	int ignore_hunk_headers = 0;
 	int errs = 0;
 	int is_not_gitdir;
 
@@ -3015,7 +3057,8 @@ int cmd_apply(int argc, const char **argv, const char *unused_prefix)
 		int fd;
 
 		if (!strcmp(arg, "-")) {
-			errs |= apply_patch(0, "<stdin>", inaccurate_eof);
+			errs |= apply_patch(0, "<stdin>", inaccurate_eof,
+					ignore_hunk_headers);
 			read_stdin = 0;
 			continue;
 		}
@@ -3118,6 +3161,10 @@ int cmd_apply(int argc, const char **argv, const char *unused_prefix)
 			inaccurate_eof = 1;
 			continue;
 		}
+		if (!strcmp(arg, "--ignore-hunk-headers")) {
+			ignore_hunk_headers = 1;
+			continue;
+		}
 		if (0 < prefix_length)
 			arg = prefix_filename(prefix, prefix_length, arg);
 
@@ -3126,12 +3173,14 @@ int cmd_apply(int argc, const char **argv, const char *unused_prefix)
 			die("can't open patch '%s': %s", arg, strerror(errno));
 		read_stdin = 0;
 		set_default_whitespace_mode(whitespace_option);
-		errs |= apply_patch(fd, arg, inaccurate_eof);
+		errs |= apply_patch(fd, arg, inaccurate_eof,
+				ignore_hunk_headers);
 		close(fd);
 	}
 	set_default_whitespace_mode(whitespace_option);
 	if (read_stdin)
-		errs |= apply_patch(0, "<stdin>", inaccurate_eof);
+		errs |= apply_patch(0, "<stdin>", inaccurate_eof,
+				ignore_hunk_headers);
 	if (whitespace_error) {
 		if (squelch_whitespace_errors &&
 		    squelch_whitespace_errors < whitespace_error) {
-- 
1.5.6.rc1.181.gb439d

Re: [PATCH v2 2/2] git-add: introduce --edit (to edit the diff vs. the index)

From: Pieter de Bie <hidden>
Date: 2016-06-15 22:44:41

On 5 jun 2008, at 18:20, Johannes Schindelin wrote:
With "git add -e [<files>]", Git will fire up an editor with the  
current
diff relative to the index (i.e. what you would get with "git diff
[<files>]").

Now you can edit the patch as much as you like, including adding/ 
removing
lines, editing the text, whatever.  Make sure, though, that the first
character of the hunk lines is still a space, a plus or a minus.
Nice feature! However, the lockfile isn't deleted on my system (OS X),
perhaps because the atexit() isn't called after an exec(). How about  
this
patch?
diff --git a/builtin-add.c b/builtin-add.c
index 05ae40d..07fdd2e 100644
--- a/builtin-add.c
+++ b/builtin-add.c
@@ -192,6 +192,8 @@ int edit_patch(int argc, const char **argv, const  
char *prefix)
         struct child_process child;
         int ac;
         struct stat st;
+       const char * apply_args[] = { "apply", "--fixup-line-counts",
+                                     "--cached", lock.filename, NULL };

         memset(&child, 0, sizeof(child));
         child.argv = xcalloc(sizeof(const char *), (argc + 5));
@@ -224,10 +226,11 @@ int edit_patch(int argc, const char **argv,  
const char *prefix)
                 return 0;
         }

-       execl_git_cmd("apply", "--fixup-line-counts", "--cached",
-                       lock.filename, NULL);
+       child.argv = apply_args;
+       if (run_command(&child))
+               return 1;

-       return 1;
+       return 0;
  }

  static struct lock_file lock_file;
Keyboard shortcuts
hback out one level
jnext message in thread
kprevious message in thread
ldrill in
Escclose help / fold thread tree
?toggle this help