git.vger.kernel.org archive mirror
 help / color / mirror / Atom feed
* [PATCH] Introduce "reset type" flag to "git reset"
@ 2005-08-23  1:07 Junio C Hamano
  2005-08-23 20:26 ` Sam Ravnborg
  0 siblings, 1 reply; 7+ messages in thread
From: Junio C Hamano @ 2005-08-23  1:07 UTC (permalink / raw)
  To: git; +Cc: Linus Torvalds, Sam Ravnborg

I have been feeling that the current behaviour of "git reset" is
not quite optimal, but so far could not express exactly what I
felt was wrong with it.  This patch clarifies it.

There are at least two situations you may want to "reset" your
working tree.

1. You made a mess in your working tree.  You want to switch
   back to a known good state and start over.  This mess may be
   a result of your own editing, a merge that had too many
   conflicting changes that you do not feel like to resolve by
   hand at this moment, or a botched application of a patch you
   received from somewhere.

   In this case, you would want to have "git reset HEAD" reset
   the index file to the tree read from the HEAD commit and the
   files in the working tree to match index (i.e. "git status"
   should say "Nothing to commit", without any "unrecorded
   changes").

   The current behaviour leaves the files in the working tree
   intact, which requires you to run "git checkout -f".  Also
   you need to remember "rm -f" any files that the botched patch
   may have left in the working tree if the purpose of this
   "reset" is to attempt to apply it again; most likely the
   patch would fail if such a file is left behind.

2. You have discovered that commits you made earlier need to be
   reorganized.  The simplest example is to undo the last
   commit, re-edit some files, and redo the commit.  Another
   simple eample is to undo the last two commits, and commit the
   changes in those two commits as a single commit.

   In this case, you would want to have "git reset HEAD^" reset
   the $GIT_DIR/HEAD to the commit object name of the parent
   commit of the current commit (i.e. rewinding one commit),
   leave the index file and the files in the working tree in a
   state where you can easily make a commit that records a tree
   that resembles what you have in the current index file and
   the working tree.

   The current behaviour is almost OK for this purpose, except
   that you need to find which files you need to manually run
   "git add" yourself.  They are files that are in the original
   HEAD commit and not in the commit you are resetting to.

The default without the type flag is to do "--mixed", which is
the current behaviour.

    $ git reset [ --hard | --soft | --mixed ] [ <commit-ish> ]

A hard reset would be used for 1 and works in this way:

    (1) remember the set of paths that appear in the current
        index file (which may even have unmerged entries) and
	the current $GIT_DIR/HEAD commit.

    (2) "read-tree --reset" the specified <commit-ish> (default
        to HEAD), followed by "checkout-cache -f -u -a".

    (3) remove any files that appear in (1) but not in
        <commit-ish> from the working tree.

    (4) backup $GIT_DIR/HEAD to $GIT_DIR/ORIG_HEAD and update
        $GIT_DIR/HEAD with the specified <commit-ish>.

    (5) remove leftover $GIT_DIR/MERGE_HEAD

A soft reset would be used for 2 and works in this way:

    (1) Make sure that the index file is merged and we do not
        have MERGE_HEAD; otherwise it does not make sense to do
        soft reset.

    (2) backup $GIT_DIR/HEAD to $GIT_DIR/ORIG_HEAD and update
        $GIT_DIR/HEAD with the specified <commit-ish>.

Note that with the current behaviour, "git diff" is the way to
see what could be committed immediately after "git reset".  With
the "soft reset" described here you would need to say "git diff
HEAD" to find that out.

I am not sure what mixed reset (the current behaviour) is good
for.  If nobody comes up with a good use case it may not be a
bad idea to remove it.

Signed-off-by: Junio C Hamano <junkio@cox.net>

---

 git-reset-script |   96 +++++++++++++++++++++++++++++++++++++++++++++++++++---
 1 files changed, 90 insertions(+), 6 deletions(-)

c0e136c6ab8481fb4927f033bb7da105b7417207
diff --git a/git-reset-script b/git-reset-script
--- a/git-reset-script
+++ b/git-reset-script
@@ -1,13 +1,97 @@
 #!/bin/sh
 . git-sh-setup-script || die "Not a git archive"
+
+tmp=/var/tmp/reset.$$
+trap 'rm -f $tmp-*' 0 1 2 3 15
+
+reset_type=--mixed
+case "$1" in
+--mixed | --soft | --hard)
+	reset_type="$1"
+	shift
+	;;
+esac
+
 rev=$(git-rev-parse --verify --default HEAD "$@") || exit
 rev=$(git-rev-parse --verify $rev^0) || exit
-git-read-tree --reset "$rev" && {
-	if orig=$(git-rev-parse --verify HEAD 2>/dev/null)
+
+# We need to remember the set of paths that _could_ be left
+# behind before a hard reset, so that we can remove them.
+if test "$reset_type" = "--hard"
+then
+	{
+		git-ls-files --stage -z
+		git-rev-parse --verify HEAD 2>/dev/null &&
+		git-ls-tree -r -z HEAD
+	} | perl -e '
+	    use strict;
+	    my %seen;
+	    $/ = "\0";
+	    while (<>) {
+		chomp;
+		my ($info, $path) = split(/\t/, $_);
+		next if ($info =~ / tree /);
+		if (!$seen{$path}) {
+			$seen{$path} = 1;
+			print "$path\0";
+		}
+	    }
+	' >$tmp-exists
+fi
+
+# Soft reset does not touch the index file nor the working tree
+# at all, but requires them in a good order.  Other resets reset
+# the index file to the tree object we are switching to.
+if test "$reset_type" = "--soft"
+then
+	if test -f "$GIT_DIR/MERGE_HEAD" ||
+	   test "" != "$(git-ls-files --unmerged)"
 	then
-		echo "$orig" >"$GIT_DIR/ORIG_HEAD"
+		die "Cannot do a soft reset in the middle of a merge."
 	fi
-	echo "$rev" > "$GIT_DIR/HEAD"
-}
-git-update-cache --refresh
+else
+	git-read-tree --reset "$rev" || exit
+fi
+
+# Any resets update HEAD to the head being switched to.
+if orig=$(git-rev-parse --verify HEAD 2>/dev/null)
+then
+	echo "$orig" >"$GIT_DIR/ORIG_HEAD"
+else
+	rm -f "$GIT_DIR/ORIG_HEAD"
+fi
+echo "$rev" >"$GIT_DIR/HEAD"
+
+case "$reset_type" in
+--hard )
+	# Hard reset matches the working tree to that of the tree
+	# being switched to.
+	git-checkout-cache -f -u -q -a
+	git-ls-files --cached -z |
+	perl -e '
+		use strict;
+		my (%keep, $fh);
+		$/ = "\0";
+		while (<STDIN>) {
+			chomp;
+			$keep{$_} = 1;
+		}
+		open $fh, "<", $ARGV[0]
+			or die "cannot open $ARGV[0]";
+		while (<$fh>) {
+			chomp;
+			if (! exists $keep{$_}) {
+				print "$_\0";
+			}
+		}
+	' $tmp-exists | xargs -0 rm -v -f --
+	;;
+--soft )
+	;; # Nothing else to do
+--mixed )
+	# Report what has not been updated.
+	git-update-cache --refresh
+	;;
+esac
+
 rm -f "$GIT_DIR/MERGE_HEAD"

^ permalink raw reply	[flat|nested] 7+ messages in thread

* Re: [PATCH] Introduce "reset type" flag to "git reset"
  2005-08-23  1:07 [PATCH] Introduce "reset type" flag to "git reset" Junio C Hamano
@ 2005-08-23 20:26 ` Sam Ravnborg
  2005-08-23 22:08   ` Junio C Hamano
  0 siblings, 1 reply; 7+ messages in thread
From: Sam Ravnborg @ 2005-08-23 20:26 UTC (permalink / raw)
  To: Junio C Hamano; +Cc: git, Linus Torvalds

> I am not sure what mixed reset (the current behaviour) is good
> for.  If nobody comes up with a good use case it may not be a
> bad idea to remove it.
Using the principle of minimum suprise the --mixed should be removed.
--soft - undo the commit leaving all changes.
--hard - undo the commit and removing all changes

I'm a cogito user so not used to got options.
But --soft, --hard looks rather confusing to me.

Something like --force or --prune may be a bit more intuitive, and let
default behaviour be the one you name --soft for now.

I think it would make sense to be able to specify the topmost SHA1 (or 
HEAD:5 or HEAD^^^^^) from where the reset should start.

	Sam

^ permalink raw reply	[flat|nested] 7+ messages in thread

* Re: [PATCH] Introduce "reset type" flag to "git reset"
  2005-08-23 20:26 ` Sam Ravnborg
