From: Pierre Habouzit <hidden> Date: 2016-06-15 22:47:05
One of my most frequent use case for git-add -p is when I had an intense
debug session with quite a lot of debug() traces added. I then want only
to select the hunks corresponding to the bugfixes and throw away the debug
ones.
With this new operation, instead of not staging hunks I don't want and
will eventually undo, I can just undo them.
Signed-off-by: Pierre Habouzit <redacted>
---
I reckon this is a tad late given we're already at -rc2, but that's
an itch that has scratched me for quite some time already, and I had
to scratch it today...
the change looks pretty safe to me though.
The only think that looks odd in the patch is the removal of the
if ($_->{USE}) clause from the TEXT copying loops, but
coalesce_overlapping_hunks already ensures that only ->{USE}d hunks
remain. I just have modified it to deal with ->{UNDO}ed hunks the
same way.
Documentation/git-add.txt | 1 +
git-add--interactive.perl | 38 ++++++++++++++++++++++++++++++--------
2 files changed, 31 insertions(+), 8 deletions(-)
@@ -254,6 +254,7 @@ patch:: y - stage this hunk n - do not stage this hunk+ u - do not stage this hunk and revert it q - quit, do not stage this hunk nor any of the remaining ones a - stage this and all the remaining hunks in the file d - do not stage this hunk nor any of the remaining hunks in the file
From: Thomas Rast <hidden> Date: 2016-06-15 22:47:05
Pierre Habouzit wrote:
One of my most frequent use case for git-add -p is when I had an intense
debug session with quite a lot of debug() traces added. I then want only
to select the hunks corresponding to the bugfixes and throw away the debug
ones.
With this new operation, instead of not staging hunks I don't want and
will eventually undo, I can just undo them.
This is what 'git checkout --interactive -- $file' or 'git reset
--interactive --hard' would accomplish, if they existed. I wonder if
there would be a way to avoid yet more command letters, and instead
have "modes" that affect what happens with hunks you said 'y' to. For
example:
add -p apply --cached
undo -p apply -R
unstage -p apply -R --cached
[with hunks coming from diff --cached obviously]
(I picked 'undo' and 'unstage' semi-randomly, but it's not, after all,
an 'add' operation any more and the user doesn't need to know that the
program doing this is in fact git-add--interactive.)
+ u - do not stage this hunk and revert it
you're overloading terminology a bit too much for my taste. It has
nothing to do with what git-revert does, and we shouldn't confuse
people more about that.
@@ -693,6 +693,7 @@ sub split_hunk { ADDDEL => 0, POSTCTX => 0, USE => undef,+ UNDO => undef, };
Why not fold this into a single field? It could, say, take values 0,
1, or '-R'. It could probably be renamed to ACTION, but USE would be
fine if you want to avoid the code churn. Then you shouldn't need
_completely_ separate handling during application.
+ $hunk[$ix]{UNDO} = 0;
and similarly for [yad] too, on the grounds that the user can go back
and change his choices with [KJ]. Of course that is not necessary if
you go the ACTION way outlined above.
+ if (@undo) {
+ my $fh;
+
+ open $fh, '| git apply -R';
This probably needs a --recount to cope with the case where the hunk
headers became stale/invalid through user [e]diting.
From: Pierre Habouzit <hidden> Date: 2016-06-15 22:47:05
On Thu, Jul 23, 2009 at 10:41:31AM +0200, Thomas Rast wrote:
Pierre Habouzit wrote:
quoted
One of my most frequent use case for git-add -p is when I had an intense
debug session with quite a lot of debug() traces added. I then want only
to select the hunks corresponding to the bugfixes and throw away the debug
ones.
With this new operation, instead of not staging hunks I don't want and
will eventually undo, I can just undo them.
This is what 'git checkout --interactive -- $file' or 'git reset
--interactive --hard' would accomplish, if they existed. I wonder if
there would be a way to avoid yet more command letters, and instead
have "modes" that affect what happens with hunks you said 'y' to. For
example:
add -p apply --cached
undo -p apply -R
unstage -p apply -R --cached
[with hunks coming from diff --cached obviously]
(I picked 'undo' and 'unstage' semi-randomly, but it's not, after all,
an 'add' operation any more and the user doesn't need to know that the
program doing this is in fact git-add--interactive.)
The point is I want to do them at once, see my use case: I want to stage
the hunks from my bugfix, and remove the debugging bits of it at the
same time, I don't want to run two commands.
I see git add -p as a triaging command, giving me the choice to do the
three things you can do with a hunk:
- stage it now (y)
- stage it later (n)
- never stage it, it was intermediate code, debug, whatever (u).
quoted
+ u - do not stage this hunk and revert it
you're overloading terminology a bit too much for my taste. It has
nothing to do with what git-revert does, and we shouldn't confuse
people more about that.
Right, revert is probably too overloaded, let it be "forget" or "drop"
instead if you want, I don't care much.
@@ -693,6 +693,7 @@ sub split_hunk { ADDDEL => 0, POSTCTX => 0, USE => undef,+ UNDO => undef, };
Why not fold this into a single field? It could, say, take values 0,
1, or '-R'. It could probably be renamed to ACTION, but USE would be
fine if you want to avoid the code churn. Then you shouldn't need
_completely_ separate handling during application.
+ $hunk[$ix]{UNDO} = 0;
and similarly for [yad] too, on the grounds that the user can go back
and change his choices with [KJ]. Of course that is not necessary if
you go the ACTION way outlined above.
I hesitated to do so, but yes it makes perfect sense.
quoted
+ if (@undo) {
+ my $fh;
+
+ open $fh, '| git apply -R';
This probably needs a --recount to cope with the case where the hunk
headers became stale/invalid through user [e]diting.
From: Thomas Rast <hidden> Date: 2016-06-15 22:47:05
This is just the required change to git-add--interactive. Since the
use of this script is an implementation detail, the next step would be
to wrap this option in other commands such as 'git reset --patch' and
'git unstage --patch'.
Since there is no frontend support whatsoever, you have to run
git add--interactive --patch=unstage --
manually (including the --), and similarly for --patch=reset.
---
I wrote:
This is what 'git checkout --interactive -- $file' or 'git reset
--interactive --hard' would accomplish, if they existed. I wonder if
there would be a way to avoid yet more command letters, and instead
have "modes" that affect what happens with hunks you said 'y' to. For
example:
add -p apply --cached
undo -p apply -R
unstage -p apply -R --cached
[with hunks coming from diff --cached obviously]
(I picked 'undo' and 'unstage' semi-randomly, but it's not, after all,
an 'add' operation any more and the user doesn't need to know that the
program doing this is in fact git-add--interactive.)
Like so, maybe. I realise that it does _not_ fill Pierre's need for a
command that can do it all in one go, but if people like this I'll
make a real patch series.
I'm not completely happy with the idea of reset --interactive by the
way, as it's not a reset in the 'reset $commit' sense.
git-add--interactive.perl | 60 +++++++++++++++++++++++++++++++++-----------
1 files changed, 45 insertions(+), 15 deletions(-)
@@ -877,6 +899,7 @@ordie"failed to open hunk edit file for writing: ".$!;print$fh"# Manual hunk edit mode -- see bottom for a quick guide\n";print$fh@$oldtext;+my$participle=$patch_modes{$patch_mode}{PARTICIPLE};print$fh<<EOF;# ---# To remove '-' lines, make them ' ' lines (context).
@@ -884,7 +907,7 @@# Lines starting with # will be removed.## If the patch applies cleanly, the edited hunk will immediately be-# marked for staging. If it does not apply cleanly, you will be given+# marked for $participle. If it does not apply cleanly, you will be given# an opportunity to edit again. If all lines of the hunk are removed,# then the edit is aborted and the hunk is left unchanged.EOF
From: Thomas Rast <hidden> Date: 2016-06-15 22:47:05
The new command 'git unstage' is the precise opposite of 'git stage'
(i.e., git-add). As such, it is the same as 'git reset --' unless the
current branch is unborn.
Signed-off-by: Thomas Rast <redacted>
---
So I decided I had wished for these frequently enough to actually
implement them. I ran out of time before getting to the tests, but
the rest should be there.
v1 had a bug where it would not correctly detect the changed files,
this is fixed in the new patch (now 3/3).
Documentation/git-unstage.txt | 26 ++++++++++++++++++++++++++
Makefile | 1 +
git-unstage.sh | 26 ++++++++++++++++++++++++++
wt-status.c | 6 +-----
4 files changed, 54 insertions(+), 5 deletions(-)
create mode 100644 Documentation/git-unstage.txt
create mode 100644 git-unstage.sh
@@ -0,0 +1,26 @@+git-unstage(1)+==============++NAME+----+git-unstage - Remove changes to a file from the staging area+++SYNOPSIS+--------+[verse]+'git unstage' <paths> ...+++DESCRIPTION+-----------++Overwrites the staged changes to the 'paths' with the values from+HEAD, so that they are not included in the next commit. The worktree+is not affected. (This is the same as `git reset \-- <paths>` unless+you are on an unborn branch.)+++SEE ALSO+--------+linkgit:git-reset[1]
@@ -0,0 +1,26 @@+#!/bin/sh++SUBDIRECTORY_OK=Yes+OPTIONS_KEEPDASHDASH=+OPTIONS_SPEC="\+gitunstagefile...+--"++.git-sh-setup+++case"$1"in+--)+if[$#-eq1];then+die"You must specify at least one file to unstage"+fi+ifgitrev-parse-q--verifyHEAD>/dev/null;then+execgitreset"$@"+else+execgitrm--cached"$@"+fi+;;+*)+usage+;;+esac
@@ -0,0 +1,29 @@+git-discard(1)+==============++NAME+----+git-discard - Remove changes to a file from the worktree+++SYNOPSIS+--------+[verse]+'git discard' <paths> ...+++DESCRIPTION+-----------++Overwrites your edits to the 'paths' with the values from the staging+area, effectively throwing them away entirely.++*WARNING:* All unstaged changes to the 'paths' are *irreversibly*+lost.++(This is the same as `git checkout \-- <paths>`.)+++SEE ALSO+--------+linkgit:git-checkout[1]
@@ -0,0 +1,22 @@+#!/bin/sh++SUBDIRECTORY_OK=Yes+OPTIONS_KEEPDASHDASH=+OPTIONS_SPEC="\+gitdiscardfile...+--"++.git-sh-setup+++case"$1"in+--)+if[$#-eq1];then+die"You must specify at least one file to discard changes from"+fi+execgitcheckout"$@"+;;+*)+usage+;;+esac
@@ -75,7 +75,7 @@ static void wt_status_print_dirty_header(struct wt_status *s,color_fprintf_ln(s->fp,c,"# (use \"git add <file>...\" to update what will be committed)");elsecolor_fprintf_ln(s->fp,c,"# (use \"git add/rm <file>...\" to update what will be committed)");-color_fprintf_ln(s->fp,c,"# (use \"git checkout -- <file>...\" to discard changes in working directory)");+color_fprintf_ln(s->fp,c,"# (use \"git discard <file>...\" to discard changes in working directory)");color_fprintf_ln(s->fp,c,"#");}
From: Thomas Rast <hidden> Date: 2016-06-15 22:47:05
This implements a new optional argument --patch=<mode> in the
git-add--interactive helper. The modes are:
'stage' (default, as before): offer hunks from 'git diff' and stage
the ones selected by the user.
'unstage': offer hunks from 'git diff --cached', and unstage the ones
selected.
'discard': offer hunks from 'git diff', and discard (i.e., undo the
edit in the working tree) the ones selected.
With this in hand, we can then easily add a --patch option to the
git-unstage and git-discard scripts that run git-add--interactive in
the corresponding modes.
Signed-off-by: Thomas Rast <redacted>
---
Documentation/git-discard.txt | 7 ++++
Documentation/git-unstage.txt | 7 ++++
git-add--interactive.perl | 69 +++++++++++++++++++++++++++++++---------
git-discard.sh | 9 ++++-
git-unstage.sh | 9 ++++-
5 files changed, 81 insertions(+), 20 deletions(-)
@@ -24,6 +24,13 @@ lost. (This is the same as `git checkout \-- <paths>`.)+OPTIONS+-------+-p::+--patch::+ Interactively select hunks to discard.++ SEE ALSO -------- linkgit:git-checkout[1]
@@ -21,6 +21,13 @@ is not affected. (This is the same as `git reset \-- <paths>` unless you are on an unborn branch.)+OPTIONS+-------+-p::+--patch::+ Interactively select hunks to unstage.++ SEE ALSO -------- linkgit:git-reset[1]
@@ -877,6 +902,7 @@ordie"failed to open hunk edit file for writing: ".$!;print$fh"# Manual hunk edit mode -- see bottom for a quick guide\n";print$fh@$oldtext;+my$participle=$patch_modes{$patch_mode}{PARTICIPLE};print$fh<<EOF;# ---# To remove '-' lines, make them ' ' lines (context).
@@ -884,7 +910,7 @@# Lines starting with # will be removed.## If the patch applies cleanly, the edited hunk will immediately be-# marked for staging. If it does not apply cleanly, you will be given+# marked for $participle. If it does not apply cleanly, you will be given# an opportunity to edit again. If all lines of the hunk are removed,# then the edit is aborted and the hunk is left unchanged.EOF
@@ -3,13 +3,18 @@SUBDIRECTORY_OK=YesOPTIONS_KEEPDASHDASH=OPTIONS_SPEC="\-gitdiscardfile...---"+gitdiscard[-p]file...+--+p,patchinteractivelyselecthunkstodiscard" .git-sh-setupcase"$1"in+-p|--patch)+shift+execgitadd--interactive--patch=discard"$@"+;;--)if[$#-eq1];thendie"You must specify at least one file to discard changes from"
@@ -3,13 +3,18 @@SUBDIRECTORY_OK=YesOPTIONS_KEEPDASHDASH=OPTIONS_SPEC="\-gitunstagefile...---"+gitunstage[-p]file...+--+p,patchinteractivelyselecthunkstounstage" .git-sh-setupcase"$1"in+-p|--patch)+shift+execgitadd--interactive--patch=unstage"$@"+;;--)if[$#-eq1];thendie"You must specify at least one file to unstage"
On Fri, Jul 24, 2009 at 6:24 PM, Thomas Rast[off-list ref] wrote:
This implements a new optional argument --patch=<mode> in the
git-add--interactive helper. The modes are:
'stage' (default, as before): offer hunks from 'git diff' and stage
the ones selected by the user.
'unstage': offer hunks from 'git diff --cached', and unstage the ones
selected.
'discard': offer hunks from 'git diff', and discard (i.e., undo the
edit in the working tree) the ones selected.
With this in hand, we can then easily add a --patch option to the
git-unstage and git-discard scripts that run git-add--interactive in
the corresponding modes.
While I do not really think even more git commands are so helpful, I
like the proposed command names, and I really like that it would be
possible to remove single hunks from the index. I have come to rely
very much on git add -p to make self-contained and clear commits and
think it would be a great feature if I could use this the other way
round too.
Thanks,
Matthias
On Fri, Jul 24, 2009 at 10:24 AM, Thomas Rast[off-list ref] wrote:
The new command 'git unstage' is the precise opposite of 'git stage'
(i.e., git-add). As such, it is the same as 'git reset --' unless the
current branch is unborn.
I really, really like the idea of being able to do something like
unstage -p. That's sweet, thanks for working on that.
Some potential issues, though:
git unstage may cause issues for some people if they try to use it
when in the middle of a merge (why reset back to HEAD rather than one
of the other branches being merged?). With git reset, one can specify
which commit to reset the index back to. With your 'unstage' command,
you not only assume 'HEAD' but don't allow specifying any other value.
You could add a commit argument here, but that may be problematic
wording-wise, in that you're allowing to 'unstage' back to a specified
commit, with the possibly perplexing result that you have 'staged'
something else.
Also, you have added two new commands, unstage and discard, which are
two pieces of an hg-like revert (revert edits). We still don't have a
command for a full hg-like revert, though (git checkout does not cover
the bases), and to cover that we'd have to add a third command.
Perhaps the three could be combined?
Elijah
On Fri, Jul 24, 2009 at 12:12 PM, Bert Wesarg[off-list ref] wrote:
You fall into the same trap as me for patch 1/3. He does not shift
away the '--', so it is still in "$@".
Indeed; I somehow missed that '--' was silently added by git. I guess
that's what I get for shooting off my mouth without actually trying
it. Sorry for the noise.
From: Pierre Habouzit <hidden> Date: 2016-06-15 22:47:06
On Fri, Jul 24, 2009 at 06:24:35PM +0200, Thomas Rast wrote:
+*WARNING:* All unstaged changes to the 'paths' are *irreversibly*
+lost.
FWIW, as git checkout -- <path> is already doing that, and that
git-discard is clearly something meant as some UI sugar, I would make
that operation a "safe" porcelain by puting the discarded hunks in a
stash.
I'm shamelessly stealing this idea from Jeff, but it's probably an
excellent idea to have a strash¹. It makes git even safer to use,
especially to beginners, to whom we would talk about git-discard instead
of git checkout.
¹: stash-trash
--
Intersec <http://www.intersec.com>
Pierre Habouzit [off-list ref]
Tél : +33 (0)1 5570 3346
Mob : +33 (0)6 1636 8131
Fax : +33 (0)1 5570 3332
37 Rue Pierre Lhomme
92400 Courbevoie