Skip to content

Commit

Permalink
reset: allow reset on unborn branch
Browse files Browse the repository at this point in the history
Some users seem to think, knowingly or not, that being on an unborn
branch is like having a commit with an empty tree checked out, but
when run on an unborn branch, "git reset" currently fails with:

  fatal: Failed to resolve 'HEAD' as a valid ref.

Instead of making users figure out that they should run

 git rm --cached -r .

, let's teach "git reset" without a revision argument, when on an
unborn branch, to behave as if the user asked to reset to an empty
tree. Don't take the analogy with an empty commit too far, though, but
still disallow explictly referring to HEAD in "git reset HEAD".

Signed-off-by: Martin von Zweigbergk <martinvonz@gmail.com>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
  • Loading branch information
Martin von Zweigbergk authored and Junio C Hamano committed Jan 15, 2013
1 parent 2f328c3 commit 166ec2e
Show file tree
Hide file tree
Showing 2 changed files with 62 additions and 6 deletions.
16 changes: 10 additions & 6 deletions builtin/reset.c
Original file line number Diff line number Diff line change
Expand Up @@ -240,7 +240,7 @@ static int update_refs(const char *rev, const unsigned char *sha1)
int cmd_reset(int argc, const char **argv, const char *prefix)
{
int reset_type = NONE, update_ref_status = 0, quiet = 0;
int patch_mode = 0;
int patch_mode = 0, unborn;
const char *rev;
unsigned char sha1[20];
const char **pathspec = NULL;
Expand All @@ -265,7 +265,11 @@ int cmd_reset(int argc, const char **argv, const char *prefix)
PARSE_OPT_KEEP_DASHDASH);
pathspec = parse_args(argv, prefix, &rev);

if (!pathspec) {
unborn = !strcmp(rev, "HEAD") && get_sha1("HEAD", sha1);
if (unborn) {
/* reset on unborn branch: treat as reset to empty tree */
hashcpy(sha1, EMPTY_TREE_SHA1_BIN);
} else if (!pathspec) {
struct commit *commit;
if (get_sha1_committish(rev, sha1))
die(_("Failed to resolve '%s' as a valid revision."), rev);
Expand All @@ -286,7 +290,7 @@ int cmd_reset(int argc, const char **argv, const char *prefix)
if (patch_mode) {
if (reset_type != NONE)
die(_("--patch is incompatible with --{hard,mixed,soft}"));
return run_add_interactive(rev, "--patch=reset", pathspec);
return run_add_interactive(sha1_to_hex(sha1), "--patch=reset", pathspec);
}

/* git reset tree [--] paths... can be used to
Expand Down Expand Up @@ -340,16 +344,16 @@ int cmd_reset(int argc, const char **argv, const char *prefix)
die(_("Could not write new index file."));
}

if (!pathspec) {
if (!pathspec && !unborn) {
/* Any resets without paths update HEAD to the head being
* switched to, saving the previous head in ORIG_HEAD before. */
update_ref_status = update_refs(rev, sha1);

if (reset_type == HARD && !update_ref_status && !quiet)
print_new_head_line(lookup_commit_reference(sha1));

remove_branch_state();
}
if (!pathspec)
remove_branch_state();

return update_ref_status;
}
52 changes: 52 additions & 0 deletions t/t7106-reset-unborn-branch.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
#!/bin/sh

test_description='git reset should work on unborn branch'
. ./test-lib.sh

test_expect_success 'setup' '
echo a >a &&
echo b >b
'

test_expect_success 'reset' '
git add a b &&
git reset &&
test "$(git ls-files)" = ""
'

test_expect_success 'reset HEAD' '
rm .git/index &&
git add a b &&
test_must_fail git reset HEAD
'

test_expect_success 'reset $file' '
rm .git/index &&
git add a b &&
git reset a &&
test "$(git ls-files)" = "b"
'

test_expect_success 'reset -p' '
rm .git/index &&
git add a &&
echo y | git reset -p &&
test "$(git ls-files)" = ""
'

test_expect_success 'reset --soft is a no-op' '
rm .git/index &&
git add a &&
git reset --soft
test "$(git ls-files)" = "a"
'

test_expect_success 'reset --hard' '
rm .git/index &&
git add a &&
git reset --hard &&
test "$(git ls-files)" = "" &&
test_path_is_missing a
'

test_done

0 comments on commit 166ec2e

Please sign in to comment.