Re: RFE: Discard hunks during `git add -p`

2016-11-02 Thread Jeff King
On Wed, Nov 02, 2016 at 06:11:14PM -0400, Jeff King wrote:

> > Being able to discard hunks (reset working copy to index contents) 
> > during add-p would alleviate the (quite broad) hard reset.
> 
> As Konstantin pointed out, you can already discard interactively with
> "git checkout -p". It might be nice to be able to do both in the same
> run, and turn the "yes/no" decision into "yes/no/discard".
> 
> In theory it should be easy, as the same code drives the hunk selector
> for both commands. It's just a matter of which command we feed the
> selected hunks to. I don't know if there would be corner cases around
> hunk-editing and splitting, though. The "add" phase should never touch
> the working tree file itself, so any hunks present from the initial list
> should still apply cleanly during the "discard" phase.

The patch is something like the one below, which worked for me in a very
trivial test. I won't be surprised if there are some corner cases it's
missing. At the very least, coalesce_overlapping_hunks() needs to learn
about the differences between "apply" and "discard" hunks (and not
coalesce them!).

I don't have immediate plans for this, so if somebody wants to pick it
up and run with it, be my guest.

-Peff

diff --git a/git-add--interactive.perl b/git-add--interactive.perl
index ee3d81269..43651435a 100755
--- a/git-add--interactive.perl
+++ b/git-add--interactive.perl
@@ -109,6 +109,7 @@ my %patch_modes = (
PARTICIPLE => 'staging',
FILTER => 'file-only',
IS_REVERSE => 0,
+   DISCARD => sub { apply_patch 'apply -R', @_; },
},
'stash' => {
DIFF => 'diff-index -p HEAD',
@@ -1325,6 +1326,11 @@ sub patch_update_file {
my ($prev, $next, $other, $undecided, $i);
$other = '';
 
+   my $discard = exists $patch_mode_flavour{DISCARD};
+   if ($discard) {
+   $other .= ',D';
+   }
+
if ($num <= $ix) {
$ix = 0;
}
@@ -1384,6 +1390,9 @@ sub patch_update_file {
elsif ($line =~ /^n/i) {
$hunk[$ix]{USE} = 0;
}
+   elsif ($discard && $line =~ /^D/) {
+   $hunk[$ix]{USE} = -1;
+   }
elsif ($line =~ /^a/i) {
while ($ix < $num) {
if (!defined $hunk[$ix]{USE}) {
@@ -1539,9 +1548,12 @@ sub patch_update_file {
 
my $n_lofs = 0;
my @result = ();
+   my @discard = ();
for (@hunk) {
-   if ($_->{USE}) {
+   if ($_->{USE} > 0) {
push @result, @{$_->{TEXT}};
+   } elsif ($_->{USE} < 0) {
+   push @discard, @{$_->{TEXT}};
}
}
 
@@ -1552,6 +1564,13 @@ sub patch_update_file {
refresh();
}
 
+   if (@discard) {
+   my @patch = reassemble_patch($head->{TEXT}, @discard);
+   my $apply_routine = $patch_mode_flavour{DISCARD};
+   &$apply_routine(@patch);
+   refresh();
+   }
+
print "\n";
return $quit;
 }


Re: RFE: Discard hunks during `git add -p`

2016-11-02 Thread Jeff King
On Wed, Nov 02, 2016 at 02:46:04PM +0100, Jan Engelhardt wrote:

> Current version: 2.10.2
> Example workflow:
> 
> * I would do a global substitution across a source tree, e.g. `perl -i 
>   -pe 's{OLD_FOO\(x\)}{NEW_BAR(x, 0)}' *.c`
> * Using `git add -p`, I would verify each of the substitutions that they 
>   make sense in their respective locations, and, based on that,
>   answer "y" or "n" to the interactive prompting to stage good hunks.
> * When done with add-p, I would commit the so-staged hunks,
>   and then use `git reset --hard` to discard all changes that were 
>   not acknowledged during add-p.
> 
> Being able to discard hunks (reset working copy to index contents) 
> during add-p would alleviate the (quite broad) hard reset.

As Konstantin pointed out, you can already discard interactively with
"git checkout -p". It might be nice to be able to do both in the same
run, and turn the "yes/no" decision into "yes/no/discard".

In theory it should be easy, as the same code drives the hunk selector
for both commands. It's just a matter of which command we feed the
selected hunks to. I don't know if there would be corner cases around
hunk-editing and splitting, though. The "add" phase should never touch
the working tree file itself, so any hunks present from the initial list
should still apply cleanly during the "discard" phase.

-Peff


Re: RFE: Discard hunks during `git add -p`

2016-11-02 Thread Konstantin Khomoutov
On Wed, 2 Nov 2016 14:46:04 +0100 (CET)
Jan Engelhardt  wrote:

> Current version: 2.10.2
> Example workflow:
> 
> * I would do a global substitution across a source tree, e.g. `perl
> -i -pe 's{OLD_FOO\(x\)}{NEW_BAR(x, 0)}' *.c`
> * Using `git add -p`, I would verify each of the substitutions that
> they make sense in their respective locations, and, based on that,
>   answer "y" or "n" to the interactive prompting to stage good hunks.
> * When done with add-p, I would commit the so-staged hunks,
>   and then use `git reset --hard` to discard all changes that were 
>   not acknowledged during add-p.
> 
> Being able to discard hunks (reset working copy to index contents) 
> during add-p would alleviate the (quite broad) hard reset.

Couldn't you just do

  git checkout -- .

after staging your approved changes?

To selectively zap uncommitted changes from your working tree, you could
do

  git checkout --patch -- .


I'm not sure overloading `git add` with a "reverse" action is a good
idea.  I'm actually prefer pragmatism over conceptual purity but I'm
not sure the prospective gain here is clear.


RFE: Discard hunks during `git add -p`

2016-11-02 Thread Jan Engelhardt

Current version: 2.10.2
Example workflow:

* I would do a global substitution across a source tree, e.g. `perl -i 
  -pe 's{OLD_FOO\(x\)}{NEW_BAR(x, 0)}' *.c`
* Using `git add -p`, I would verify each of the substitutions that they 
  make sense in their respective locations, and, based on that,
  answer "y" or "n" to the interactive prompting to stage good hunks.
* When done with add-p, I would commit the so-staged hunks,
  and then use `git reset --hard` to discard all changes that were 
  not acknowledged during add-p.

Being able to discard hunks (reset working copy to index contents) 
during add-p would alleviate the (quite broad) hard reset.

Similar approach:

* global substitution
* Using `git add -p`, some hunks may warrant some more editing, doable 
  with the "e" command. The index would be updated with the extra
  change, but the working copy be left as-is.
* When rerunning `git add -p` in such a state, a difference is shown 
  again for such edited spots, which I would like to discard (bring 
  the working copy into sync with index).