Introduce "reset type" flag to "git reset"

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>
1 file changed
tree: 530289ed5c283a41d6596cc13f0cee35e7f4c336
  1. debian/
  2. Documentation/
  3. mozilla-sha1/
  4. ppc/
  5. t/
  6. templates/
  7. tools/
  8. apply.c
  9. blob.c
  10. blob.h
  11. build-rev-cache.c
  12. cache.h
  13. cat-file.c
  14. checkout-cache.c
  15. clone-pack.c
  16. commit-tree.c
  17. commit.c
  18. commit.h
  19. connect.c
  20. convert-cache.c
  21. COPYING
  22. count-delta.c
  23. count-delta.h
  24. csum-file.c
  25. csum-file.h
  26. daemon.c
  27. date.c
  28. delta.h
  29. diff-cache.c
  30. diff-delta.c
  31. diff-files.c
  32. diff-helper.c
  33. diff-stages.c
  34. diff-tree.c
  35. diff.c
  36. diff.h
  37. diffcore-break.c
  38. diffcore-order.c
  39. diffcore-pathspec.c
  40. diffcore-pickaxe.c
  41. diffcore-rename.c
  42. diffcore.h
  43. entry.c
  44. epoch.c
  45. epoch.h
  46. export.c
  47. fetch-pack.c
  48. fsck-cache.c
  49. get-tar-commit-id.c
  50. git
  51. git-add-script
  52. git-apply-patch-script
  53. git-bisect-script
  54. git-branch-script
  55. git-checkout-script
  56. git-cherry
  57. git-clone-dumb-http
  58. git-clone-script
  59. git-commit-script
  60. git-core.spec.in
  61. git-count-objects-script
  62. git-cvsimport-script
  63. git-diff-script
  64. git-external-diff-script
  65. git-fetch-script
  66. git-format-patch-script
  67. git-log-script
  68. git-ls-remote-script
  69. git-merge-one-file-script
  70. git-parse-remote
  71. git-prune-script
  72. git-pull-script
  73. git-push-script
  74. git-rebase-script
  75. git-relink-script
  76. git-rename-script
  77. git-repack-script
  78. git-request-pull-script
  79. git-reset-script
  80. git-resolve-script
  81. git-revert-script
  82. git-send-email-script
  83. git-sh-setup-script
  84. git-shortlog
  85. git-status-script
  86. git-tag-script
  87. git-verify-tag-script
  88. git-whatchanged
  89. gitenv.c
  90. gitk
  91. hash-object.c
  92. http-pull.c
  93. ident.c
  94. index.c
  95. init-db.c
  96. INSTALL
  97. local-pull.c
  98. ls-files.c
  99. ls-tree.c
  100. Makefile
  101. merge-base.c
  102. merge-cache.c
  103. mktag.c
  104. object.c
  105. object.h
  106. pack-check.c
  107. pack-objects.c
  108. pack.h
  109. patch-delta.c
  110. patch-id.c
  111. path.c
  112. peek-remote.c
  113. pkt-line.c
  114. pkt-line.h
  115. prune-packed.c
  116. pull.c
  117. pull.h
  118. quote.c
  119. quote.h
  120. read-cache.c
  121. read-tree.c
  122. README
  123. receive-pack.c
  124. refs.c
  125. refs.h
  126. rev-cache.c
  127. rev-cache.h
  128. rev-list.c
  129. rev-parse.c
  130. rev-tree.c
  131. rsh.c
  132. rsh.h
  133. run-command.c
  134. run-command.h
  135. send-pack.c
  136. server-info.c
  137. setup.c
  138. sha1_file.c
  139. sha1_name.c
  140. show-branch.c
  141. show-index.c
  142. show-rev-cache.c
  143. ssh-pull.c
  144. ssh-push.c
  145. strbuf.c
  146. strbuf.h
  147. stripspace.c
  148. tag.c
  149. tag.h
  150. tar-tree.c
  151. test-date.c
  152. test-delta.c
  153. tree.c
  154. tree.h
  155. unpack-file.c
  156. unpack-objects.c
  157. update-cache.c
  158. update-server-info.c
  159. upload-pack.c
  160. usage.c
  161. var.c
  162. verify-pack.c
  163. write-tree.c