{"thread":{"id":"18826","subject":"[RFC PATCH] git add -p: new \"quit\" command at the prompt.","startedAt":"2009-04-10T14:57:01Z","lastAt":"2009-04-16T16:46:23Z","messageCount":15,"participants":["Matthieu Moy","Junio C Hamano","Sverre Rabbelier","Nicolas Sebrecht","Miles Bader","Wincent Colaiuta","Jeff King"],"isPatch":true,"patchVersion":1,"patchTotal":null},"messages":[{"id":"111010","messageId":"1239375421-2556-1-git-send-email-Matthieu.Moy@imag.fr","threadId":"18826","inReplyTo":null,"subject":"[RFC PATCH] git add -p: new \"quit\" command at the prompt.","fromName":"Matthieu Moy","fromEmail":"matthieu.moy@imag.fr","sentAt":"2009-04-10T14:57:01Z","receivedAt":"2009-04-10T14:57:01Z","isPatch":true,"sender":{"key":"git@matthieu-moy.fr","avatar":"https://avatars.githubusercontent.com/u/14709?v=4"},"body":"There's already 'd' to stop staging hunks in a file, but no command to\nstop the interactive staging (for the current files and the remaining\nones). This patch implements this functionality, and binds it to 'q'.\n---\n\nI'm not familiar at all with the code in git-add--interactive.perl, so\nmy code is mostly cut-and-pasted+adapted from the 'd' command.\nProbably suboptimal.\n\n git-add--interactive.perl |   20 +++++++++++++++++++-\n 1 files changed, 19 insertions(+), 1 deletions(-)\n\ndiff --git a/git-add--interactive.perl b/git-add--interactive.perl\nindex def062a..210d230 100755\n--- a/git-add--interactive.perl\n+++ b/git-add--interactive.perl\n@@ -894,6 +894,7 @@ sub help_patch_cmd {\n \tprint colored $help_color, <<\\EOF ;\n y - stage this hunk\n n - do not stage this hunk\n+q - quit, do not stage this hunk nor any of the remaining ones\n a - stage this and all the remaining hunks in the file\n d - do not stage this hunk nor any of the remaining hunks in the file\n g - select a hunk to go to\n@@ -930,7 +931,7 @@ sub patch_update_cmd {\n \t\t\t\t\t@mods);\n \t}\n \tfor (@them) {\n-\t\tpatch_update_file($_->{VALUE});\n+\t\treturn 0 if patch_update_file($_->{VALUE});\n \t}\n }\n \n@@ -976,6 +977,7 @@ sub display_hunks {\n }\n \n sub patch_update_file {\n+\tmy $quit = 0;\n \tmy ($ix, $num);\n \tmy $path = shift;\n \tmy ($head, @hunk) = parse_diff($path);\n@@ -1006,6 +1008,11 @@ sub patch_update_file {\n \t\t\t\t$_->{USE} = 0 foreach ($mode, @hunk);\n \t\t\t\tlast;\n \t\t\t}\n+\t\t\telsif ($line =~ /^q/i) {\n+\t\t\t\t$_->{USE} = 0 foreach ($mode, @hunk);\n+\t\t\t\t$quit = 1;\n+\t\t\t\tlast;\n+\t\t\t}\n \t\t\telse {\n \t\t\t\thelp_patch_cmd('');\n \t\t\t\tnext;\n@@ -1113,6 +1120,16 @@ sub patch_update_file {\n \t\t\t\t}\n \t\t\t\tnext;\n \t\t\t}\n+\t\t\telsif ($line =~ /^q/i) {\n+\t\t\t\twhile ($ix < $num) {\n+\t\t\t\t\tif (!defined $hunk[$ix]{USE}) {\n+\t\t\t\t\t\t$hunk[$ix]{USE} = 0;\n+\t\t\t\t\t}\n+\t\t\t\t\t$ix++;\n+\t\t\t\t}\n+\t\t\t\t$quit = 1;\n+\t\t\t\tnext;\n+\t\t\t}\n \t\t\telsif ($line =~ m|^/(.*)|) {\n \t\t\t\tmy $regex = $1;\n \t\t\t\tif ($1 eq \"\") {\n@@ -1239,6 +1256,7 @@ sub patch_update_file {\n \t}\n \n \tprint \"\\n\";\n+\treturn $quit;\n }\n \n sub diff_cmd {\n-- \n1.6.2.2.449.g92961.dirty\n"},{"id":"111074","messageId":"7vws9rdmgd.fsf@gitster.siamese.dyndns.org","threadId":"18826","inReplyTo":"1239375421-2556-1-git-send-email-Matthieu.Moy@imag.fr","subject":"Re: [RFC PATCH] git add -p: new \"quit\" command at the prompt.","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2009-04-11T19:22:58Z","receivedAt":"2009-04-11T19:22:58Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Matthieu Moy <Matthieu.Moy@imag.fr> writes:\n\n> There's already 'd' to stop staging hunks in a file, but no command to\n> stop the interactive staging (for the current files and the remaining\n> ones). This patch implements this functionality, and binds it to 'q'.\n> ---\n>\n> I'm not familiar at all with the code in git-add--interactive.perl, so\n> my code is mostly cut-and-pasted+adapted from the 'd' command.\n\nYou can say 'd' and then ^C, I think.\n"},{"id":"111126","messageId":"vpqfxgevy58.fsf@bauges.imag.fr","threadId":"18826","inReplyTo":"7vws9rdmgd.fsf@gitster.siamese.dyndns.org","subject":"Re: [RFC PATCH] git add -p: new \"quit\" command at the prompt.","fromName":"Matthieu Moy","fromEmail":"matthieu.moy@imag.fr","sentAt":"2009-04-12T12:45:23Z","receivedAt":"2009-04-12T12:45:23Z","isPatch":true,"sender":{"key":"git@matthieu-moy.fr","avatar":"https://avatars.githubusercontent.com/u/14709?v=4"},"body":"Junio C Hamano <gitster@pobox.com> writes:\n\n> Matthieu Moy <Matthieu.Moy@imag.fr> writes:\n>\n>> There's already 'd' to stop staging hunks in a file, but no command to\n>> stop the interactive staging (for the current files and the remaining\n>> ones). This patch implements this functionality, and binds it to 'q'.\n>> ---\n>>\n>> I'm not familiar at all with the code in git-add--interactive.perl, so\n>> my code is mostly cut-and-pasted+adapted from the 'd' command.\n>\n> You can say 'd' and then ^C, I think.\n\nYes, you /can/, and that's what I'm doing right now in this situation.\nBut that's undocumented, not so intuitive (I found out I could do that\nafter trying ^C alone, which doesn't work, staged content is recorded\non disk at the end of the file only, not after each prompt), ...\n\nI thought the situation was common enough to deserve an explicit\ncommand. The 'd' command is natural for \"git add -i\" + patch\nsubcommand, but for \"git add -p\", I found 'd' mostly useless, and I\nreally want a \"quit\" command.\n\nSure, I can live without it, but if other people would like to have\nit, please speak now ;-).\n\n-- \nMatthieu\n"},{"id":"111127","messageId":"fabb9a1e0904120554n355adf26s99966c92e874880f@mail.gmail.com","threadId":"18826","inReplyTo":"vpqfxgevy58.fsf@bauges.imag.fr","subject":"Re: [RFC PATCH] git add -p: new \"quit\" command at the prompt.","fromName":"Sverre Rabbelier","fromEmail":"srabbelier@gmail.com","sentAt":"2009-04-12T12:54:22Z","receivedAt":"2009-04-12T12:54:22Z","isPatch":true,"sender":{"key":"srabbelier@gmail.com","avatar":"https://avatars.githubusercontent.com/u/3098?v=4"},"body":"Heya,\n\nOn Sunday, April 12, 2009, Matthieu Moy <Matthieu.Moy@imag.fr> wrote:\n> Sure, I can live without it, but if other people would like to have\n> it, please speak now ;-).\n\nYes please, I would like a q command to git add -p too!\n\n--\nCheers,\n\nSverre Rabbelier\n\n-- \nCheers,\n\nSverre Rabbelier\n"},{"id":"111132","messageId":"20090412172936.GA12909@vidovic","threadId":"18826","inReplyTo":"vpqfxgevy58.fsf@bauges.imag.fr","subject":"[RFC PATCH] Re: git add -p: new \"quit\" command at the prompt.","fromName":"Nicolas Sebrecht","fromEmail":"nicolas.s-dev@laposte.net","sentAt":"2009-04-12T17:29:36Z","receivedAt":"2009-04-12T17:29:36Z","isPatch":true,"sender":{"key":"nicolas.s-dev@laposte.net","avatar":null},"body":"On Sun, Apr 12, 2009 at 02:45:23PM +0200, Matthieu Moy wrote:\n\n> I thought the situation was common enough to deserve an explicit\n> command. The 'd' command is natural for \"git add -i\" + patch\n> subcommand, but for \"git add -p\", I found 'd' mostly useless, and I\n> really want a \"quit\" command.\n> \n> Sure, I can live without it, but if other people would like to have\n> it, please speak now ;-).\n\nAcked-by: Nicolas Sebrecht <nicolas.s-dev@laposte.net>\n\n-- \nNicolas Sebrecht\n"},{"id":"111146","messageId":"buor5zxcoxc.fsf@dhlpc061.dev.necel.com","threadId":"18826","inReplyTo":"fabb9a1e0904120554n355adf26s99966c92e874880f@mail.gmail.com","subject":"Re: [RFC PATCH] git add -p: new \"quit\" command at the prompt.","fromName":"Miles Bader","fromEmail":"miles@gnu.org","sentAt":"2009-04-13T01:39:27Z","receivedAt":"2009-04-13T01:39:27Z","isPatch":true,"sender":{"key":"miles@gnu.org","avatar":"https://gravatar.com/avatar/01069b69593af7bff28e2f97afeb3644ae6fe2f5f56cb3a8cf34c5fb8c36efe5?d=mp&s=160"},"body":"Sverre Rabbelier <srabbelier@gmail.com> writes:\n> Yes please, I would like a q command to git add -p too!\n\nMe too.\n\nEven though I've used add -p a lot, I _still_ find myself looking for a\nquit sub-command sometimes and being momentarily confused because there\nisn't one... it just seems such a natural thing...\n\n-Miles\n\n-- \nWould you like fries with that?\n"},{"id":"111197","messageId":"80317CFC-6D87-4232-92EB-C5927F262E17@wincent.com","threadId":"18826","inReplyTo":"vpqfxgevy58.fsf@bauges.imag.fr","subject":"Re: [RFC PATCH] git add -p: new \"quit\" command at the prompt.","fromName":"Wincent Colaiuta","fromEmail":"win@wincent.com","sentAt":"2009-04-13T16:38:22Z","receivedAt":"2009-04-13T16:38:22Z","isPatch":true,"sender":{"key":"greg@hurrell.net","avatar":"https://avatars.githubusercontent.com/u/7074?v=4"},"body":"El 12/4/2009, a las 14:45, Matthieu Moy escribió:\n\n> Junio C Hamano <gitster@pobox.com> writes:\n>\n>> You can say 'd' and then ^C, I think.\n>\n> Yes, you /can/, and that's what I'm doing right now in this situation.\n> But that's undocumented, not so intuitive (I found out I could do that\n> after trying ^C alone, which doesn't work, staged content is recorded\n> on disk at the end of the file only, not after each prompt), ...\n>\n> I thought the situation was common enough to deserve an explicit\n> command. The 'd' command is natural for \"git add -i\" + patch\n> subcommand, but for \"git add -p\", I found 'd' mostly useless, and I\n> really want a \"quit\" command.\n>\n> Sure, I can live without it, but if other people would like to have\n> it, please speak now ;-).\n\nYes, I'd like it too. I've been using ^C a lot, but I'd never noticed  \nthat changes weren't staged except at the end of each file. Thanks for  \nbringing it up; you might have saved some people (including me) from  \nbeing bitten by it at some point.\n\nWincent\n"},{"id":"111317","messageId":"vpqtz4rynhp.fsf@bauges.imag.fr","threadId":"18826","inReplyTo":"vpqfxgevy58.fsf@bauges.imag.fr","subject":"Re: [RFC PATCH] git add -p: new \"quit\" command at the prompt.","fromName":"Matthieu Moy","fromEmail":"matthieu.moy@imag.fr","sentAt":"2009-04-14T20:44:02Z","receivedAt":"2009-04-14T20:44:02Z","isPatch":true,"sender":{"key":"git@matthieu-moy.fr","avatar":"https://avatars.githubusercontent.com/u/14709?v=4"},"body":"Matthieu Moy <Matthieu.Moy@imag.fr> writes:\n\n> Junio C Hamano <gitster@pobox.com> writes:\n>\n>> Matthieu Moy <Matthieu.Moy@imag.fr> writes:\n>>\n>>> There's already 'd' to stop staging hunks in a file, but no command to\n>>> stop the interactive staging (for the current files and the remaining\n>>> ones). This patch implements this functionality, and binds it to 'q'.\n>>> ---\n>>>\n>>> I'm not familiar at all with the code in git-add--interactive.perl, so\n>>> my code is mostly cut-and-pasted+adapted from the 'd' command.\n>>\n>> You can say 'd' and then ^C, I think.\n>\n> Yes, you /can/, and that's what I'm doing right now in this situation.\n> But that's undocumented, not so intuitive (I found out I could do that\n> after trying ^C alone, which doesn't work, staged content is recorded\n> on disk at the end of the file only, not after each prompt), ...\n>\n> I thought the situation was common enough to deserve an explicit\n> command. The 'd' command is natural for \"git add -i\" + patch\n> subcommand, but for \"git add -p\", I found 'd' mostly useless, and I\n> really want a \"quit\" command.\n>\n> Sure, I can live without it, but if other people would like to have\n> it, please speak now ;-).\n\nI think everybody agree that the intention of the patch is good (well,\nseveral pro, and no real counter-argument). I'll send an updated\nversion with documentation soon, but I'd appreciate review and\ncomments on the code.\n\nI'm not really happy with the fact that I mainly cut-and-pasted code\nfrom the \"d\" command, but OTOH, that's already how the code is today\n(huge if/elsif/... with similar elsif blocks for each command).\n\n-- \nMatthieu\n"},{"id":"111404","messageId":"7v7i1lqz24.fsf@gitster.siamese.dyndns.org","threadId":"18826","inReplyTo":"vpqtz4rynhp.fsf@bauges.imag.fr","subject":"Re: [RFC PATCH] git add -p: new \"quit\" command at the prompt.","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2009-04-15T23:25:55Z","receivedAt":"2009-04-15T23:25:55Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Matthieu Moy <Matthieu.Moy@imag.fr> writes:\n\n> I think everybody agree that the intention of the patch is good (well,\n> several pro, and no real counter-argument).\n\nOh, I think we have already passed that state long time ago.  It's queued\nas c9cc8d9 ([NEEDS SIGN OFF, DOC, AND REVIEW] git add -p: new \"quit\"\ncommand at the prompt., 2009-04-10) in 'pu'.\n\nI agree that there is a \"Huh?\" factor in the repeated and similar hunks to\npatch_update_file, but the first hunk is dealing with the mode change and\nthe second one is about the patch text.\n\nCurrently parse_diff_header() returns the mode line into $mode and the\nmain loop treats $mode differently from @hunk, which is an array of hunks\nparsed by parse_diff().  Treating $mode as a \"fake hunk\" by unshifting it\nat the beginning of @hunk array and teaching the main loop minor details\nsuch as $mode \"fake hunk\" cannot be edited nor split, I suspect we _could_\nunify the two.\n\nca72468 (add--interactive: allow user to choose mode update, 2008-03-27)\nintroduced this duplication.  Jeff, what do you think?  I am not sure if\nit is worth it.\n"},{"id":"111419","messageId":"20090416060027.GA2992@coredump.intra.peff.net","threadId":"18826","inReplyTo":"7v7i1lqz24.fsf@gitster.siamese.dyndns.org","subject":"Re: [RFC PATCH] git add -p: new \"quit\" command at the prompt.","fromName":"Jeff King","fromEmail":"peff@peff.net","sentAt":"2009-04-16T06:00:27Z","receivedAt":"2009-04-16T06:00:27Z","isPatch":true,"sender":{"key":"peff@peff.net","avatar":"https://avatars.githubusercontent.com/u/45925?v=4"},"body":"On Wed, Apr 15, 2009 at 04:25:55PM -0700, Junio C Hamano wrote:\n\n> Currently parse_diff_header() returns the mode line into $mode and the\n> main loop treats $mode differently from @hunk, which is an array of hunks\n> parsed by parse_diff().  Treating $mode as a \"fake hunk\" by unshifting it\n> at the beginning of @hunk array and teaching the main loop minor details\n> such as $mode \"fake hunk\" cannot be edited nor split, I suspect we _could_\n> unify the two.\n> \n> ca72468 (add--interactive: allow user to choose mode update, 2008-03-27)\n> introduced this duplication.  Jeff, what do you think?  I am not sure if\n> it is worth it.\n\nYeah, at least at one point I thought that was possible:\n\n  http://article.gmane.org/gmane.comp.version-control.git/78340\n\nLet me see how painful it would be.\n\n-Peff\n"},{"id":"111422","messageId":"20090416065223.GA927@coredump.intra.peff.net","threadId":"18826","inReplyTo":"20090416060027.GA2992@coredump.intra.peff.net","subject":"Re: [RFC PATCH] git add -p: new \"quit\" command at the prompt.","fromName":"Jeff King","fromEmail":"peff@peff.net","sentAt":"2009-04-16T06:52:23Z","receivedAt":"2009-04-16T06:52:23Z","isPatch":true,"sender":{"key":"peff@peff.net","avatar":"https://avatars.githubusercontent.com/u/45925?v=4"},"body":"On Thu, Apr 16, 2009 at 02:00:27AM -0400, Jeff King wrote:\n\n> > Currently parse_diff_header() returns the mode line into $mode and the\n> > main loop treats $mode differently from @hunk, which is an array of hunks\n> > parsed by parse_diff().  Treating $mode as a \"fake hunk\" by unshifting it\n> > at the beginning of @hunk array and teaching the main loop minor details\n> > such as $mode \"fake hunk\" cannot be edited nor split, I suspect we _could_\n> > unify the two.\n>\n> Let me see how painful it would be.\n\nNot too painful at all. We can _almost_ get away with a really minimal\n\"just unshift it\" patch, but calling splittable_hunk() generates some\nperl warnings (because the hunk lacks @@ lines), and doing a hunk edit\nseems to confuse the code (it duplicates the \"old mode\" line for some\nreason). It is not worth trying to fix, though, as editing the mode hunk\nis not useful in practice (see the commit message below).\n\nIt would also be possible to refactor the header parsing to just pull\nthe mode lines out as we are parsing the hunks. However, it is probably\nnot worth the added complexity: you have header lines, then some mode\nlines, then some more header lines, then some hunks. So you have to keep\nmore state around to do a linear parse.\n\nAnyway, I think this is a nice improvement on its own, and it should\nmake Matthieu's patch a little cleaner.\n\n-- >8 --\nSubject: [PATCH] add-interactive: refactor mode hunk handling\n\nThe original implementation considered the mode separately\nfrom the rest of the hunks, asking about it outside the main\nhunk-selection loop. This patch instead places a mode change\nas the first hunk in the loop. This has two advantages:\n\n  1. less duplicated code (since we use the main selection\n     loop). This also cleans up an inconsistency, which is\n     that the main selection loop separates options with a\n     comma, whereas the mode prompt used slashes.\n\n  2. users can now skip the mode change and come back to it,\n     search for it (via \"/mode\"), etc, as they can with other\n     hunks.\n\nTo facilitate this, each hunk is now marked with a \"type\".\nMode hunks are not considered for splitting (which would\nmake no sense, and also confuses the split_hunk function),\nnor are they editable. In theory, one could edit the mode\nlines and change to an entirely new mode. In practice, there\nare only two modes that git cares about (0644 and 0755), so\neither you want to move from one to the other or not (and\nyou can do that by staging or not staging).\n\nSigned-off-by: Jeff King <peff@peff.net>\n---\n git-add--interactive.perl |   59 ++++++++++++++++-----------------------------\n 1 files changed, 21 insertions(+), 38 deletions(-)\n\ndiff --git a/git-add--interactive.perl b/git-add--interactive.perl\nindex def062a..b895e3b 100755\n--- a/git-add--interactive.perl\n+++ b/git-add--interactive.perl\n@@ -620,11 +620,12 @@ sub parse_diff {\n \tif ($diff_use_color) {\n \t\t@colored = run_cmd_pipe(qw(git diff-files -p --color --), $path);\n \t}\n-\tmy (@hunk) = { TEXT => [], DISPLAY => [] };\n+\tmy (@hunk) = { TEXT => [], DISPLAY => [], TYPE => 'header' };\n \n \tfor (my $i = 0; $i < @diff; $i++) {\n \t\tif ($diff[$i] =~ /^@@ /) {\n-\t\t\tpush @hunk, { TEXT => [], DISPLAY => [] };\n+\t\t\tpush @hunk, { TEXT => [], DISPLAY => [],\n+\t\t\t\tTYPE => 'hunk' };\n \t\t}\n \t\tpush @{$hunk[-1]{TEXT}}, $diff[$i];\n \t\tpush @{$hunk[-1]{DISPLAY}},\n@@ -636,8 +637,8 @@ sub parse_diff {\n sub parse_diff_header {\n \tmy $src = shift;\n \n-\tmy $head = { TEXT => [], DISPLAY => [] };\n-\tmy $mode = { TEXT => [], DISPLAY => [] };\n+\tmy $head = { TEXT => [], DISPLAY => [], TYPE => 'header' };\n+\tmy $mode = { TEXT => [], DISPLAY => [], TYPE => 'mode' };\n \n \tfor (my $i = 0; $i < @{$src->{TEXT}}; $i++) {\n \t\tmy $dest = $src->{TEXT}->[$i] =~ /^(old|new) mode (\\d+)$/ ?\n@@ -684,6 +685,7 @@ sub split_hunk {\n \t\tmy $this = +{\n \t\t\tTEXT => [],\n \t\t\tDISPLAY => [],\n+\t\t\tTYPE => 'hunk',\n \t\t\tOLD => $o_ofs,\n \t\t\tNEW => $n_ofs,\n \t\t\tOCNT => 0,\n@@ -873,7 +875,11 @@ sub edit_hunk_loop {\n \t\tif (!defined $text) {\n \t\t\treturn undef;\n \t\t}\n-\t\tmy $newhunk = { TEXT => $text, USE => 1 };\n+\t\tmy $newhunk = {\n+\t\t\tTEXT => $text,\n+\t\t\tTYPE => $hunk->[$ix]->{TYPE},\n+\t\t\tUSE => 1\n+\t\t};\n \t\tif (diff_applies($head,\n \t\t\t\t @{$hunk}[0..$ix-1],\n \t\t\t\t $newhunk,\n@@ -985,32 +991,7 @@ sub patch_update_file {\n \t}\n \n \tif (@{$mode->{TEXT}}) {\n-\t\twhile (1) {\n-\t\t\tprint @{$mode->{DISPLAY}};\n-\t\t\tprint colored $prompt_color,\n-\t\t\t\t\"Stage mode change [y/n/a/d/?]? \";\n-\t\t\tmy $line = prompt_single_character;\n-\t\t\tif ($line =~ /^y/i) {\n-\t\t\t\t$mode->{USE} = 1;\n-\t\t\t\tlast;\n-\t\t\t}\n-\t\t\telsif ($line =~ /^n/i) {\n-\t\t\t\t$mode->{USE} = 0;\n-\t\t\t\tlast;\n-\t\t\t}\n-\t\t\telsif ($line =~ /^a/i) {\n-\t\t\t\t$_->{USE} = 1 foreach ($mode, @hunk);\n-\t\t\t\tlast;\n-\t\t\t}\n-\t\t\telsif ($line =~ /^d/i) {\n-\t\t\t\t$_->{USE} = 0 foreach ($mode, @hunk);\n-\t\t\t\tlast;\n-\t\t\t}\n-\t\t\telse {\n-\t\t\t\thelp_patch_cmd('');\n-\t\t\t\tnext;\n-\t\t\t}\n-\t\t}\n+\t\tunshift @hunk, $mode;\n \t}\n \n \t$num = scalar @hunk;\n@@ -1054,14 +1035,19 @@ sub patch_update_file {\n \t\t}\n \t\tlast if (!$undecided);\n \n-\t\tif (hunk_splittable($hunk[$ix]{TEXT})) {\n+\t\tif ($hunk[$ix]{TYPE} eq 'hunk' &&\n+\t\t    hunk_splittable($hunk[$ix]{TEXT})) {\n \t\t\t$other .= ',s';\n \t\t}\n-\t\t$other .= ',e';\n+\t\tif ($hunk[$ix]{TYPE} eq 'hunk') {\n+\t\t\t$other .= ',e';\n+\t\t}\n \t\tfor (@{$hunk[$ix]{DISPLAY}}) {\n \t\t\tprint;\n \t\t}\n-\t\tprint colored $prompt_color, \"Stage this hunk [y,n,a,d,/$other,?]? \";\n+\t\tprint colored $prompt_color, 'Stage ',\n+\t\t  ($hunk[$ix]{TYPE} eq 'mode' ? 'mode change' : 'this hunk'),\n+\t\t  \" [y,n,a,d,/$other,?]? \";\n \t\tmy $line = prompt_single_character;\n \t\tif ($line) {\n \t\t\tif ($line =~ /^y/i) {\n@@ -1193,7 +1179,7 @@ sub patch_update_file {\n \t\t\t\t$num = scalar @hunk;\n \t\t\t\tnext;\n \t\t\t}\n-\t\t\telsif ($line =~ /^e/) {\n+\t\t\telsif ($other =~ /e/ && $line =~ /^e/) {\n \t\t\t\tmy $newhunk = edit_hunk_loop($head, \\@hunk, $ix);\n \t\t\t\tif (defined $newhunk) {\n \t\t\t\t\tsplice @hunk, $ix, 1, $newhunk;\n@@ -1214,9 +1200,6 @@ sub patch_update_file {\n \n \tmy $n_lofs = 0;\n \tmy @result = ();\n-\tif ($mode->{USE}) {\n-\t\tpush @result, @{$mode->{TEXT}};\n-\t}\n \tfor (@hunk) {\n \t\tif ($_->{USE}) {\n \t\t\tpush @result, @{$_->{TEXT}};\n-- \n1.6.3.rc0.157.g02b29.dirty\n"},{"id":"111425","messageId":"20090416071415.GC20071@coredump.intra.peff.net","threadId":"18826","inReplyTo":"20090416065223.GA927@coredump.intra.peff.net","subject":"Re: [RFC PATCH] git add -p: new \"quit\" command at the prompt.","fromName":"Jeff King","fromEmail":"peff@peff.net","sentAt":"2009-04-16T07:14:15Z","receivedAt":"2009-04-16T07:14:15Z","isPatch":true,"sender":{"key":"peff@peff.net","avatar":"https://avatars.githubusercontent.com/u/45925?v=4"},"body":"On Thu, Apr 16, 2009 at 02:52:23AM -0400, Jeff King wrote:\n\n> Anyway, I think this is a nice improvement on its own, and it should\n> make Matthieu's patch a little cleaner.\n\nHmm, it looks like you just applied Matthieu's patch to next already.\nHere is the rebased version of mine (the conflict resolution was pretty\ntrivial, though: just delete the newly added 'q' option from the mode\nloop, which no longer exists).\n\n-- >8 --\nSubject: [PATCH] add-interactive: refactor mode hunk handling\n\nThe original implementation considered the mode separately\nfrom the rest of the hunks, asking about it outside the main\nhunk-selection loop. This patch instead places a mode change\nas the first hunk in the loop. This has two advantages:\n\n  1. less duplicated code (since we use the main selection\n     loop). This also cleans up an inconsistency, which is\n     that the main selection loop separates options with a\n     comma, whereas the mode prompt used slashes.\n\n  2. users can now skip the mode change and come back to it,\n     search for it (via \"/mode\"), etc, as they can with other\n     hunks.\n\nTo facilitate this, each hunk is now marked with a \"type\".\nMode hunks are not considered for splitting (which would\nmake no sense, and also confuses the split_hunk function),\nnor are they editable. In theory, one could edit the mode\nlines and change to a new mode. In practice, there are only\ntwo modes that git cares about (0644 and 0755), so either\nyou want to move from one to the other or not (and you can\ndo that by staging or not staging).\n\nSigned-off-by: Jeff King <peff@peff.net>\n---\n git-add--interactive.perl |   64 ++++++++++++++------------------------------\n 1 files changed, 21 insertions(+), 43 deletions(-)\n\ndiff --git a/git-add--interactive.perl b/git-add--interactive.perl\nindex 210d230..60dd1b5 100755\n--- a/git-add--interactive.perl\n+++ b/git-add--interactive.perl\n@@ -620,11 +620,12 @@ sub parse_diff {\n \tif ($diff_use_color) {\n \t\t@colored = run_cmd_pipe(qw(git diff-files -p --color --), $path);\n \t}\n-\tmy (@hunk) = { TEXT => [], DISPLAY => [] };\n+\tmy (@hunk) = { TEXT => [], DISPLAY => [], TYPE => 'header' };\n \n \tfor (my $i = 0; $i < @diff; $i++) {\n \t\tif ($diff[$i] =~ /^@@ /) {\n-\t\t\tpush @hunk, { TEXT => [], DISPLAY => [] };\n+\t\t\tpush @hunk, { TEXT => [], DISPLAY => [],\n+\t\t\t\tTYPE => 'hunk' };\n \t\t}\n \t\tpush @{$hunk[-1]{TEXT}}, $diff[$i];\n \t\tpush @{$hunk[-1]{DISPLAY}},\n@@ -636,8 +637,8 @@ sub parse_diff {\n sub parse_diff_header {\n \tmy $src = shift;\n \n-\tmy $head = { TEXT => [], DISPLAY => [] };\n-\tmy $mode = { TEXT => [], DISPLAY => [] };\n+\tmy $head = { TEXT => [], DISPLAY => [], TYPE => 'header' };\n+\tmy $mode = { TEXT => [], DISPLAY => [], TYPE => 'mode' };\n \n \tfor (my $i = 0; $i < @{$src->{TEXT}}; $i++) {\n \t\tmy $dest = $src->{TEXT}->[$i] =~ /^(old|new) mode (\\d+)$/ ?\n@@ -684,6 +685,7 @@ sub split_hunk {\n \t\tmy $this = +{\n \t\t\tTEXT => [],\n \t\t\tDISPLAY => [],\n+\t\t\tTYPE => 'hunk',\n \t\t\tOLD => $o_ofs,\n \t\t\tNEW => $n_ofs,\n \t\t\tOCNT => 0,\n@@ -873,7 +875,11 @@ sub edit_hunk_loop {\n \t\tif (!defined $text) {\n \t\t\treturn undef;\n \t\t}\n-\t\tmy $newhunk = { TEXT => $text, USE => 1 };\n+\t\tmy $newhunk = {\n+\t\t\tTEXT => $text,\n+\t\t\tTYPE => $hunk->[$ix]->{TYPE},\n+\t\t\tUSE => 1\n+\t\t};\n \t\tif (diff_applies($head,\n \t\t\t\t @{$hunk}[0..$ix-1],\n \t\t\t\t $newhunk,\n@@ -987,37 +993,7 @@ sub patch_update_file {\n \t}\n \n \tif (@{$mode->{TEXT}}) {\n-\t\twhile (1) {\n-\t\t\tprint @{$mode->{DISPLAY}};\n-\t\t\tprint colored $prompt_color,\n-\t\t\t\t\"Stage mode change [y/n/a/d/?]? \";\n-\t\t\tmy $line = prompt_single_character;\n-\t\t\tif ($line =~ /^y/i) {\n-\t\t\t\t$mode->{USE} = 1;\n-\t\t\t\tlast;\n-\t\t\t}\n-\t\t\telsif ($line =~ /^n/i) {\n-\t\t\t\t$mode->{USE} = 0;\n-\t\t\t\tlast;\n-\t\t\t}\n-\t\t\telsif ($line =~ /^a/i) {\n-\t\t\t\t$_->{USE} = 1 foreach ($mode, @hunk);\n-\t\t\t\tlast;\n-\t\t\t}\n-\t\t\telsif ($line =~ /^d/i) {\n-\t\t\t\t$_->{USE} = 0 foreach ($mode, @hunk);\n-\t\t\t\tlast;\n-\t\t\t}\n-\t\t\telsif ($line =~ /^q/i) {\n-\t\t\t\t$_->{USE} = 0 foreach ($mode, @hunk);\n-\t\t\t\t$quit = 1;\n-\t\t\t\tlast;\n-\t\t\t}\n-\t\t\telse {\n-\t\t\t\thelp_patch_cmd('');\n-\t\t\t\tnext;\n-\t\t\t}\n-\t\t}\n+\t\tunshift @hunk, $mode;\n \t}\n \n \t$num = scalar @hunk;\n@@ -1061,14 +1037,19 @@ sub patch_update_file {\n \t\t}\n \t\tlast if (!$undecided);\n \n-\t\tif (hunk_splittable($hunk[$ix]{TEXT})) {\n+\t\tif ($hunk[$ix]{TYPE} eq 'hunk' &&\n+\t\t    hunk_splittable($hunk[$ix]{TEXT})) {\n \t\t\t$other .= ',s';\n \t\t}\n-\t\t$other .= ',e';\n+\t\tif ($hunk[$ix]{TYPE} eq 'hunk') {\n+\t\t\t$other .= ',e';\n+\t\t}\n \t\tfor (@{$hunk[$ix]{DISPLAY}}) {\n \t\t\tprint;\n \t\t}\n-\t\tprint colored $prompt_color, \"Stage this hunk [y,n,a,d,/$other,?]? \";\n+\t\tprint colored $prompt_color, 'Stage ',\n+\t\t  ($hunk[$ix]{TYPE} eq 'mode' ? 'mode change' : 'this hunk'),\n+\t\t  \" [y,n,a,d,/$other,?]? \";\n \t\tmy $line = prompt_single_character;\n \t\tif ($line) {\n \t\t\tif ($line =~ /^y/i) {\n@@ -1210,7 +1191,7 @@ sub patch_update_file {\n \t\t\t\t$num = scalar @hunk;\n \t\t\t\tnext;\n \t\t\t}\n-\t\t\telsif ($line =~ /^e/) {\n+\t\t\telsif ($other =~ /e/ && $line =~ /^e/) {\n \t\t\t\tmy $newhunk = edit_hunk_loop($head, \\@hunk, $ix);\n \t\t\t\tif (defined $newhunk) {\n \t\t\t\t\tsplice @hunk, $ix, 1, $newhunk;\n@@ -1231,9 +1212,6 @@ sub patch_update_file {\n \n \tmy $n_lofs = 0;\n \tmy @result = ();\n-\tif ($mode->{USE}) {\n-\t\tpush @result, @{$mode->{TEXT}};\n-\t}\n \tfor (@hunk) {\n \t\tif ($_->{USE}) {\n \t\t\tpush @result, @{$_->{TEXT}};\n-- \n1.6.3.rc0.204.g6bb2\n"},{"id":"111457","messageId":"vpqiql4tuov.fsf@bauges.imag.fr","threadId":"18826","inReplyTo":"20090416071415.GC20071@coredump.intra.peff.net","subject":"Re: [RFC PATCH] git add -p: new \"quit\" command at the prompt.","fromName":"Matthieu Moy","fromEmail":"matthieu.moy@imag.fr","sentAt":"2009-04-16T16:44:16Z","receivedAt":"2009-04-16T16:44:16Z","isPatch":true,"sender":{"key":"git@matthieu-moy.fr","avatar":"https://avatars.githubusercontent.com/u/14709?v=4"},"body":"Jeff King <peff@peff.net> writes:\n\n> On Thu, Apr 16, 2009 at 02:52:23AM -0400, Jeff King wrote:\n>\n>> Anyway, I think this is a nice improvement on its own, and it should\n>> make Matthieu's patch a little cleaner.\n>\n> Hmm, it looks like you just applied Matthieu's patch to next\n> already.\n\n2 things : my patch was lacking a Signed-off-by:, and your (Junio)\nmodification to add the documentation has a typo (quite instead of\nquit). I'm resending the patch with a Signed-off-by, in case, and\nanother patch fixes the typo (and updates the help with 'g' and '/').\n\n-- \nMatthieu\n"},{"id":"111459","messageId":"1239900383-29628-1-git-send-email-Matthieu.Moy@imag.fr","threadId":"18826","inReplyTo":"vpqiql4tuov.fsf@bauges.imag.fr","subject":"[PATCH 1/2] git add -p: new \"quit\" command at the prompt.","fromName":"Matthieu Moy","fromEmail":"matthieu.moy@imag.fr","sentAt":"2009-04-16T16:46:22Z","receivedAt":"2009-04-16T16:46:22Z","isPatch":true,"sender":{"key":"git@matthieu-moy.fr","avatar":"https://avatars.githubusercontent.com/u/14709?v=4"},"body":"There's already 'd' to stop staging hunks in a file, but no explicit\ncommand to stop the interactive staging (for the current files and the\nremaining ones).  Of course you can do 'd' and then ^C, but it would be\nmore intuitive to allow 'quit' action.\n\nSigned-off-by: Matthieu Moy <Matthieu.Moy@imag.fr>\nSigned-off-by: Junio C Hamano <gitster@pobox.com>\n---\n Documentation/git-add.txt |    1 +\n git-add--interactive.perl |   20 +++++++++++++++++++-\n 2 files changed, 20 insertions(+), 1 deletions(-)\n\ndiff --git a/Documentation/git-add.txt b/Documentation/git-add.txt\nindex ce71838..709e04b 100644\n--- a/Documentation/git-add.txt\n+++ b/Documentation/git-add.txt\n@@ -245,6 +245,7 @@ patch::\n \n        y - stage this hunk\n        n - do not stage this hunk\n+       q - quite, do not stage this hunk nor any of the remaining ones\n        a - stage this and all the remaining hunks in the file\n        d - do not stage this hunk nor any of the remaining hunks in the file\n        j - leave this hunk undecided, see next undecided hunk\ndiff --git a/git-add--interactive.perl b/git-add--interactive.perl\nindex def062a..210d230 100755\n--- a/git-add--interactive.perl\n+++ b/git-add--interactive.perl\n@@ -894,6 +894,7 @@ sub help_patch_cmd {\n \tprint colored $help_color, <<\\EOF ;\n y - stage this hunk\n n - do not stage this hunk\n+q - quit, do not stage this hunk nor any of the remaining ones\n a - stage this and all the remaining hunks in the file\n d - do not stage this hunk nor any of the remaining hunks in the file\n g - select a hunk to go to\n@@ -930,7 +931,7 @@ sub patch_update_cmd {\n \t\t\t\t\t@mods);\n \t}\n \tfor (@them) {\n-\t\tpatch_update_file($_->{VALUE});\n+\t\treturn 0 if patch_update_file($_->{VALUE});\n \t}\n }\n \n@@ -976,6 +977,7 @@ sub display_hunks {\n }\n \n sub patch_update_file {\n+\tmy $quit = 0;\n \tmy ($ix, $num);\n \tmy $path = shift;\n \tmy ($head, @hunk) = parse_diff($path);\n@@ -1006,6 +1008,11 @@ sub patch_update_file {\n \t\t\t\t$_->{USE} = 0 foreach ($mode, @hunk);\n \t\t\t\tlast;\n \t\t\t}\n+\t\t\telsif ($line =~ /^q/i) {\n+\t\t\t\t$_->{USE} = 0 foreach ($mode, @hunk);\n+\t\t\t\t$quit = 1;\n+\t\t\t\tlast;\n+\t\t\t}\n \t\t\telse {\n \t\t\t\thelp_patch_cmd('');\n \t\t\t\tnext;\n@@ -1113,6 +1120,16 @@ sub patch_update_file {\n \t\t\t\t}\n \t\t\t\tnext;\n \t\t\t}\n+\t\t\telsif ($line =~ /^q/i) {\n+\t\t\t\twhile ($ix < $num) {\n+\t\t\t\t\tif (!defined $hunk[$ix]{USE}) {\n+\t\t\t\t\t\t$hunk[$ix]{USE} = 0;\n+\t\t\t\t\t}\n+\t\t\t\t\t$ix++;\n+\t\t\t\t}\n+\t\t\t\t$quit = 1;\n+\t\t\t\tnext;\n+\t\t\t}\n \t\t\telsif ($line =~ m|^/(.*)|) {\n \t\t\t\tmy $regex = $1;\n \t\t\t\tif ($1 eq \"\") {\n@@ -1239,6 +1256,7 @@ sub patch_update_file {\n \t}\n \n \tprint \"\\n\";\n+\treturn $quit;\n }\n \n sub diff_cmd {\n-- \n1.6.2.2.449.g92961.dirty\n"},{"id":"111458","messageId":"1239900383-29628-2-git-send-email-Matthieu.Moy@imag.fr","threadId":"18826","inReplyTo":"1239900383-29628-1-git-send-email-Matthieu.Moy@imag.fr","subject":"[PATCH 2/2] Update git-add.txt according to the new possibilities of 'git add -p'.","fromName":"Matthieu Moy","fromEmail":"matthieu.moy@imag.fr","sentAt":"2009-04-16T16:46:23Z","receivedAt":"2009-04-16T16:46:23Z","isPatch":true,"sender":{"key":"git@matthieu-moy.fr","avatar":"https://avatars.githubusercontent.com/u/14709?v=4"},"body":"The text is merely cut-and-pasted from git-add--interactive.perl. The\ncut-and-paste also fixes a typo.\n\nSigned-off-by: Matthieu Moy <Matthieu.Moy@imag.fr>\n---\n Documentation/git-add.txt |    4 +++-\n 1 files changed, 3 insertions(+), 1 deletions(-)\n\ndiff --git a/Documentation/git-add.txt b/Documentation/git-add.txt\nindex 709e04b..d938b42 100644\n--- a/Documentation/git-add.txt\n+++ b/Documentation/git-add.txt\n@@ -245,9 +245,11 @@ patch::\n \n        y - stage this hunk\n        n - do not stage this hunk\n-       q - quite, do not stage this hunk nor any of the remaining ones\n+       q - quit, do not stage this hunk nor any of the remaining ones\n        a - stage this and all the remaining hunks in the file\n        d - do not stage this hunk nor any of the remaining hunks in the file\n+       g - select a hunk to go to\n+       / - search for a hunk matching the given regex\n        j - leave this hunk undecided, see next undecided hunk\n        J - leave this hunk undecided, see next hunk\n        k - leave this hunk undecided, see previous undecided hunk\n-- \n1.6.2.2.449.g92961.dirty\n"}]}