Re: [PATCH v3] git-add--interactive: manual hunk editing mode

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



On Mon, Jun 09, 2008 at 11:19:23PM +0200, Johan Herland wrote:

> On Monday 09 June 2008, Jeff King wrote:
> > But honestly, I don't really see a use case that isn't covered by
> > "manually edit the diff and apply the hunk". And the rationale in your
> > "side note" indicates that you think the same way.

Below is a simple patch to build interactive edit support on top of
Dscho's "git apply --recount" patch. Rather than create new hunks, the
action is just "edit and apply": if the apply is successful, the hunk is
removed from further consideration. This is just for playing with, and
not for commit:

  - it's not very well tested :)

  - I think the recount stuff may have flaws; I didn't follow the thread
    too closely, but Junio seemed to have a lot of comments (I am
    working under the assumption that Dscho will get that part right,
    and we can just build on top of it)

  - I tried one or two simple tests where I edited and applied an early
    hunk, and then resumed the loop for later hunks. Everything seemed
    to work, but I am not convinced that it isn't possible to make the
    rest of the hunk selection loop useless by applying early and
    invalidating all of the other hunks. That might be a flaw with this
    approach. A more sane interface might be to simply jump from the
    hunk selection loop into manually editing _all_ hunks and then
    applying, ending the hunk selection loop.

This should be applied on top of "allow git-apply to ignore the hunk
headers" (v3) which can be found on the list.  Obviously significant
portions of the patch below are based on Thomas' version.

-- >8 --
git-add--interactive: manual hunk editing mode

Adds a new option 'e' to the 'add -p' command loop that lets you
edit the current hunk in your favourite editor, applying the
result.
---
 git-add--interactive.perl |   81 +++++++++++++++++++++++++++++++++++++++++++++
 1 files changed, 81 insertions(+), 0 deletions(-)

diff --git a/git-add--interactive.perl b/git-add--interactive.perl
index 903953e..62b5aed 100755
--- a/git-add--interactive.perl
+++ b/git-add--interactive.perl
@@ -2,6 +2,7 @@
 
 use strict;
 use Git;
+use File::Temp;
 
 my $repo = Git->repository();
 
@@ -770,6 +771,76 @@ sub coalesce_overlapping_hunks {
 	return @out;
 }
 
+sub edit_hunk_manually {
+	my ($oldtext) = @_;
+
+	my $t = File::Temp->new(
+		TEMPLATE => $repo->repo_path . "/git-hunk-edit.XXXXXX",
+		SUFFIX => '.diff'
+	);
+	print $t "# Manual hunk edit mode -- see bottom for a quick guide\n";
+	print $t @$oldtext;
+	print $t <<EOF;
+# ---
+# To remove '-' lines, make them ' ' lines (context).
+# To remove '+' lines, delete them.
+# Empty lines and lines starting with # will be removed.
+#
+# Lines starting with @ start a new hunk. Line counts will be adjusted
+# according to contents. If the line numbers are missing altogether,
+# they will be inferred from the previous hunk.
+#
+# You can change the hunk to your heart's content, but it will be
+# refused if the end result (the entire patch including your edited
+# hunk) does not apply cleanly.
+EOF
+	close $t;
+
+	my $editor = $ENV{GIT_EDITOR} || $repo->config("core.editor")
+		|| $ENV{VISUAL} || $ENV{EDITOR} || "vi";
+	system('sh', '-c', $editor.' "$@"', $editor, $t);
+
+	open my $fh, '<', $t
+		or die "failed to open hunk edit file for reading: " . $!;
+	my @newtext = grep { !/^#/ } <$fh>;
+	close $fh;
+
+	# Reinsert the first hunk header if the user accidentally deleted it
+	if ($newtext[0] !~ /^@/) {
+		unshift @newtext, $oldtext->[0];
+	}
+	return \@newtext;
+}
+
+sub apply_diff {
+	open(my $fh, '|-', qw(git apply --cached --recount));
+	print $fh map { @$_ } @_;
+	return close $fh;
+}
+
+sub prompt_yesno {
+	my ($prompt) = @_;
+	while (1) {
+		print colored $prompt_color, $prompt;
+		my $line = <STDIN>;
+		return 0 if $line =~ /^n/i;
+		return 1 if $line =~ /^y/i;
+	}
+}
+
+sub edit_hunk_loop {
+	my ($head, $text) = @_;
+
+	while (1) {
+		$text = edit_hunk_manually($text);
+		apply_diff($head, $text) and return 1;
+		prompt_yesno(
+			'Your edited hunk does not apply. Edit again '
+			. '(saying "no" discards!) [y/n]? '
+		) or return 0;
+	}
+}
+
 sub help_patch_cmd {
 	print colored $help_color, <<\EOF ;
 y - stage this hunk
@@ -781,6 +852,7 @@ J - leave this hunk undecided, see next hunk
 k - leave this hunk undecided, see previous undecided hunk
 K - leave this hunk undecided, see previous hunk
 s - split the current hunk into smaller hunks
+e - manually edit the current hunk
 ? - print help
 EOF
 }
@@ -885,6 +957,7 @@ sub patch_update_file {
 		if (hunk_splittable($hunk[$ix]{TEXT})) {
 			$other .= '/s';
 		}
+		$other .= '/e';
 		for (@{$hunk[$ix]{DISPLAY}}) {
 			print;
 		}
@@ -949,6 +1022,14 @@ sub patch_update_file {
 				$num = scalar @hunk;
 				next;
 			}
+			elsif ($line =~ /^e/) {
+				if (edit_hunk_loop($head->{TEXT},
+						   $hunk[$ix]{TEXT})) {
+					splice @hunk, $ix, 1;
+					$num = @hunk;
+				}
+				next;
+			}
 			else {
 				help_patch_cmd($other);
 				next;
-- 
1.5.6.rc2.26.gda075.dirty

--
To unsubscribe from this list: send the line "unsubscribe git" in
the body of a message to majordomo@xxxxxxxxxxxxxxx
More majordomo info at  http://vger.kernel.org/majordomo-info.html

[Index of Archives]     [Linux Kernel Development]     [Gcc Help]     [IETF Annouce]     [DCCP]     [Netdev]     [Networking]     [Security]     [V4L]     [Bugtraq]     [Yosemite]     [MIPS Linux]     [ARM Linux]     [Linux Security]     [Linux RAID]     [Linux SCSI]     [Fedora Users]

  Powered by Linux