From 9bc454df08ca2a27b51ac0ab9ff8f154e51b8698 Mon Sep 17 00:00:00 2001 From: Christian Couder Date: Tue, 19 Jan 2010 05:25:57 +0100 Subject: [PATCH 1/6] reset: add option "--keep" to "git reset" The purpose of this new option is to discard some of the last commits but to keep current changes in the work tree. The use case is when you work on something and commit that work. And then you work on something else that touches other files, but you don't commit it yet. Then you realize that what you commited when you worked on the first thing is not good or belongs to another branch. So you want to get rid of the previous commits (at least in the current branch) but you want to make sure that you keep the changes you have in the work tree. And you are pretty sure that your changes are independent from what you previously commited, so you don't want the reset to succeed if the previous commits changed a file that you also changed in your work tree. The table below shows what happens when running "git reset --keep target" to reset the HEAD to another commit (as a special case "target" could be the same as HEAD). working index HEAD target working index HEAD ---------------------------------------------------- A B C D --keep (disallowed) A B C C --keep A C C B B C D --keep (disallowed) B B C C --keep B C C In this table, A, B and C are some different states of a file. For example the last line of the table means that if a file is in state B in the working tree and the index, and in a different state C in HEAD and in the target, then "git reset --keep target" will put the file in state B in the working tree, and in state C in the index and in HEAD. The following table shows what happens on unmerged entries: working index HEAD target working index HEAD ---------------------------------------------------- X U A B --keep (disallowed) X U A A --keep X A A In this table X can be any state and U means an unmerged entry. Though the error message when "reset --keep" is disallowed on unmerged entries is something like: error: Entry 'file1' would be overwritten by merge. Cannot merge. fatal: Could not reset index file to revision 'HEAD^'. which is not very nice. A following patch will add some test cases for "--keep". The "--keep" option is implemented by doing a 2 way merge between HEAD and the reset target, and if this succeeds by doing a mixed reset to the target. The code comes from the sequencer GSoC project, where such an option was developed by Stephan Beyer: git://repo.or.cz/git/sbeyer.git (at commit 5a78908b70ceb5a4ea9fd4b82f07ceba1f019079) But in the sequencer project the "reset" flag was set in the "struct unpack_trees_options" passed to "unpack_trees()". With this flag the changes in the working tree were discarded if the file was different between HEAD and the reset target. Mentored-by: Daniel Barkalow Mentored-by: Christian Couder Signed-off-by: Stephan Beyer Signed-off-by: Christian Couder Signed-off-by: Junio C Hamano --- builtin-reset.c | 29 ++++++++++++++++++++++++----- 1 file changed, 24 insertions(+), 5 deletions(-) diff --git a/builtin-reset.c b/builtin-reset.c index 0f5022eed2..da61f20e87 100644 --- a/builtin-reset.c +++ b/builtin-reset.c @@ -22,13 +22,15 @@ #include "cache-tree.h" static const char * const git_reset_usage[] = { - "git reset [--mixed | --soft | --hard | --merge] [-q] []", + "git reset [--mixed | --soft | --hard | --merge | --keep] [-q] []", "git reset [--mixed] [--] ...", NULL }; -enum reset_type { MIXED, SOFT, HARD, MERGE, NONE }; -static const char *reset_type_names[] = { "mixed", "soft", "hard", "merge", NULL }; +enum reset_type { MIXED, SOFT, HARD, MERGE, KEEP, NONE }; +static const char *reset_type_names[] = { + "mixed", "soft", "hard", "merge", "keep", NULL +}; static char *args_to_str(const char **argv) { @@ -71,6 +73,7 @@ static int reset_index_file(const unsigned char *sha1, int reset_type, int quiet if (!quiet) opts.verbose_update = 1; switch (reset_type) { + case KEEP: case MERGE: opts.update = 1; break; @@ -85,6 +88,16 @@ static int reset_index_file(const unsigned char *sha1, int reset_type, int quiet read_cache_unmerged(); + if (reset_type == KEEP) { + unsigned char head_sha1[20]; + if (get_sha1("HEAD", head_sha1)) + return error("You do not have a valid HEAD."); + if (!fill_tree_descriptor(desc, head_sha1)) + return error("Failed to find tree of HEAD."); + nr++; + opts.fn = twoway_merge; + } + if (!fill_tree_descriptor(desc + nr - 1, sha1)) return error("Failed to find tree of %s.", sha1_to_hex(sha1)); if (unpack_trees(nr, desc, &opts)) @@ -229,6 +242,8 @@ int cmd_reset(int argc, const char **argv, const char *prefix) "reset HEAD, index and working tree", HARD), OPT_SET_INT(0, "merge", &reset_type, "reset HEAD, index and working tree", MERGE), + OPT_SET_INT(0, "keep", &reset_type, + "reset HEAD but keep local changes", KEEP), OPT_BOOLEAN('p', "patch", &patch_mode, "select hunks interactively"), OPT_END() }; @@ -317,9 +332,13 @@ int cmd_reset(int argc, const char **argv, const char *prefix) if (reset_type == SOFT) { if (is_merge() || read_cache() < 0 || unmerged_cache()) die("Cannot do a soft reset in the middle of a merge."); + } else { + int err = reset_index_file(sha1, reset_type, quiet); + if (reset_type == KEEP) + err = err || reset_index_file(sha1, MIXED, quiet); + if (err) + die("Could not reset index file to revision '%s'.", rev); } - else if (reset_index_file(sha1, reset_type, quiet)) - die("Could not reset index file to revision '%s'.", rev); /* Any resets update HEAD to the head being switched to, * saving the previous head in ORIG_HEAD before. */ From ffbc5dc2d0cbdbd63a4ae04dc2cc1ebf385fcc25 Mon Sep 17 00:00:00 2001 From: Christian Couder Date: Tue, 19 Jan 2010 05:25:58 +0100 Subject: [PATCH 2/6] reset: add test cases for "--keep" option This shows that with the "--keep" option, changes that are both in the work tree and the index are kept in the work tree after the reset (but discarded in the index). In the case of unmerged entries, we can see that "git reset --keep" works only when the target state is the same as HEAD. And then the work tree is not reset. Signed-off-by: Christian Couder Signed-off-by: Junio C Hamano --- t/t7110-reset-merge.sh | 119 ++++++++++++++++++++++++++++++++++++++++- t/t7111-reset-table.sh | 8 +++ 2 files changed, 126 insertions(+), 1 deletion(-) diff --git a/t/t7110-reset-merge.sh b/t/t7110-reset-merge.sh index 8704d00196..1a9c1c7494 100755 --- a/t/t7110-reset-merge.sh +++ b/t/t7110-reset-merge.sh @@ -3,7 +3,7 @@ # Copyright (c) 2009 Christian Couder # -test_description='Tests for "git reset --merge"' +test_description='Tests for "git reset" with "--merge" and "--keep" options' . ./test-lib.sh @@ -43,6 +43,30 @@ test_expect_success 'reset --merge is ok when switching back' ' test -z "$(git diff --cached)" ' +# The next test will test the following: +# +# working index HEAD target working index HEAD +# ---------------------------------------------------- +# file1: C C C D --keep D D D +# file2: C D D D --keep C D D +test_expect_success 'reset --keep is ok with changes in file it does not touch' ' + git reset --hard second && + cat file1 >file2 && + git reset --keep HEAD^ && + ! grep 4 file1 && + grep 4 file2 && + test "$(git rev-parse HEAD)" = "$(git rev-parse initial)" && + test -z "$(git diff --cached)" +' + +test_expect_success 'reset --keep is ok when switching back' ' + git reset --keep second && + grep 4 file1 && + grep 4 file2 && + test "$(git rev-parse HEAD)" = "$(git rev-parse second)" && + test -z "$(git diff --cached)" +' + # The next test will test the following: # # working index HEAD target working index HEAD @@ -74,6 +98,18 @@ test_expect_success 'reset --merge is ok again when switching back (1)' ' test -z "$(git diff --cached)" ' +# The next test will test the following: +# +# working index HEAD target working index HEAD +# ---------------------------------------------------- +# file1: B B C D --keep (disallowed) +test_expect_success 'reset --keep fails with changes in index in files it touches' ' + git reset --hard second && + echo "line 5" >> file1 && + git add file1 && + test_must_fail git reset --keep HEAD^ +' + # The next test will test the following: # # working index HEAD target working index HEAD @@ -100,6 +136,30 @@ test_expect_success 'reset --merge is ok again when switching back (2)' ' test -z "$(git diff --cached)" ' +# The next test will test the following: +# +# working index HEAD target working index HEAD +# ---------------------------------------------------- +# file1: C C C D --keep D D D +# file2: C C D D --keep C D D +test_expect_success 'reset --keep keeps changes it does not touch' ' + git reset --hard second && + echo "line 4" >> file2 && + git add file2 && + git reset --keep HEAD^ && + grep 4 file2 && + test "$(git rev-parse HEAD)" = "$(git rev-parse initial)" && + test -z "$(git diff --cached)" +' + +test_expect_success 'reset --keep keeps changes when switching back' ' + git reset --keep second && + grep 4 file2 && + grep 4 file1 && + test "$(git rev-parse HEAD)" = "$(git rev-parse second)" && + test -z "$(git diff --cached)" +' + # The next test will test the following: # # working index HEAD target working index HEAD @@ -116,6 +176,22 @@ test_expect_success 'reset --merge fails with changes in file it touches' ' grep file1 err.log | grep "not uptodate" ' +# The next test will test the following: +# +# working index HEAD target working index HEAD +# ---------------------------------------------------- +# file1: A B B C --keep (disallowed) +test_expect_success 'reset --keep fails with changes in file it touches' ' + git reset --hard second && + echo "line 5" >> file1 && + test_tick && + git commit -m "add line 5" file1 && + sed -e "s/line 1/changed line 1/" file3 && + mv file3 file1 && + test_must_fail git reset --keep HEAD^ 2>err.log && + grep file1 err.log | grep "not uptodate" +' + test_expect_success 'setup 3 different branches' ' git reset --hard second && git branch branch1 && @@ -152,6 +228,18 @@ test_expect_success '"reset --merge HEAD^" is ok with pending merge' ' test -z "$(git diff)" ' +# The next test will test the following: +# +# working index HEAD target working index HEAD +# ---------------------------------------------------- +# file1: X U B C --keep (disallowed) +test_expect_success '"reset --keep HEAD^" fails with pending merge' ' + git reset --hard third && + test_must_fail git merge branch1 && + test_must_fail git reset --keep HEAD^ 2>err.log && + grep file1 err.log | grep "overwritten by merge" +' + # The next test will test the following: # # working index HEAD target working index HEAD @@ -166,6 +254,21 @@ test_expect_success '"reset --merge HEAD" is ok with pending merge' ' test -z "$(git diff)" ' +# The next test will test the following: +# +# working index HEAD target working index HEAD +# ---------------------------------------------------- +# file1: X U B B --keep X B B +test_expect_success '"reset --keep HEAD" is ok with pending merge' ' + git reset --hard third && + test_must_fail git merge branch1 && + cat file1 >orig_file1 && + git reset --keep HEAD && + test "$(git rev-parse HEAD)" = "$(git rev-parse third)" && + test -z "$(git diff --cached)" && + test_cmp file1 orig_file1 +' + test_expect_success '--merge with added/deleted' ' git reset --hard third && rm -f file2 && @@ -180,4 +283,18 @@ test_expect_success '--merge with added/deleted' ' git diff --exit-code --cached ' +test_expect_success '--keep with added/deleted' ' + git reset --hard third && + rm -f file2 && + test_must_fail git merge branch3 && + ! test -f file2 && + test -f file3 && + git diff --exit-code file3 && + git diff --exit-code branch3 file3 && + git reset --keep HEAD && + test -f file3 && + ! test -f file2 && + git diff --exit-code --cached +' + test_done diff --git a/t/t7111-reset-table.sh b/t/t7111-reset-table.sh index de896c948d..2ebda97828 100755 --- a/t/t7111-reset-table.sh +++ b/t/t7111-reset-table.sh @@ -44,26 +44,32 @@ A B C D soft A B D A B C D mixed A D D A B C D hard D D D A B C D merge XXXXX +A B C D keep XXXXX A B C C soft A B C A B C C mixed A C C A B C C hard C C C A B C C merge XXXXX +A B C C keep A C C B B C D soft B B D B B C D mixed B D D B B C D hard D D D B B C D merge D D D +B B C D keep XXXXX B B C C soft B B C B B C C mixed B C C B B C C hard C C C B B C C merge C C C +B B C C keep B C C B C C D soft B C D B C C D mixed B D D B C C D hard D D D B C C D merge XXXXX +B C C D keep XXXXX B C C C soft B C C B C C C mixed B C C B C C C hard C C C B C C C merge B C C +B C C C keep B C C EOF test_expect_success 'setting up branches to test with unmerged entries' ' @@ -104,10 +110,12 @@ X U B C soft XXXXX X U B C mixed X C C X U B C hard C C C X U B C merge C C C +X U B C keep XXXXX X U B B soft XXXXX X U B B mixed X B B X U B B hard B B B X U B B merge B B B +X U B B keep X B B EOF test_done From 7349df1142a8dba579c015b51805cc290fcb4e6e Mon Sep 17 00:00:00 2001 From: Christian Couder Date: Fri, 5 Mar 2010 21:25:36 +0100 Subject: [PATCH 3/6] Documentation: reset: describe new "--keep" option and give an example to show how it can be used. Signed-off-by: Christian Couder Signed-off-by: Junio C Hamano --- Documentation/git-reset.txt | 49 ++++++++++++++++++++++++++++++++++++- 1 file changed, 48 insertions(+), 1 deletion(-) diff --git a/Documentation/git-reset.txt b/Documentation/git-reset.txt index 168db08627..1e9ae0ae9f 100644 --- a/Documentation/git-reset.txt +++ b/Documentation/git-reset.txt @@ -8,7 +8,7 @@ git-reset - Reset current HEAD to the specified state SYNOPSIS -------- [verse] -'git reset' [--mixed | --soft | --hard | --merge] [-q] [] +'git reset' [--mixed | --soft | --hard | --merge | --keep] [-q] [] 'git reset' [-q] [] [--] ... 'git reset' --patch [] [--] [...] @@ -52,6 +52,11 @@ OPTIONS and updates the files that are different between the named commit and the current commit in the working tree. +--keep:: + Resets the index to match the tree recorded by the named commit, + but keep changes in the working tree. Aborts if the reset would + change files that are already modified in the working tree. + -p:: --patch:: Interactively select hunks in the difference between the index @@ -93,6 +98,7 @@ in the index and in state D in HEAD. --mixed A D D --hard D D D --merge (disallowed) + --keep (disallowed) working index HEAD target working index HEAD ---------------------------------------------------- @@ -100,6 +106,7 @@ in the index and in state D in HEAD. --mixed A C C --hard C C C --merge (disallowed) + --keep A C C working index HEAD target working index HEAD ---------------------------------------------------- @@ -107,6 +114,7 @@ in the index and in state D in HEAD. --mixed B D D --hard D D D --merge D D D + --keep (disallowed) working index HEAD target working index HEAD ---------------------------------------------------- @@ -114,6 +122,7 @@ in the index and in state D in HEAD. --mixed B C C --hard C C C --merge C C C + --keep B C C working index HEAD target working index HEAD ---------------------------------------------------- @@ -121,6 +130,7 @@ in the index and in state D in HEAD. --mixed B D D --hard D D D --merge (disallowed) + --keep (disallowed) working index HEAD target working index HEAD ---------------------------------------------------- @@ -128,6 +138,7 @@ in the index and in state D in HEAD. --mixed B C C --hard C C C --merge B C C + --keep B C C "reset --merge" is meant to be used when resetting out of a conflicted merge. Any mergy operation guarantees that the work tree file that is @@ -138,6 +149,14 @@ between the index and the work tree, then it means that we are not resetting out from a state that a mergy operation left after failing with a conflict. That is why we disallow --merge option in this case. +"reset --keep" is meant to be used when removing some of the last +commits in the current branch while keeping changes in the working +tree. If there could be conflicts between the changes in the commit we +want to remove and the changes in the working tree we want to keep, +the reset is disallowed. That's why it is disallowed if there are both +changes between the working tree and HEAD, and between HEAD and the +target. + The following tables show what happens when there are unmerged entries: @@ -147,6 +166,7 @@ entries: --mixed X B B --hard B B B --merge B B B + --keep (disallowed) working index HEAD target working index HEAD ---------------------------------------------------- @@ -154,6 +174,7 @@ entries: --mixed X A A --hard A A A --merge A A A + --keep X A A X means any state and U means an unmerged index. @@ -325,6 +346,32 @@ $ git add frotz.c <3> <2> This commits all other changes in the index. <3> Adds the file to the index again. +Keep changes in working tree while discarding some previous commits:: ++ +Suppose you are working on something and you commit it, and then you +continue working a bit more, but now you think that what you have in +your working tree should be in another branch that has nothing to do +with what you commited previously. You can start a new branch and +reset it while keeping the changes in your work tree. ++ +------------ +$ git tag start +$ git checkout -b branch1 +$ edit +$ git commit ... <1> +$ edit +$ git checkout -b branch2 <2> +$ git reset --keep start <3> +------------ ++ +<1> This commits your first edits in branch1. +<2> In the ideal world, you could have realized that the earlier + commit did not belong to the new topic when you created and switched + to branch2 (i.e. "git checkout -b branch2 start"), but nobody is + perfect. +<3> But you can use "reset --keep" to remove the unwanted commit after + you switched to "branch2". + Author ------ Written by Junio C Hamano and Linus Torvalds From ab892a19e83edd1cf9a767bc09d3239f72469d05 Mon Sep 17 00:00:00 2001 From: Christian Couder Date: Tue, 19 Jan 2010 05:26:00 +0100 Subject: [PATCH 4/6] reset: disallow "reset --keep" outside a work tree It is safer and consistent with "--merge" and "--hard" resets to disallow "git reset --keep" outside a work tree. So let's just do that and add some tests while at it. Signed-off-by: Christian Couder Signed-off-by: Junio C Hamano --- builtin-reset.c | 2 +- t/t7103-reset-bare.sh | 25 +++++++++++++++++-------- 2 files changed, 18 insertions(+), 9 deletions(-) diff --git a/builtin-reset.c b/builtin-reset.c index da61f20e87..52584afbdf 100644 --- a/builtin-reset.c +++ b/builtin-reset.c @@ -319,7 +319,7 @@ int cmd_reset(int argc, const char **argv, const char *prefix) if (reset_type == NONE) reset_type = MIXED; /* by default */ - if (reset_type == HARD || reset_type == MERGE) + if (reset_type != SOFT && reset_type != MIXED) setup_work_tree(); if (reset_type == MIXED && is_bare_repository()) diff --git a/t/t7103-reset-bare.sh b/t/t7103-reset-bare.sh index afb55b3a46..1eef93c2b2 100755 --- a/t/t7103-reset-bare.sh +++ b/t/t7103-reset-bare.sh @@ -11,21 +11,26 @@ test_expect_success 'setup non-bare' ' git commit -a -m two ' -test_expect_success 'hard reset requires a worktree' ' +test_expect_success '"hard" reset requires a worktree' ' (cd .git && test_must_fail git reset --hard) ' -test_expect_success 'merge reset requires a worktree' ' +test_expect_success '"merge" reset requires a worktree' ' (cd .git && test_must_fail git reset --merge) ' -test_expect_success 'mixed reset is ok' ' +test_expect_success '"keep" reset requires a worktree' ' + (cd .git && + test_must_fail git reset --keep) +' + +test_expect_success '"mixed" reset is ok' ' (cd .git && git reset) ' -test_expect_success 'soft reset is ok' ' +test_expect_success '"soft" reset is ok' ' (cd .git && git reset --soft) ' @@ -40,19 +45,23 @@ test_expect_success 'setup bare' ' cd bare.git ' -test_expect_success 'hard reset is not allowed in bare' ' +test_expect_success '"hard" reset is not allowed in bare' ' test_must_fail git reset --hard HEAD^ ' -test_expect_success 'merge reset is not allowed in bare' ' +test_expect_success '"merge" reset is not allowed in bare' ' test_must_fail git reset --merge HEAD^ ' -test_expect_success 'mixed reset is not allowed in bare' ' +test_expect_success '"keep" reset is not allowed in bare' ' + test_must_fail git reset --keep HEAD^ +' + +test_expect_success '"mixed" reset is not allowed in bare' ' test_must_fail git reset --mixed HEAD^ ' -test_expect_success 'soft reset is allowed in bare' ' +test_expect_success '"soft" reset is allowed in bare' ' git reset --soft HEAD^ && test "`git show --pretty=format:%s | head -n 1`" = "one" ' From 812d2a3d61b1bbb1931aff2ed6d2a17e939f5bf2 Mon Sep 17 00:00:00 2001 From: Christian Couder Date: Tue, 19 Jan 2010 05:26:01 +0100 Subject: [PATCH 5/6] reset: disallow using --keep when there are unmerged entries The use case for --keep option is to remove previous commits unrelated to the current changes in the working tree. So in this use case we are not supposed to have unmerged entries. This is why it seems safer to just disallow using --keep when there are unmerged entries. And this patch changes the error message when --keep was disallowed and there were some unmerged entries from: error: Entry 'file1' would be overwritten by merge. Cannot merge. fatal: Could not reset index file to revision 'HEAD^'. to: fatal: Cannot do a keep reset in the middle of a merge. which is nicer. Signed-off-by: Christian Couder Signed-off-by: Junio C Hamano --- Documentation/git-reset.txt | 5 +++-- builtin-reset.c | 20 +++++++++++++++----- t/t7110-reset-merge.sh | 23 +++++++++-------------- t/t7111-reset-table.sh | 2 +- 4 files changed, 28 insertions(+), 22 deletions(-) diff --git a/Documentation/git-reset.txt b/Documentation/git-reset.txt index 1e9ae0ae9f..58d9b4c062 100644 --- a/Documentation/git-reset.txt +++ b/Documentation/git-reset.txt @@ -155,7 +155,8 @@ tree. If there could be conflicts between the changes in the commit we want to remove and the changes in the working tree we want to keep, the reset is disallowed. That's why it is disallowed if there are both changes between the working tree and HEAD, and between HEAD and the -target. +target. To be safe, it is also disallowed when there are unmerged +entries. The following tables show what happens when there are unmerged entries: @@ -174,7 +175,7 @@ entries: --mixed X A A --hard A A A --merge A A A - --keep X A A + --keep (disallowed) X means any state and U means an unmerged index. diff --git a/builtin-reset.c b/builtin-reset.c index 52584afbdf..2c3a69adc6 100644 --- a/builtin-reset.c +++ b/builtin-reset.c @@ -224,6 +224,14 @@ static void prepend_reflog_action(const char *action, char *buf, size_t size) warning("Reflog action message too long: %.*s...", 50, buf); } +static void die_if_unmerged_cache(int reset_type) +{ + if (is_merge() || read_cache() < 0 || unmerged_cache()) + die("Cannot do a %s reset in the middle of a merge.", + reset_type_names[reset_type]); + +} + int cmd_reset(int argc, const char **argv, const char *prefix) { int i = 0, reset_type = NONE, update_ref_status = 0, quiet = 0; @@ -329,11 +337,13 @@ int cmd_reset(int argc, const char **argv, const char *prefix) /* 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 (reset_type == SOFT) { - if (is_merge() || read_cache() < 0 || unmerged_cache()) - die("Cannot do a soft reset in the middle of a merge."); - } else { - int err = reset_index_file(sha1, reset_type, quiet); + if (reset_type == SOFT) + die_if_unmerged_cache(reset_type); + else { + int err; + if (reset_type == KEEP) + die_if_unmerged_cache(reset_type); + err = reset_index_file(sha1, reset_type, quiet); if (reset_type == KEEP) err = err || reset_index_file(sha1, MIXED, quiet); if (err) diff --git a/t/t7110-reset-merge.sh b/t/t7110-reset-merge.sh index 1a9c1c7494..70cdd8e618 100755 --- a/t/t7110-reset-merge.sh +++ b/t/t7110-reset-merge.sh @@ -237,7 +237,7 @@ test_expect_success '"reset --keep HEAD^" fails with pending merge' ' git reset --hard third && test_must_fail git merge branch1 && test_must_fail git reset --keep HEAD^ 2>err.log && - grep file1 err.log | grep "overwritten by merge" + grep "middle of a merge" err.log ' # The next test will test the following: @@ -258,18 +258,15 @@ test_expect_success '"reset --merge HEAD" is ok with pending merge' ' # # working index HEAD target working index HEAD # ---------------------------------------------------- -# file1: X U B B --keep X B B -test_expect_success '"reset --keep HEAD" is ok with pending merge' ' +# file1: X U B B --keep (disallowed) +test_expect_success '"reset --keep HEAD" fails with pending merge' ' git reset --hard third && test_must_fail git merge branch1 && - cat file1 >orig_file1 && - git reset --keep HEAD && - test "$(git rev-parse HEAD)" = "$(git rev-parse third)" && - test -z "$(git diff --cached)" && - test_cmp file1 orig_file1 + test_must_fail git reset --keep HEAD 2>err.log && + grep "middle of a merge" err.log ' -test_expect_success '--merge with added/deleted' ' +test_expect_success '--merge is ok with added/deleted merge' ' git reset --hard third && rm -f file2 && test_must_fail git merge branch3 && @@ -283,7 +280,7 @@ test_expect_success '--merge with added/deleted' ' git diff --exit-code --cached ' -test_expect_success '--keep with added/deleted' ' +test_expect_success '--keep fails with added/deleted merge' ' git reset --hard third && rm -f file2 && test_must_fail git merge branch3 && @@ -291,10 +288,8 @@ test_expect_success '--keep with added/deleted' ' test -f file3 && git diff --exit-code file3 && git diff --exit-code branch3 file3 && - git reset --keep HEAD && - test -f file3 && - ! test -f file2 && - git diff --exit-code --cached + test_must_fail git reset --keep HEAD 2>err.log && + grep "middle of a merge" err.log ' test_done diff --git a/t/t7111-reset-table.sh b/t/t7111-reset-table.sh index 2ebda97828..ce421ad5ac 100755 --- a/t/t7111-reset-table.sh +++ b/t/t7111-reset-table.sh @@ -115,7 +115,7 @@ X U B B soft XXXXX X U B B mixed X B B X U B B hard B B B X U B B merge B B B -X U B B keep X B B +X U B B keep XXXXX EOF test_done From eaf436c09c09a28804697c89f3ff9a7e1ad2361c Mon Sep 17 00:00:00 2001 From: Junio C Hamano Date: Tue, 9 Mar 2010 02:51:16 +0100 Subject: [PATCH 6/6] Documentation: improve description of "git reset --keep" Signed-off-by: Christian Couder Signed-off-by: Junio C Hamano --- Documentation/git-reset.txt | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/Documentation/git-reset.txt b/Documentation/git-reset.txt index 58d9b4c062..645f0c1748 100644 --- a/Documentation/git-reset.txt +++ b/Documentation/git-reset.txt @@ -53,9 +53,12 @@ OPTIONS and the current commit in the working tree. --keep:: - Resets the index to match the tree recorded by the named commit, - but keep changes in the working tree. Aborts if the reset would - change files that are already modified in the working tree. + Reset the index to the given commit, keeping local changes in + the working tree since the current commit, while updating + working tree files without local changes to what appears in + the given commit. If a file that is different between the + current commit and the given commit has local changes, reset + is aborted. -p:: --patch::