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 <martinvonz@gmail.com> Signed-off-by: Junio C Hamano <gitster@pobox.com>
Martin von Zweigbergk committed
Jan 14, 2013 at 21:47 UTC
166ec2e96e31bac913f44823dadd6c732d353172
2 files changed
+62
-6
builtin/reset.c
+10
-6
@@ -240,7 +240,7 @@ static int update_refs(const char *rev, const unsigned char *sha1)
240
int cmd_reset(int argc, const char **argv, const char *prefix)
241
{
242
int reset_type = NONE, update_ref_status = 0, quiet = 0;
243
- int patch_mode = 0;
243
+ int patch_mode = 0, unborn;
244
const char *rev;
245
unsigned char sha1[20];
246
const char **pathspec = NULL;
@@ -265,7 +265,11 @@ int cmd_reset(int argc, const char **argv, const char *prefix)
265
PARSE_OPT_KEEP_DASHDASH);
266
pathspec = parse_args(argv, prefix, &rev);
267
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) {
273
struct commit *commit;
274
if (get_sha1_committish(rev, sha1))
275
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)
290
if (patch_mode) {
291
if (reset_type != NONE)
292
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);
294
}
295
296
/* git reset tree [--] paths... can be used to
@@ -340,16 +344,16 @@ int cmd_reset(int argc, const char **argv, const char *prefix)
344
die(_("Could not write new index file."));
345
}
346
343
- if (!pathspec) {
347
+ if (!pathspec && !unborn) {
348
/* Any resets without paths update HEAD to the head being
349
* switched to, saving the previous head in ORIG_HEAD before. */
350
update_ref_status = update_refs(rev, sha1);
351
352
if (reset_type == HARD && !update_ref_status && !quiet)
353
print_new_head_line(lookup_commit_reference(sha1));
350
-
351
- remove_branch_state();
354
}
355
+ if (!pathspec)
356
+ remove_branch_state();
357
358
return update_ref_status;
359
}
t/t7106-reset-unborn-branch.sh
new
+52
@@ -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