{"thread":{"id":"22080","subject":"[RFC/PATCH 0/5] add \"--keep\" option to \"git reset\"","startedAt":"2010-01-02T05:39:28Z","lastAt":"2010-01-19T04:28:54Z","messageCount":12,"participants":["Christian Couder","Andreas Schwab","Daniel Convissor","Junio C Hamano"],"isPatch":true,"patchVersion":1,"patchTotal":5},"messages":[{"id":"130673","messageId":"20100102053303.30066.26391.chriscool@tuxfamily.org","threadId":"22080","inReplyTo":null,"subject":"[RFC/PATCH 0/5] add \"--keep\" option to \"git reset\"","fromName":"Christian Couder","fromEmail":"chriscool@tuxfamily.org","sentAt":"2010-01-02T05:39:28Z","receivedAt":"2010-01-02T05:39:28Z","isPatch":true,"sender":{"key":"christian.couder@gmail.com","avatar":"https://avatars.githubusercontent.com/u/208954?v=4"},"body":"This patch series is sent to make it easy to test the changes in the\nfirst patch by Junio of this series on a new \"--keep\" reset option.  \n\nChristian Couder (4):\n  reset: add option \"--keep\" to \"git reset\"\n  reset: add test cases for \"--keep\" option\n  Documentation: reset: describe new \"--keep\" option\n  reset: disallow \"reset --keep\" outside a work tree\n\nJunio C Hamano (1):\n  reset: make \"reset --merge\" discard work tree changes on unmerged\n    entries\n\n Documentation/git-reset.txt |   45 ++++++++++++++--\n builtin-reset.c             |   31 +++++++++--\n read-cache.c                |    2 +-\n t/t7103-reset-bare.sh       |   25 ++++++---\n t/t7110-reset-merge.sh      |  119 ++++++++++++++++++++++++++++++++++++++++---\n unpack-trees.c              |   19 ++++---\n 6 files changed, 206 insertions(+), 35 deletions(-)\n"},{"id":"130675","messageId":"20100102053934.30066.95746.chriscool@tuxfamily.org","threadId":"22080","inReplyTo":"20100102053303.30066.26391.chriscool@tuxfamily.org","subject":"[RFC/PATCH 1/5] reset: make \"reset --merge\" discard work tree changes on unmerged entries","fromName":"Christian Couder","fromEmail":"chriscool@tuxfamily.org","sentAt":"2010-01-02T05:39:29Z","receivedAt":"2010-01-02T05:39:29Z","isPatch":true,"sender":{"key":"christian.couder@gmail.com","avatar":"https://avatars.githubusercontent.com/u/208954?v=4"},"body":"From: Junio C Hamano <gitster@pobox.com>\n\nCommit 9e8ecea (Add 'merge' mode to 'git reset', 2008-12-01) disallowed\n\"git reset --merge\" when there was unmerged entries. It acknowledged\nthat this is not the best possible behavior, and that it would be better\nif unmerged entries were reset as if --hard (instead of --merge) has\nbeen used.\n\nRecently another commit (reset: use \"unpack_trees()\" directly instead of\n\"git read-tree\", 2009-12-30) changed the behavior of --merge to accept\nresetting unmerged entries if they are reset to a different state than\nHEAD, but it did not reset the changes in the work tree. So the behavior\nwas kind of improved, but it was not yet as if --hard has been used.\n\nThis patch finally makes \"git reset --merge\" behaves like\n\"git reset --hard\" on unmerged entries.\n\nTo do that it does three things:\n\n - Updates the documentation to match the wish of original \"reset\n   --merge\" better, namely, \"An unmerged entry is a sign that the path\n   didn't have any local modification and can be safely resetted to\n   whatever the new HEAD records\";\n\n - Updates read_index_unmerged(), which reads the index file into the\n   cache while dropping any higher-stage entries down to stage #0, not\n   to copy the object name recorded in the cache entry.  The code used to\n   take the object name from the highest stage entry (\"theirs\" if you\n   happened to have stage #3, or \"ours\" if they removed while you kept),\n   which essentially meant that you are getting random results and\n   didn't make sense.\n\n   The _only_ reason we want to keep a previously unmerged entry in the\n   index at stage #0 is so that we don't forget the fact that we have\n   corresponding file in the work tree in order to be able to remove it\n   when the tree we are resetting to does not have the path.  In order\n   to differentiate such an entry from ordinary cache entry, the cache\n   entry added by read_index_unmerged() records null sha1.\n\n - Updates merged_entry() and deleted_entry() so that they pay attention\n   to cache entries with null sha1 (note that we _might_ want to use a\n   new in-core ce->ce_flags instead of using the null-sha1 hack).  They\n   are previously unmerged entries, and the files in the work tree that\n   correspond to them are resetted away by oneway_merge() to the version\n   from the tree we are resetting to.\n\nSigned-off-by: Christian Couder <chriscool@tuxfamily.org>\n---\n Documentation/git-reset.txt |    4 ++--\n read-cache.c                |    2 +-\n t/t7110-reset-merge.sh      |   14 +++++++-------\n unpack-trees.c              |   19 ++++++++++++-------\n 4 files changed, 22 insertions(+), 17 deletions(-)\n\ndiff --git a/Documentation/git-reset.txt b/Documentation/git-reset.txt\nindex 2480be5..b78e2e1 100644\n--- a/Documentation/git-reset.txt\n+++ b/Documentation/git-reset.txt\n@@ -123,14 +123,14 @@ entries:\n        X       U     A    B     --soft  (disallowed)\n \t\t\t\t--mixed  X       B     B\n \t\t\t\t--hard   B       B     B\n-\t\t\t\t--merge  X       B     B\n+\t\t\t\t--merge  B       B     B\n \n       working index HEAD target         working index HEAD\n       ----------------------------------------------------\n        X       U     A    A     --soft  (disallowed)\n \t\t\t\t--mixed  X       A     A\n \t\t\t\t--hard   A       A     A\n-\t\t\t\t--merge (disallowed)\n+\t\t\t\t--merge  A       A     A\n \n X means any state and U means an unmerged index.\n \ndiff --git a/read-cache.c b/read-cache.c\nindex 94b92d3..e07a6df 100644\n--- a/read-cache.c\n+++ b/read-cache.c\n@@ -1635,7 +1635,7 @@ int read_index_unmerged(struct index_state *istate)\n \t\tlen = strlen(ce->name);\n \t\tsize = cache_entry_size(len);\n \t\tnew_ce = xcalloc(1, size);\n-\t\thashcpy(new_ce->sha1, ce->sha1);\n+\t\t/* don't copy sha1; this should not match anything */\n \t\tmemcpy(new_ce->name, ce->name, len);\n \t\tnew_ce->ce_flags = create_ce_flags(len, 0);\n \t\tnew_ce->ce_mode = ce->ce_mode;\ndiff --git a/t/t7110-reset-merge.sh b/t/t7110-reset-merge.sh\nindex ff2875c..249df7c 100755\n--- a/t/t7110-reset-merge.sh\n+++ b/t/t7110-reset-merge.sh\n@@ -135,27 +135,27 @@ test_expect_success 'setup 2 different branches' '\n #\n #           working index HEAD target         working index HEAD\n #           ----------------------------------------------------\n-# file1:     X       U     B    C     --merge  X       C     C\n+# file1:     X       U     B    C     --merge  C       C     C\n test_expect_success '\"reset --merge HEAD^\" is ok with pending merge' '\n     test_must_fail git merge branch1 &&\n-    cat file1 >orig_file1 &&\n     git reset --merge HEAD^ &&\n     test \"$(git rev-parse HEAD)\" = \"$(git rev-parse second)\" &&\n     test -z \"$(git diff --cached)\" &&\n-    test_cmp file1 orig_file1\n+    test -z \"$(git diff)\"\n '\n \n # The next test will test the following:\n #\n #           working index HEAD target         working index HEAD\n #           ----------------------------------------------------\n-# file1:     X       U     B    B     --merge  (disallowed)\n-test_expect_success '\"reset --merge HEAD\" fails with pending merge' '\n+# file1:     X       U     B    B     --merge  B       B     B\n+test_expect_success '\"reset --merge HEAD\" is ok with pending merge' '\n     git reset --hard third &&\n     test_must_fail git merge branch1 &&\n-    test_must_fail git reset --merge HEAD &&\n+    git reset --merge HEAD &&\n     test \"$(git rev-parse HEAD)\" = \"$(git rev-parse third)\" &&\n-    test -n \"$(git diff --cached)\"\n+    test -z \"$(git diff --cached)\" &&\n+    test -z \"$(git diff)\"\n '\n \n test_done\ndiff --git a/unpack-trees.c b/unpack-trees.c\nindex 7570475..87f95a1 100644\n--- a/unpack-trees.c\n+++ b/unpack-trees.c\n@@ -809,7 +809,11 @@ static int merged_entry(struct cache_entry *merge, struct cache_entry *old,\n {\n \tint update = CE_UPDATE;\n \n-\tif (old) {\n+\tif (!old) {\n+\t\tif (verify_absent(merge, \"overwritten\", o))\n+\t\t\treturn -1;\n+\t\tinvalidate_ce_path(merge, o);\n+\t} else if (!is_null_sha1(old->sha1)) {\n \t\t/*\n \t\t * See if we can re-use the old CE directly?\n \t\t * That way we get the uptodate stat info.\n@@ -827,11 +831,12 @@ static int merged_entry(struct cache_entry *merge, struct cache_entry *old,\n \t\t\t\tupdate |= CE_SKIP_WORKTREE;\n \t\t\tinvalidate_ce_path(old, o);\n \t\t}\n-\t}\n-\telse {\n-\t\tif (verify_absent(merge, \"overwritten\", o))\n-\t\t\treturn -1;\n-\t\tinvalidate_ce_path(merge, o);\n+\t} else {\n+\t\t/*\n+\t\t * Previously unmerged entry left as an existence\n+\t\t * marker by read_index_unmerged();\n+\t\t */\n+\t\tinvalidate_ce_path(old, o);\n \t}\n \n \tadd_entry(o, merge, update, CE_STAGEMASK);\n@@ -847,7 +852,7 @@ static int deleted_entry(struct cache_entry *ce, struct cache_entry *old,\n \t\t\treturn -1;\n \t\treturn 0;\n \t}\n-\tif (verify_uptodate(old, o))\n+\tif (!is_null_sha1(old->sha1) && verify_uptodate(old, o))\n \t\treturn -1;\n \tadd_entry(o, ce, CE_REMOVE, 0);\n \tinvalidate_ce_path(ce, o);\n-- \n1.6.6.rc2.5.g49666\n"},{"id":"130677","messageId":"20100102053934.30066.85625.chriscool@tuxfamily.org","threadId":"22080","inReplyTo":"20100102053303.30066.26391.chriscool@tuxfamily.org","subject":"[RFC/PATCH 2/5] reset: add option \"--keep\" to \"git reset\"","fromName":"Christian Couder","fromEmail":"chriscool@tuxfamily.org","sentAt":"2010-01-02T05:39:30Z","receivedAt":"2010-01-02T05:39:30Z","isPatch":true,"sender":{"key":"christian.couder@gmail.com","avatar":"https://avatars.githubusercontent.com/u/208954?v=4"},"body":"The purpose of this new option is to discard some of the\nlast commits but to keep current changes in the work tree.\n\nThe use case is when you work on something and commit\nthat work. And then you work on something else that touches\nother files, but you don't commit it yet. Then you realize\nthat what you commited when you worked on the first thing\nis not good or belongs to another branch.\n\nSo you want to get rid of the previous commits (at least in\nthe current branch) but you want to make sure that you keep\nthe changes you have in the work tree. And you are pretty\nsure that your changes are independent from what you\npreviously commited, so you don't want the reset to succeed\nif the previous commits changed a file that you also\nchanged in your work tree.\n\nThe table below shows what happens when running\n\"git reset --option target\" to reset the HEAD to another\ncommit (as a special case \"target\" could be the same as\nHEAD) in the cases where \"--merge\" and \"--keep\" behave\ndifferently.\n\nworking index HEAD target         working index HEAD\n----------------------------------------------------\n  A      B     C     D   --keep    (disallowed)\n                         --merge   (disallowed)\n  A      B     C     C   --keep     A      C     C\n                         --merge   (disallowed)\n  B      B     C     D   --keep    (disallowed)\n                         --merge    D      D     D\n  B      B     C     C   --keep     B      C     C\n                         --merge    C      C     C\n\nIn this table, A, B and C are some different states of\na file. For example the last line of the table means\nthat if a file is in state B in the working tree and\nthe index, and in a different state C in HEAD and in\nthe target, then \"git reset --merge target\" will put\nthe file in state C in the working tree, in the index\nand in HEAD.\n\nThe following table shows what happens on unmerged entries:\n\nworking index HEAD target         working index HEAD\n----------------------------------------------------\n X       U     A    B     --keep  (disallowed)\n                          --merge  B       B     B\n X       U     A    A     --keep   X       A     A\n                          --merge  A       A     A\n\nIn this table X can be any state and U means an unmerged\nentry.\n\nThough the error message when \"reset --keep\" is disallowed\non unmerged entries is something like:\n\nerror: Entry 'file1' would be overwritten by merge. Cannot merge.\nfatal: Could not reset index file to revision 'HEAD^'.\n\nwhich is not very nice.\n\nA following patch will add some test cases for\n\"--keep\", where the differences between \"--merge\" and\n\"--keep\" can also be seen.\n\nThe \"--keep\" option is implemented by doing a 2 way merge\nbetween HEAD and the reset target, and if this succeeds\nby doing a mixed reset to the target.\n\nThe code comes from the sequencer GSoC project, where\nsuch an option was developed by Stephan Beyer:\n\ngit://repo.or.cz/git/sbeyer.git\n\n(at commit 5a78908b70ceb5a4ea9fd4b82f07ceba1f019079)\n\nBut in the sequencer project the \"reset\" flag was set\nin the \"struct unpack_trees_options\" passed to\n\"unpack_trees()\". With this flag the changes in the\nworking tree were discarded if the file was different\nbetween HEAD and the reset target.\n\nMentored-by: Daniel Barkalow <barkalow@iabervon.org>\nMentored-by: Christian Couder <chriscool@tuxfamily.org>\nSigned-off-by: Stephan Beyer <s-beyer@gmx.net>\nSigned-off-by: Christian Couder <chriscool@tuxfamily.org>\n---\n builtin-reset.c |   29 ++++++++++++++++++++++++-----\n 1 files changed, 24 insertions(+), 5 deletions(-)\n\ndiff --git a/builtin-reset.c b/builtin-reset.c\nindex 0f5022e..da61f20 100644\n--- a/builtin-reset.c\n+++ b/builtin-reset.c\n@@ -22,13 +22,15 @@\n #include \"cache-tree.h\"\n \n static const char * const git_reset_usage[] = {\n-\t\"git reset [--mixed | --soft | --hard | --merge] [-q] [<commit>]\",\n+\t\"git reset [--mixed | --soft | --hard | --merge | --keep] [-q] [<commit>]\",\n \t\"git reset [--mixed] <commit> [--] <paths>...\",\n \tNULL\n };\n \n-enum reset_type { MIXED, SOFT, HARD, MERGE, NONE };\n-static const char *reset_type_names[] = { \"mixed\", \"soft\", \"hard\", \"merge\", NULL };\n+enum reset_type { MIXED, SOFT, HARD, MERGE, KEEP, NONE };\n+static const char *reset_type_names[] = {\n+\t\"mixed\", \"soft\", \"hard\", \"merge\", \"keep\", NULL\n+};\n \n static char *args_to_str(const char **argv)\n {\n@@ -71,6 +73,7 @@ static int reset_index_file(const unsigned char *sha1, int reset_type, int quiet\n \tif (!quiet)\n \t\topts.verbose_update = 1;\n \tswitch (reset_type) {\n+\tcase KEEP:\n \tcase MERGE:\n \t\topts.update = 1;\n \t\tbreak;\n@@ -85,6 +88,16 @@ static int reset_index_file(const unsigned char *sha1, int reset_type, int quiet\n \n \tread_cache_unmerged();\n \n+\tif (reset_type == KEEP) {\n+\t\tunsigned char head_sha1[20];\n+\t\tif (get_sha1(\"HEAD\", head_sha1))\n+\t\t\treturn error(\"You do not have a valid HEAD.\");\n+\t\tif (!fill_tree_descriptor(desc, head_sha1))\n+\t\t\treturn error(\"Failed to find tree of HEAD.\");\n+\t\tnr++;\n+\t\topts.fn = twoway_merge;\n+\t}\n+\n \tif (!fill_tree_descriptor(desc + nr - 1, sha1))\n \t\treturn error(\"Failed to find tree of %s.\", sha1_to_hex(sha1));\n \tif (unpack_trees(nr, desc, &opts))\n@@ -229,6 +242,8 @@ int cmd_reset(int argc, const char **argv, const char *prefix)\n \t\t\t\t\"reset HEAD, index and working tree\", HARD),\n \t\tOPT_SET_INT(0, \"merge\", &reset_type,\n \t\t\t\t\"reset HEAD, index and working tree\", MERGE),\n+\t\tOPT_SET_INT(0, \"keep\", &reset_type,\n+\t\t\t\t\"reset HEAD but keep local changes\", KEEP),\n \t\tOPT_BOOLEAN('p', \"patch\", &patch_mode, \"select hunks interactively\"),\n \t\tOPT_END()\n \t};\n@@ -317,9 +332,13 @@ int cmd_reset(int argc, const char **argv, const char *prefix)\n \tif (reset_type == SOFT) {\n \t\tif (is_merge() || read_cache() < 0 || unmerged_cache())\n \t\t\tdie(\"Cannot do a soft reset in the middle of a merge.\");\n+\t} else {\n+\t\tint err = reset_index_file(sha1, reset_type, quiet);\n+\t\tif (reset_type == KEEP)\n+\t\t\terr = err || reset_index_file(sha1, MIXED, quiet);\n+\t\tif (err)\n+\t\t\tdie(\"Could not reset index file to revision '%s'.\", rev);\n \t}\n-\telse if (reset_index_file(sha1, reset_type, quiet))\n-\t\tdie(\"Could not reset index file to revision '%s'.\", rev);\n \n \t/* Any resets update HEAD to the head being switched to,\n \t * saving the previous head in ORIG_HEAD before. */\n-- \n1.6.6.rc2.5.g49666\n"},{"id":"130676","messageId":"20100102053934.30066.53176.chriscool@tuxfamily.org","threadId":"22080","inReplyTo":"20100102053303.30066.26391.chriscool@tuxfamily.org","subject":"[RFC/PATCH 3/5] reset: add test cases for \"--keep\" option","fromName":"Christian Couder","fromEmail":"chriscool@tuxfamily.org","sentAt":"2010-01-02T05:39:31Z","receivedAt":"2010-01-02T05:39:31Z","isPatch":true,"sender":{"key":"christian.couder@gmail.com","avatar":"https://avatars.githubusercontent.com/u/208954?v=4"},"body":"This shows that with the \"--keep\" option, changes that are both in\nthe work tree and the index are kept in the work tree after the\nreset (but discarded in the index). As with the \"--merge\" option,\nchanges that are in both the work tree and the index are discarded\nafter the reset.\n\nIn the case of unmerged entries, we can see that \"git reset --merge\"\nresets everything to the target, while with \"--keep\" it works only\nwhen the target state is the same as HEAD and the work tree is not\nreset.\n\nAnd this shows that otherwise \"--merge\" and \"--keep\" have the same\nbehavior.\n\nSigned-off-by: Christian Couder <chriscool@tuxfamily.org>\n---\n t/t7110-reset-merge.sh |  105 +++++++++++++++++++++++++++++++++++++++++++++++-\n 1 files changed, 104 insertions(+), 1 deletions(-)\n\ndiff --git a/t/t7110-reset-merge.sh b/t/t7110-reset-merge.sh\nindex 249df7c..a9b2fba 100755\n--- a/t/t7110-reset-merge.sh\n+++ b/t/t7110-reset-merge.sh\n@@ -3,7 +3,7 @@\n # Copyright (c) 2009 Christian Couder\n #\n \n-test_description='Tests for \"git reset --merge\"'\n+test_description='Tests for \"git reset\" with \"--merge\" and \"--keep\" options'\n \n . ./test-lib.sh\n \n@@ -47,6 +47,30 @@ test_expect_success 'reset --merge is ok when switching back' '\n #\n #           working index HEAD target         working index HEAD\n #           ----------------------------------------------------\n+# file1:     C       C     C    D     --keep   D       D     D\n+# file2:     C       D     D    D     --keep   C       D     D\n+test_expect_success 'reset --keep is ok with changes in file it does not touch' '\n+    git reset --hard second &&\n+    cat file1 >file2 &&\n+    git reset --keep HEAD^ &&\n+    ! grep 4 file1 &&\n+    grep 4 file2 &&\n+    test \"$(git rev-parse HEAD)\" = \"$(git rev-parse initial)\" &&\n+    test -z \"$(git diff --cached)\"\n+'\n+\n+test_expect_success 'reset --keep is ok when switching back' '\n+    git reset --keep second &&\n+    grep 4 file1 &&\n+    grep 4 file2 &&\n+    test \"$(git rev-parse HEAD)\" = \"$(git rev-parse second)\" &&\n+    test -z \"$(git diff --cached)\"\n+'\n+\n+# The next test will test the following:\n+#\n+#           working index HEAD target         working index HEAD\n+#           ----------------------------------------------------\n # file1:     B       B     C    D     --merge  D       D     D\n # file2:     C       D     D    D     --merge  C       D     D\n test_expect_success 'reset --merge discards changes added to index (1)' '\n@@ -78,6 +102,18 @@ test_expect_success 'reset --merge is ok again when switching back (1)' '\n #\n #           working index HEAD target         working index HEAD\n #           ----------------------------------------------------\n+# file1:     B       B     C    D     --keep   (disallowed)\n+test_expect_success 'reset --keep fails with changes in index in files it touches' '\n+    git reset --hard second &&\n+    echo \"line 5\" >> file1 &&\n+    git add file1 &&\n+    test_must_fail git reset --keep HEAD^\n+'\n+\n+# The next test will test the following:\n+#\n+#           working index HEAD target         working index HEAD\n+#           ----------------------------------------------------\n # file1:     C       C     C    D     --merge  D       D     D\n # file2:     C       C     D    D     --merge  D       D     D\n test_expect_success 'reset --merge discards changes added to index (2)' '\n@@ -104,6 +140,30 @@ test_expect_success 'reset --merge is ok again when switching back (2)' '\n #\n #           working index HEAD target         working index HEAD\n #           ----------------------------------------------------\n+# file1:     C       C     C    D     --keep   D       D     D\n+# file2:     C       C     D    D     --keep   C       D     D\n+test_expect_success 'reset --keep keeps changes it does not touch' '\n+    git reset --hard second &&\n+    echo \"line 4\" >> file2 &&\n+    git add file2 &&\n+    git reset --keep HEAD^ &&\n+    grep 4 file2 &&\n+    test \"$(git rev-parse HEAD)\" = \"$(git rev-parse initial)\" &&\n+    test -z \"$(git diff --cached)\"\n+'\n+\n+test_expect_success 'reset --keep keeps changes when switching back' '\n+    git reset --keep second &&\n+    grep 4 file2 &&\n+    grep 4 file1 &&\n+    test \"$(git rev-parse HEAD)\" = \"$(git rev-parse second)\" &&\n+    test -z \"$(git diff --cached)\"\n+'\n+\n+# The next test will test the following:\n+#\n+#           working index HEAD target         working index HEAD\n+#           ----------------------------------------------------\n # file1:     A       B     B    C     --merge  (disallowed)\n test_expect_success 'reset --merge fails with changes in file it touches' '\n     git reset --hard second &&\n@@ -116,6 +176,22 @@ test_expect_success 'reset --merge fails with changes in file it touches' '\n     grep file1 err.log | grep \"not uptodate\"\n '\n \n+# The next test will test the following:\n+#\n+#           working index HEAD target         working index HEAD\n+#           ----------------------------------------------------\n+# file1:     A       B     B    C     --keep   (disallowed)\n+test_expect_success 'reset --keep fails with changes in file it touches' '\n+    git reset --hard second &&\n+    echo \"line 5\" >> file1 &&\n+    test_tick &&\n+    git commit -m \"add line 5\" file1 &&\n+    sed -e \"s/line 1/changed line 1/\" <file1 >file3 &&\n+    mv file3 file1 &&\n+    test_must_fail git reset --keep HEAD^ 2>err.log &&\n+    grep file1 err.log | grep \"not uptodate\"\n+'\n+\n test_expect_success 'setup 2 different branches' '\n     git reset --hard second &&\n     git branch branch1 &&\n@@ -148,6 +224,18 @@ test_expect_success '\"reset --merge HEAD^\" is ok with pending merge' '\n #\n #           working index HEAD target         working index HEAD\n #           ----------------------------------------------------\n+# file1:     X       U     B    C     --keep   (disallowed)\n+test_expect_success '\"reset --keep HEAD^\" fails with pending merge' '\n+    git reset --hard third &&\n+    test_must_fail git merge branch1 &&\n+    test_must_fail git reset --keep HEAD^ 2>err.log &&\n+    grep file1 err.log | grep \"overwritten by merge\"\n+'\n+\n+# The next test will test the following:\n+#\n+#           working index HEAD target         working index HEAD\n+#           ----------------------------------------------------\n # file1:     X       U     B    B     --merge  B       B     B\n test_expect_success '\"reset --merge HEAD\" is ok with pending merge' '\n     git reset --hard third &&\n@@ -158,4 +246,19 @@ test_expect_success '\"reset --merge HEAD\" is ok with pending merge' '\n     test -z \"$(git diff)\"\n '\n \n+# The next test will test the following:\n+#\n+#           working index HEAD target         working index HEAD\n+#           ----------------------------------------------------\n+# file1:     X       U     B    B     --keep  X       B     B\n+test_expect_success '\"reset --keep HEAD\" is ok with pending merge' '\n+    git reset --hard third &&\n+    test_must_fail git merge branch1 &&\n+    cat file1 >orig_file1 &&\n+    git reset --keep HEAD &&\n+    test \"$(git rev-parse HEAD)\" = \"$(git rev-parse third)\" &&\n+    test -z \"$(git diff --cached)\" &&\n+    test_cmp file1 orig_file1\n+'\n+\n test_done\n-- \n1.6.6.rc2.5.g49666\n"},{"id":"130674","messageId":"20100102053934.30066.76552.chriscool@tuxfamily.org","threadId":"22080","inReplyTo":"20100102053303.30066.26391.chriscool@tuxfamily.org","subject":"[RFC/PATCH 4/5] Documentation: reset: describe new \"--keep\" option","fromName":"Christian Couder","fromEmail":"chriscool@tuxfamily.org","sentAt":"2010-01-02T05:39:32Z","receivedAt":"2010-01-02T05:39:32Z","isPatch":true,"sender":{"key":"christian.couder@gmail.com","avatar":"https://avatars.githubusercontent.com/u/208954?v=4"},"body":"and give an example to show how it can be used.\n\nSigned-off-by: Christian Couder <chriscool@tuxfamily.org>\n---\n Documentation/git-reset.txt |   41 ++++++++++++++++++++++++++++++++++++++---\n 1 files changed, 38 insertions(+), 3 deletions(-)\n\ndiff --git a/Documentation/git-reset.txt b/Documentation/git-reset.txt\nindex b78e2e1..3d7c206 100644\n--- a/Documentation/git-reset.txt\n+++ b/Documentation/git-reset.txt\n@@ -8,7 +8,7 @@ git-reset - Reset current HEAD to the specified state\n SYNOPSIS\n --------\n [verse]\n-'git reset' [--mixed | --soft | --hard | --merge] [-q] [<commit>]\n+'git reset' [--mixed | --soft | --hard | --merge | --keep] [-q] [<commit>]\n 'git reset' [-q] [<commit>] [--] <paths>...\n 'git reset' --patch [<commit>] [--] [<paths>...]\n \n@@ -52,6 +52,11 @@ OPTIONS\n \tand updates the files that are different between the named commit\n \tand the current commit in the working tree.\n \n+--keep::\n+\tResets the index to match the tree recorded by the named commit,\n+\tbut keep changes in the working tree. Aborts if the reset would\n+\tchange files that are already changes in the working tree.\n+\n -p::\n --patch::\n \tInteractively select hunks in the difference between the index\n@@ -86,6 +91,7 @@ reset options depending on the state of the files.\n \t\t\t\t--mixed  A       D     D\n \t\t\t\t--hard   D       D     D\n \t\t\t\t--merge (disallowed)\n+\t\t\t\t--keep  (disallowed)\n \n       working index HEAD target         working index HEAD\n       ----------------------------------------------------\n@@ -93,6 +99,7 @@ reset options depending on the state of the files.\n \t\t\t\t--mixed  A       C     C\n \t\t\t\t--hard   C       C     C\n \t\t\t\t--merge (disallowed)\n+\t\t\t\t--keep   A       C     C\n \n       working index HEAD target         working index HEAD\n       ----------------------------------------------------\n@@ -100,6 +107,7 @@ reset options depending on the state of the files.\n \t\t\t\t--mixed  B       D     D\n \t\t\t\t--hard   D       D     D\n \t\t\t\t--merge  D       D     D\n+\t\t\t\t--keep  (disallowed)\n \n       working index HEAD target         working index HEAD\n       ----------------------------------------------------\n@@ -107,13 +115,14 @@ reset options depending on the state of the files.\n \t\t\t\t--mixed  B       C     C\n \t\t\t\t--hard   C       C     C\n \t\t\t\t--merge  C       C     C\n+\t\t\t\t--keep   B       C     C\n \n In these tables, A, B, C and D are some different states of a\n file. For example, the last line of the last table means that if a\n file is in state B in the working tree and the index, and in a\n different state C in HEAD and in the target, then \"git reset\n---merge target\" will put the file in state C in the working tree,\n-in the index and in HEAD.\n+--keep target\" will put the file in state B in the working tree,\n+and in state C in the index and in HEAD.\n \n The following tables show what happens when there are unmerged\n entries:\n@@ -124,6 +133,7 @@ entries:\n \t\t\t\t--mixed  X       B     B\n \t\t\t\t--hard   B       B     B\n \t\t\t\t--merge  B       B     B\n+\t\t\t\t--keep  (disallowed)\n \n       working index HEAD target         working index HEAD\n       ----------------------------------------------------\n@@ -131,6 +141,7 @@ entries:\n \t\t\t\t--mixed  X       A     A\n \t\t\t\t--hard   A       A     A\n \t\t\t\t--merge  A       A     A\n+\t\t\t\t--keep   X       A     A\n \n X means any state and U means an unmerged index.\n \n@@ -302,6 +313,30 @@ $ git add frotz.c                           <3>\n <2> This commits all other changes in the index.\n <3> Adds the file to the index again.\n \n+Keep changes in working tree while discarding some previous commits::\n++\n+Suppose you are working on something and you commit it, and then you\n+continue working a bit more, but now you think that what you have in\n+your working tree should be in another branch that has nothing to do\n+with what you commited previously. You can start a new branch and\n+reset it while keeping the changes in your work tree.\n++\n+------------\n+$ git tag start\n+$ git branch branch1\n+$ edit\n+$ git commit ...                            <1>\n+$ edit\n+$ git branch branch2                        <2>\n+$ git reset --keep start                    <3>\n+------------\n++\n+<1> This commits your first edits in branch1.\n+<2> This creates branch2, but unfortunately it contains the previous\n+commit that you don't want in this branch.\n+<3> This removes the unwanted previous commit, but this keeps the\n+changes in your working tree.\n+\n Author\n ------\n Written by Junio C Hamano <gitster@pobox.com> and Linus Torvalds <torvalds@osdl.org>\n-- \n1.6.6.rc2.5.g49666\n"},{"id":"130678","messageId":"20100102053934.30066.20988.chriscool@tuxfamily.org","threadId":"22080","inReplyTo":"20100102053303.30066.26391.chriscool@tuxfamily.org","subject":"[RFC/PATCH 5/5] reset: disallow \"reset --keep\" outside a work tree","fromName":"Christian Couder","fromEmail":"chriscool@tuxfamily.org","sentAt":"2010-01-02T05:39:33Z","receivedAt":"2010-01-02T05:39:33Z","isPatch":true,"sender":{"key":"christian.couder@gmail.com","avatar":"https://avatars.githubusercontent.com/u/208954?v=4"},"body":"It is safer and consistent with \"--merge\" and \"--hard\" resets to disallow\n\"git reset --keep\" outside a work tree.\n\nSo let's just do that and add some tests while at it.\n\nSigned-off-by: Christian Couder <chriscool@tuxfamily.org>\n---\n builtin-reset.c       |    2 +-\n t/t7103-reset-bare.sh |   25 +++++++++++++++++--------\n 2 files changed, 18 insertions(+), 9 deletions(-)\n\ndiff --git a/builtin-reset.c b/builtin-reset.c\nindex da61f20..52584af 100644\n--- a/builtin-reset.c\n+++ b/builtin-reset.c\n@@ -319,7 +319,7 @@ int cmd_reset(int argc, const char **argv, const char *prefix)\n \tif (reset_type == NONE)\n \t\treset_type = MIXED; /* by default */\n \n-\tif (reset_type == HARD || reset_type == MERGE)\n+\tif (reset_type != SOFT && reset_type != MIXED)\n \t\tsetup_work_tree();\n \n \tif (reset_type == MIXED && is_bare_repository())\ndiff --git a/t/t7103-reset-bare.sh b/t/t7103-reset-bare.sh\nindex afb55b3..1eef93c 100755\n--- a/t/t7103-reset-bare.sh\n+++ b/t/t7103-reset-bare.sh\n@@ -11,21 +11,26 @@ test_expect_success 'setup non-bare' '\n \tgit commit -a -m two\n '\n \n-test_expect_success 'hard reset requires a worktree' '\n+test_expect_success '\"hard\" reset requires a worktree' '\n \t(cd .git &&\n \t test_must_fail git reset --hard)\n '\n \n-test_expect_success 'merge reset requires a worktree' '\n+test_expect_success '\"merge\" reset requires a worktree' '\n \t(cd .git &&\n \t test_must_fail git reset --merge)\n '\n \n-test_expect_success 'mixed reset is ok' '\n+test_expect_success '\"keep\" reset requires a worktree' '\n+\t(cd .git &&\n+\t test_must_fail git reset --keep)\n+'\n+\n+test_expect_success '\"mixed\" reset is ok' '\n \t(cd .git && git reset)\n '\n \n-test_expect_success 'soft reset is ok' '\n+test_expect_success '\"soft\" reset is ok' '\n \t(cd .git && git reset --soft)\n '\n \n@@ -40,19 +45,23 @@ test_expect_success 'setup bare' '\n \tcd bare.git\n '\n \n-test_expect_success 'hard reset is not allowed in bare' '\n+test_expect_success '\"hard\" reset is not allowed in bare' '\n \ttest_must_fail git reset --hard HEAD^\n '\n \n-test_expect_success 'merge reset is not allowed in bare' '\n+test_expect_success '\"merge\" reset is not allowed in bare' '\n \ttest_must_fail git reset --merge HEAD^\n '\n \n-test_expect_success 'mixed reset is not allowed in bare' '\n+test_expect_success '\"keep\" reset is not allowed in bare' '\n+\ttest_must_fail git reset --keep HEAD^\n+'\n+\n+test_expect_success '\"mixed\" reset is not allowed in bare' '\n \ttest_must_fail git reset --mixed HEAD^\n '\n \n-test_expect_success 'soft reset is allowed in bare' '\n+test_expect_success '\"soft\" reset is allowed in bare' '\n \tgit reset --soft HEAD^ &&\n \ttest \"`git show --pretty=format:%s | head -n 1`\" = \"one\"\n '\n-- \n1.6.6.rc2.5.g49666\n"},{"id":"130682","messageId":"m2vdfkanad.fsf@igel.home","threadId":"22080","inReplyTo":"20100102053934.30066.76552.chriscool@tuxfamily.org","subject":"Re: [RFC/PATCH 4/5] Documentation: reset: describe new \"--keep\" option","fromName":"Andreas Schwab","fromEmail":"schwab@linux-m68k.org","sentAt":"2010-01-02T09:06:34Z","receivedAt":"2010-01-02T09:06:34Z","isPatch":true,"sender":{"key":"schwab@linux-m68k.org","avatar":"https://avatars.githubusercontent.com/u/2175493?v=4"},"body":"Christian Couder <chriscool@tuxfamily.org> writes:\n\n> +--keep::\n> +\tResets the index to match the tree recorded by the named commit,\n> +\tbut keep changes in the working tree. Aborts if the reset would\n> +\tchange files that are already changes in the working tree.\n\ns/changes/changed/ in the last sentence.\n\nAndreas.\n\n-- \nAndreas Schwab, schwab@linux-m68k.org\nGPG Key fingerprint = 58CA 54C7 6D53 942B 1756  01D3 44D5 214B 8276 4ED5\n\"And now for something completely different.\"\n"},{"id":"130691","messageId":"20100102171422.GA19522@panix.com","threadId":"22080","inReplyTo":"20100102053934.30066.76552.chriscool@tuxfamily.org","subject":"Re: [RFC/PATCH 4/5] Documentation: reset: describe new \"--keep\" option","fromName":"Daniel Convissor","fromEmail":"danielc@analysisandsolutions.com","sentAt":"2010-01-02T17:14:23Z","receivedAt":"2010-01-02T17:14:23Z","isPatch":true,"sender":{"key":"danielc@analysisandsolutions.com","avatar":"https://gravatar.com/avatar/6934d176616faccef0fe2329329c24e2a2d92783d565704c7c4f85ea9219d412?d=mp&s=160"},"body":"On Sat, Jan 02, 2010 at 06:39:32AM +0100, Christian Couder wrote:\n> +++ b/Documentation/git-reset.txt\n...\n> +--keep::\n> +\tResets the index to match the tree recorded by the named commit,\n> +\tbut keep changes in the working tree. Aborts if the reset would\n> +\tchange files that are already changes in the working tree.\n\nGrammar suggestion for the last line there.  Change \"already changes\" to \n\"already changed\".  Or better yet, use a different word, such as \"already \nmodified\", since \"change\" based words have been used so many times \nalready in the sentence.\n\nThanks,\n\n--Dan\n\n-- \n T H E   A N A L Y S I S   A N D   S O L U T I O N S   C O M P A N Y\n            data intensive web and database programming\n                http://www.AnalysisAndSolutions.com/\n 4015 7th Ave #4, Brooklyn NY 11232  v: 718-854-0335 f: 718-854-0409\n"},{"id":"130698","messageId":"7vzl4w8f2y.fsf@alter.siamese.dyndns.org","threadId":"22080","inReplyTo":"20100102053934.30066.95746.chriscool@tuxfamily.org","subject":"Re: [RFC/PATCH 1/5] reset: make \"reset --merge\" discard work tree changes on unmerged entries","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2010-01-02T19:46:45Z","receivedAt":"2010-01-02T19:46:45Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Christian Couder <chriscool@tuxfamily.org> writes:\n\n> From: Junio C Hamano <gitster@pobox.com>\n>\n> Commit 9e8ecea (Add 'merge' mode to 'git reset', 2008-12-01) disallowed\n> \"git reset --merge\" when there was unmerged entries. It acknowledged\n> that this is not the best possible behavior, and that it would be better\n> if unmerged entries were reset as if --hard (instead of --merge) has\n> been used.\n>\n> Recently another commit (reset: use \"unpack_trees()\" directly instead of\n> \"git read-tree\", 2009-12-30) changed the behavior of --merge to accept\n> resetting unmerged entries if they are reset to a different state than\n> HEAD, but it did not reset the changes in the work tree. So the behavior\n> was kind of improved, but it was not yet as if --hard has been used.\n\nIt would be more honest if we said something like:\n\n\tIt changed a safer \"I can't do as asked, please do it by hand\"\n\tinto a more dangerous \"I pretend that I did so but I didn't do the\n\tfull job; you need to fix up the result but I am not telling you\n\tthat you have to\", which is a lot worse.\n\nhere instead (that is one reason why I said my fix-up was \"squashable\").\n\nBut that is a minor issue.\n\nI have been thinking about two issues on this --merge change.  \n\n>  - Updates merged_entry() and deleted_entry() so that they pay attention\n>    to cache entries with null sha1 (note that we _might_ want to use a\n>    new in-core ce->ce_flags instead of using the null-sha1 hack).  They\n>    are previously unmerged entries, and the files in the work tree that\n>    correspond to them are resetted away by oneway_merge() to the version\n>    from the tree we are resetting to.\n\nOne is the use of ce_flags instead of relying on the 20-byte comparison I\nsaid above, for both performance (minor) and future maintainability (much\nbigger) concern.  I have a feeling that we will regret later that we used\nthe null_sha1 trick here, when we want to express another \"special\" kind\nof cache entry in unrelated situations.  The use of null_sha1 hack was\nexpedient but I fell victim of the same mentality of declaring that this\nis the _last_ such kind of special index entry and closing the door to\nothers who want to extend the system later with different kind of special\ncache entry, which I often complain about myself to patches from other\npeople.\n\nAnother is that it _might_ make sense to use two-tree form of read-tree\nmachinery (but using a different version of unpack-trees.c::twoway_merge()\nfunction), instead of the one-tree form of \"we don't bother checking if\nthe index is consistent with HEAD and assume it is, and jump to the\ntarget.\"\n\n\"git reset --merge $there\" is about the situation where you started a\n\"mergy\" operation (e.g. \"git merge\", \"git am -3\", \"git rebase\", ...) while\nyou had unrelated local changes in the work tree, and you want to go back\nto the state before that operation $there (which is HEAD if the mergy\noperation is \"merge\", but is different from HEAD if it was \"am -3\" and you\nhave successfully applied a patch or more already).  Linus may know and\nwon't use \"reset --merge\" in a situation where it is not suitable, but not\neverybody is Linus.  Even though \"reset --merge\" may \"correctly\" work with\nrespect to the table you added to \"git reset\" documentation, it would do\nsomething that may not \"make sense\" from the end-user's point of view when\nused in a situation that it wasn't designed for.  Using the two-tree form\nallows the machinery to inspect the difference between HEAD and the index,\nand detect cases where \"reset --merge\" was attempted when it shouldn't.\nFor example, if stage #2 of an unmerged path does not match HEAD, we know\nthere is something wrong.\n\nThis latter issue is much bigger and needs a lot more thought, and I don't\nthink it should block the series from going forward at all.  But I think\nit is worth keeping in the back of our heads.\n"},{"id":"130699","messageId":"7viqbk8evw.fsf@alter.siamese.dyndns.org","threadId":"22080","inReplyTo":"20100102053934.30066.85625.chriscool@tuxfamily.org","subject":"Re: [RFC/PATCH 2/5] reset: add option \"--keep\" to \"git reset\"","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2010-01-02T19:50:59Z","receivedAt":"2010-01-02T19:50:59Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Christian Couder <chriscool@tuxfamily.org> writes:\n\n> The purpose of this new option is to discard some of the last commits\n> but to keep current changes in the work tree.\n>\n> The use case is when you work on something and commit that work. And\n> then you work on something else that touches other files, but you don't\n> commit it yet. Then you realize that what you commited when you worked\n> on the first thing is not good or belongs to another branch.\n>\n> So you want to get rid of the previous commits (at least in the current\n> branch) but you want to make sure that you keep the changes you have in\n> the work tree. And you are pretty sure that your changes are independent\n> from what you previously commited, so you don't want the reset to\n> succeed if the previous commits changed a file that you also changed in\n> your work tree.\n>\n> The table below shows what happens when running \"git reset --option\n> target\" to reset the HEAD to another commit (as a special case \"target\"\n> could be the same as HEAD) in the cases where \"--merge\" and \"--keep\"\n> behave differently.\n\nI think this new option is unrelated to \"--merge\"; iow, the only relation\nto it is that it is an option to the same command \"git reset\", so it is\nrelated but it is related the same way and to the degree as \"--mixed\" is.\n\nThinking about it even more, if the number of commits you are resetting\naway is zero in your use case (i.e. target is HEAD), shouldn't this new\nmode of operation degenerate to \"--mixed\"?  So in that sense, it might\nmake sense to contrast it with \"--mixed\".\n\nBut let's try not to contrast it with anything else, and see how well it\nstands on its own.  The below is my attempt.\n\n> working index HEAD target         working index HEAD\n> ----------------------------------------------------\n>   A      B     C     D   --keep    (disallowed)\n>   A      B     C     C   --keep     A      C     C\n>   B      B     C     D   --keep    (disallowed)\n>   B      B     C     C   --keep     B      C     C\n\nLet's give an explanation of the above in terms of what this means to the\nend users.\n\n    When you have changes to a path that the accumulated commits between\n    target..HEAD touch, you don't want to discard them.  It doesn't matter\n    if the changes in the work tree has been partially added (A != B) or\n    fully added (A == B) to the index.  In both cases, the operation is\n    disallowed, just like \"checkout $another_branch\" stops in such a case.\n\n    But if you have local modifications based on one version and dropping\n    the accumulated commits between target..HEAD does not involve that\n    path, we can safely \"transplant\" that change to the target.\n\nPresented this way, a future direction (iow, I am not suggesting you to do\nthis before the current series solidifies) might be to allow users to do\nsomething similar to \"checkout -m $the_other_branch\".  IOW, instead of\ndisallowing \"I have changed from C to B and switching to D\" case, perform\na three-way merge to bring the work tree file to (D+(B-C)), transplanting\nthe local change you made on top of the target.\n\n> The following table shows what happens on unmerged entries:\n>\n> working index HEAD target         working index HEAD\n> ----------------------------------------------------\n>  X       U     A    B     --keep  (disallowed)\n>  X       U     A    A     --keep   X       A     A\n\nIn a sense, this is consistent with the above; the local change attempted\nhappens to be an unmerged result.\n\nBut it is inconsistent with the intended use case you presented, which\nleaves no room for unmerged entries to enter in the index to begin with.\nIt might be safer to error out on any unmerged entry in the index.  I\ndunno.\n"},{"id":"132068","messageId":"201001190528.47414.chriscool@tuxfamily.org","threadId":"22080","inReplyTo":"7viqbk8evw.fsf@alter.siamese.dyndns.org","subject":"Re: [RFC/PATCH 2/5] reset: add option \"--keep\" to \"git reset\"","fromName":"Christian Couder","fromEmail":"chriscool@tuxfamily.org","sentAt":"2010-01-19T04:28:47Z","receivedAt":"2010-01-19T04:28:47Z","isPatch":true,"sender":{"key":"christian.couder@gmail.com","avatar":"https://avatars.githubusercontent.com/u/208954?v=4"},"body":"On samedi 02 janvier 2010, Junio C Hamano wrote:\n> Christian Couder <chriscool@tuxfamily.org> writes:\n> > The purpose of this new option is to discard some of the last commits\n> > but to keep current changes in the work tree.\n> >\n> > The use case is when you work on something and commit that work. And\n> > then you work on something else that touches other files, but you don't\n> > commit it yet. Then you realize that what you commited when you worked\n> > on the first thing is not good or belongs to another branch.\n> >\n> > So you want to get rid of the previous commits (at least in the current\n> > branch) but you want to make sure that you keep the changes you have in\n> > the work tree. And you are pretty sure that your changes are\n> > independent from what you previously commited, so you don't want the\n> > reset to succeed if the previous commits changed a file that you also\n> > changed in your work tree.\n> >\n> > The table below shows what happens when running \"git reset --option\n> > target\" to reset the HEAD to another commit (as a special case \"target\"\n> > could be the same as HEAD) in the cases where \"--merge\" and \"--keep\"\n> > behave differently.\n>\n> I think this new option is unrelated to \"--merge\"; iow, the only relation\n> to it is that it is an option to the same command \"git reset\", so it is\n> related but it is related the same way and to the degree as \"--mixed\" is.\n>\n> Thinking about it even more, if the number of commits you are resetting\n> away is zero in your use case (i.e. target is HEAD), shouldn't this new\n> mode of operation degenerate to \"--mixed\"?  So in that sense, it might\n> make sense to contrast it with \"--mixed\".\n>\n> But let's try not to contrast it with anything else, and see how well it\n> stands on its own. \n\nOk, I removed parts of the commit messages that contrasted it \nwith \"--merge\".\n\n[...]\n\n> > The following table shows what happens on unmerged entries:\n> >\n> > working index HEAD target         working index HEAD\n> > ----------------------------------------------------\n> >  X       U     A    B     --keep  (disallowed)\n> >  X       U     A    A     --keep   X       A     A\n>\n> In a sense, this is consistent with the above; the local change attempted\n> happens to be an unmerged result.\n>\n> But it is inconsistent with the intended use case you presented, which\n> leaves no room for unmerged entries to enter in the index to begin with.\n> It might be safer to error out on any unmerged entry in the index.  I\n> dunno.\n\nYeah I agree it might be safer, so I added a patch to disallow using --keep \nwhen there are unmerged entries.\n\nThanks,\nChristian.\n"},{"id":"132069","messageId":"201001190528.54642.chriscool@tuxfamily.org","threadId":"22080","inReplyTo":"20100102171422.GA19522@panix.com","subject":"Re: [RFC/PATCH 4/5] Documentation: reset: describe new \"--keep\" option","fromName":"Christian Couder","fromEmail":"chriscool@tuxfamily.org","sentAt":"2010-01-19T04:28:54Z","receivedAt":"2010-01-19T04:28:54Z","isPatch":true,"sender":{"key":"christian.couder@gmail.com","avatar":"https://avatars.githubusercontent.com/u/208954?v=4"},"body":"On samedi 02 janvier 2010, Daniel Convissor wrote:\n> On Sat, Jan 02, 2010 at 06:39:32AM +0100, Christian Couder wrote:\n> > +++ b/Documentation/git-reset.txt\n>\n> ...\n>\n> > +--keep::\n> > +\tResets the index to match the tree recorded by the named commit,\n> > +\tbut keep changes in the working tree. Aborts if the reset would\n> > +\tchange files that are already changes in the working tree.\n>\n> Grammar suggestion for the last line there.  Change \"already changes\" to\n> \"already changed\".  Or better yet, use a different word, such as \"already\n> modified\", since \"change\" based words have been used so many times\n> already in the sentence.\n\nOk I used \"already modified\".\n\nThanks,\nChristian.\n"}]}