@ 2005-08-23 22:08   ` Junio C Hamano
  2005-08-24  0:13     ` Yasushi SHOJI
  2005-08-24 18:35     ` Junio C Hamano
  0 siblings, 2 replies; 7+ messages in thread
From: Junio C Hamano @ 2005-08-23 22:08 UTC (permalink / raw)
  To: Sam Ravnborg; +Cc: git, Linus Torvalds

Sam Ravnborg <sam@ravnborg.org> writes:

> But --soft, --hard looks rather confusing to me.
>
> Something like --force or --prune may be a bit more intuitive, and let
> default behaviour be the one you name --soft for now.

I do not have objections to removing --mixed, but I do not find
--force/--prune any less confusing than --soft/--hard.  Its just
a terminology so once people get used to it anything would do.
But I agree that we need to come up with a good name for them.
I do not think --force/--prune is it, though.

> I think it would make sense to be able to specify the topmost SHA1 (or 
> HEAD:5 or HEAD^^^^^) from where the reset should start.

"git reset --hard HEAD~5" should work.  Sorry, the colon ":"
turns out to be confusing to refspec notation <src>:<dst> used
in fetch/push and was replaced with a tilde "~" some time ago.

^ permalink raw reply	[flat|nested] 7+ messages in thread

* Re: [PATCH] Introduce "reset type" flag to "git reset"
  2005-08-23 22:08   ` Junio C Hamano
