Skip to content

Commit 166ec2e

Browse files
martinvonzgitster
authored andcommitted
reset: allow reset on unborn branch
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 <[email protected]> Signed-off-by: Junio C Hamano <[email protected]>
1 parent 2f328c3 commit 166ec2e

File tree

2 files changed

+62
-6
lines changed

2 files changed

+62
-6
lines changed

builtin/reset.c

Lines changed: 10 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -240,7 +240,7 @@ static int update_refs(const char *rev, const unsigned char *sha1)
240240
int cmd_reset(int argc, const char **argv, const char *prefix)
241241
{
242242
int reset_type = NONE, update_ref_status = 0, quiet = 0;
243-
int patch_mode = 0;
243+
int patch_mode = 0, unborn;
244244
const char *rev;
245245
unsigned char sha1[20];
246246
const char **pathspec = NULL;
@@ -265,7 +265,11 @@ int cmd_reset(int argc, const char **argv, const char *prefix)
265265
PARSE_OPT_KEEP_DASHDASH);
266266
pathspec = parse_args(argv, prefix, &rev);
267267

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

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

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

348352
if (reset_type == HARD && !update_ref_status && !quiet)
349353
print_new_head_line(lookup_commit_reference(sha1));
350-
351-
remove_branch_state();
352354
}
355+
if (!pathspec)
356+
remove_branch_state();
353357

354358
return update_ref_status;
355359
}

t/t7106-reset-unborn-branch.sh

Lines changed: 52 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,52 @@
1+
#!/bin/sh
2+
3+
test_description='git reset should work on unborn branch'
4+
. ./test-lib.sh
5+
6+
test_expect_success 'setup' '
7+
echo a >a &&
8+
echo b >b
9+
'
10+
11+
test_expect_success 'reset' '
12+
git add a b &&
13+
git reset &&
14+
test "$(git ls-files)" = ""
15+
'
16+
17+
test_expect_success 'reset HEAD' '
18+
rm .git/index &&
19+
git add a b &&
20+
test_must_fail git reset HEAD
21+
'
22+
23+
test_expect_success 'reset $file' '
24+
rm .git/index &&
25+
git add a b &&
26+
git reset a &&
27+
test "$(git ls-files)" = "b"
28+
'
29+
30+
test_expect_success 'reset -p' '
31+
rm .git/index &&
32+
git add a &&
33+
echo y | git reset -p &&
34+
test "$(git ls-files)" = ""
35+
'
36+
37+
test_expect_success 'reset --soft is a no-op' '
38+
rm .git/index &&
39+
git add a &&
40+
git reset --soft
41+
test "$(git ls-files)" = "a"
42+
'
43+
44+
test_expect_success 'reset --hard' '
45+
rm .git/index &&
46+
git add a &&
47+
git reset --hard &&
48+
test "$(git ls-files)" = "" &&
49+
test_path_is_missing a
50+
'
51+
52+
test_done

0 commit comments

Comments
 (0)