@ 2005-08-24  0:13     ` Yasushi SHOJI
  2005-08-24  0:22       ` Junio C Hamano
  2005-08-24 18:35     ` Junio C Hamano
  1 sibling, 1 reply; 7+ messages in thread
From: Yasushi SHOJI @ 2005-08-24  0:13 UTC (permalink / raw)
  To: Junio C Hamano; +Cc: Sam Ravnborg, git, Linus Torvalds

At Tue, 23 Aug 2005 15:08:44 -0700,
Junio C Hamano wrote:
> 
> Sam Ravnborg <sam@ravnborg.org> writes:
> 
> > But --soft, --hard looks rather confusing to me.
> >
> > Something like --force or --prune may be a bit more intuitive, and let
> > default behaviour be the one you name --soft for now.
> 
> I do not have objections to removing --mixed, but I do not find
> --force/--prune any less confusing than --soft/--hard.  Its just
> a terminology so once people get used to it anything would do.
> But I agree that we need to come up with a good name for them.
> I do not think --force/--prune is it, though.

I think the point is "what is the target?".

I believe "git reset" is targeting at the index file and only the
index file and nothing more. it's that simple.

what we want instead is a command to sync/reset/revert both index and
tree to know working point.  so this isn't core plumbing but as a user
of git, i'm sure it's very handy to have it.

--soft one is simple to think, so i'm starting with this one. let's
assume that, as you described in the original post, this one is
intended to be used to rework on the work _you_ have before.  that
means that _you_ know exactly what you are doing.

there might be a case, and this happned to me quite some time when I
was working with quilt, which you don't want to automatically add all
the files you added on the privious commit. ie. moving defines from
header to .c, splitting a work to two commits.

so in this case, it's ideal to just use "git reset" if the command
lists files removed from the index.

for --hard option, what you want to do is to completely revert the
current state of your index file and work tree to known point.

for that, how about git-revert-script?  can we add --force option to
that command so that even if your working tree is dirty it reverts to
the specified point?
--
          yashi

^ permalink raw reply	[flat|nested] 7+ messages in thread

* Re: [PATCH] Introduce "reset type" flag to "git reset"
  2005-08-24  0:13     ` Yasushi SHOJI
@ 2005-08-24  0:22       ` Junio C Hamano
  2005-08-24  0:41         ` Yasushi SHOJI
  0 siblings, 1 reply; 7+ messages in thread
From: Junio C Hamano @ 2005-08-24  0:22 UTC (permalink / raw)
  To: Yasushi SHOJI; +Cc: Sam Ravnborg, git, Linus Torvalds

Yasushi SHOJI <yashi@atmark-techno.com> writes:

> for --hard option, what you want to do is to completely revert the
> current state of your index file and work tree to known point.
>
> for that, how about git-revert-script?

"git revert" is to create a commit that reverts a previous
commit, which I think is quite different from what we have been
discussing so far.

^ permalink raw reply	[flat|nested] 7+ messages in thread

* Re: [PATCH] Introduce "reset type" flag to "git reset"
  2005-08-24  0:22       ` Junio C Hamano
@ 2005-08-24  0:41         ` Yasushi SHOJI
  0 siblings, 0 replies; 7+ messages in thread
From: Yasushi SHOJI @ 2005-08-24  0:41 UTC (permalink / raw)
  To: Junio C Hamano; +Cc: Sam Ravnborg, git, Linus Torvalds

At Tue, 23 Aug 2005 17:22:47 -0700,
Junio C Hamano wrote:
> 
> Yasushi SHOJI <yashi@atmark-techno.com> writes:
> 
> > for --hard option, what you want to do is to completely revert the
> > current state of your index file and work tree to known point.
> >
> > for that, how about git-revert-script?
> 
> "git revert" is to create a commit that reverts a previous
> commit, which I think is quite different from what we have been
> discussing so far.

ah, ok.  I was gonna suggest git-revert-script for the name but quick
check showed me that we already have that script. so I just thought it
does the thing.
--
         yashi

^ permalink raw reply	[flat|nested] 7+ messages in thread

* Re: [PATCH] Introduce "reset type" flag to "git reset"
  2005-08-23 22:08   ` Junio C Hamano
  2005-08-24  0:13     ` Yasushi SHOJI
@ 2005-08-24 18:35     ` Junio C Hamano
  1 sibling, 0 replies; 7+ messages in thread
From: Junio C Hamano @ 2005-08-24 18:35 UTC (permalink / raw)
  To: Sam Ravnborg; +Cc: git, Linus Torvalds

Junio C Hamano <junkio@cox.net> writes:

> Sam Ravnborg <sam@ravnborg.org> writes:
>
>> But --soft, --hard looks rather confusing to me.
>>
>> Something like --force or --prune may be a bit more intuitive, and let
>> default behaviour be the one you name --soft for now.
>
> I do not have objections to removing --mixed, but I do not find
> --force/--prune any less confusing than --soft/--hard.  Its just
> a terminology so once people get used to it anything would do.
> But I agree that we need to come up with a good name for them.
> I do not think --force/--prune is it, though.

Names aside, I have a feeling that "git reset --hard HEAD" is
what "git checkout -f HEAD" should have done.  As it stands, the
latter leaves files not in HEAD but in the previous tree behind.

Comments?

^ permalink raw reply	[flat|nested] 7+ messages in thread

end of thread, other threads:[~2005-08-24 18:36 UTC | newest]

Thread overview: 7+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2005-08-23  1:07 [PATCH] Introduce "reset type" flag to "git reset" Junio C Hamano
2005-08-23 20:26 ` Sam Ravnborg
2005-08-23 22:08   ` Junio C Hamano
2005-08-24  0:13     ` Yasushi SHOJI
2005-08-24  0:22       ` Junio C Hamano
2005-08-24  0:41         ` Yasushi SHOJI
2005-08-24 18:35     ` Junio C Hamano

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).