reset: support "--mixed --intent-to-add" mode
When --mixed is used, entries could be removed from index if the target ref does not have them. When "reset" is used in preparation for commit spliting (in a dirty worktree), it could be hard to track what files to be added back. The new option --intent-to-add simplifies it by marking all removed files intent-to-add. Signed-off-by: Nguyễn Thái Ngọc Duy <pclouds@gmail.com>
Nguyễn Thái Ngọc Duy committed
Feb 4, 2014 at 09:20 UTC
b4b313f94ab06fabe78fa91b3f2ebbc7ef08b012
5 files changed
+50
-15
Documentation/git-reset.txt
+4
-1
@@ -10,7 +10,7 @@ SYNOPSIS
10
[verse]
11
'git reset' [-q] [<tree-ish>] [--] <paths>...
12
'git reset' (--patch | -p) [<tree-ish>] [--] [<paths>...]
13
-'git reset' [--soft | --mixed | --hard | --merge | --keep] [-q] [<commit>]
13
+'git reset' [--soft | --mixed [-N] | --hard | --merge | --keep] [-q] [<commit>]
14
15
DESCRIPTION
16
-----------
@@ -60,6 +60,9 @@ section of linkgit:git-add[1] to learn how to operate the `--patch` mode.
60
Resets the index but not the working tree (i.e., the changed files
61
are preserved but not marked for commit) and reports what has not
62
been updated. This is the default action.
63
++
64
+If `-N` is specified, removed paths are marked as intent-to-add (see
65
+linkgit:git-add[1]).
66
67
--hard::
68
Resets the index and working tree. Any changes to tracked files in the
builtin/reset.c
+28
-12
@@ -116,25 +116,34 @@ static void update_index_from_diff(struct diff_queue_struct *q,
116
struct diff_options *opt, void *data)
117
{
118
int i;
119
+ int intent_to_add = *(int *)data;
120
121
for (i = 0; i < q->nr; i++) {
122
struct diff_filespec *one = q->queue[i]->one;
122
- if (one->mode && !is_null_sha1(one->sha1)) {
123
- struct cache_entry *ce;
124
- ce = make_cache_entry(one->mode, one->sha1, one->path,
125
- 0, 0);
126
- if (!ce)
127
- die(_("make_cache_entry failed for path '%s'"),
128
- one->path);
129
- add_cache_entry(ce, ADD_CACHE_OK_TO_ADD |
130
- ADD_CACHE_OK_TO_REPLACE);
131
- } else
123
+ int is_missing = !(one->mode && !is_null_sha1(one->sha1));
124
+ struct cache_entry *ce;
125
+
126
+ if (is_missing && !intent_to_add) {
127
remove_file_from_cache(one->path);
128
+ continue;
129
+ }
130
+
131
+ ce = make_cache_entry(one->mode, one->sha1, one->path,
132
+ 0, 0);
133
+ if (!ce)
134
+ die(_("make_cache_entry failed for path '%s'"),
135
+ one->path);
136
+ if (is_missing) {
137
+ ce->ce_flags |= CE_INTENT_TO_ADD;
138
+ set_object_name_for_intent_to_add_entry(ce);
139
+ }
140
+ add_cache_entry(ce, ADD_CACHE_OK_TO_ADD | ADD_CACHE_OK_TO_REPLACE);
141
}
142
}
143
144
static int read_from_tree(const struct pathspec *pathspec,
137
- unsigned char *tree_sha1)
145
+ unsigned char *tree_sha1,
146
+ int intent_to_add)
147
{
148
struct diff_options opt;
149
@@ -142,6 +151,7 @@ static int read_from_tree(const struct pathspec *pathspec,
151
copy_pathspec(&opt.pathspec, pathspec);
152
opt.output_format = DIFF_FORMAT_CALLBACK;
153
opt.format_callback = update_index_from_diff;
154
+ opt.format_callback_data = &intent_to_add;
155
156
if (do_diff_cache(tree_sha1, &opt))
157
return 1;
@@ -258,6 +268,7 @@ int cmd_reset(int argc, const char **argv, const char *prefix)
268
const char *rev;
269
unsigned char sha1[20];
270
struct pathspec pathspec;
271
+ int intent_to_add = 0;
272
const struct option options[] = {
273
OPT__QUIET(&quiet, N_("be quiet, only report errors")),
274
OPT_SET_INT(0, "mixed", &reset_type,
@@ -270,6 +281,8 @@ int cmd_reset(int argc, const char **argv, const char *prefix)
281
OPT_SET_INT(0, "keep", &reset_type,
282
N_("reset HEAD but keep local changes"), KEEP),
283
OPT_BOOL('p', "patch", &patch_mode, N_("select hunks interactively")),
284
+ OPT_BOOL('N', "intent-to-add", &intent_to_add,
285
+ N_("record only the fact that removed paths will be added later")),
286
OPT_END()
287
};
288
@@ -327,6 +340,9 @@ int cmd_reset(int argc, const char **argv, const char *prefix)
340
die(_("%s reset is not allowed in a bare repository"),
341
_(reset_type_names[reset_type]));
342
343
+ if (intent_to_add && reset_type != MIXED)
344
+ die(_("-N can only be used with --mixed"));
345
+
346
/* Soft reset does not touch the index file nor the working tree
347
* at all, but requires them in a good order. Other resets reset
348
* the index file to the tree object we are switching to. */
@@ -338,7 +354,7 @@ int cmd_reset(int argc, const char **argv, const char *prefix)
354
int newfd = hold_locked_index(lock, 1);
355
if (reset_type == MIXED) {
356
int flags = quiet ? REFRESH_QUIET : REFRESH_IN_PORCELAIN;
341
- if (read_from_tree(&pathspec, sha1))
357
+ if (read_from_tree(&pathspec, sha1, intent_to_add))
358
return 1;
359
refresh_index(&the_index, flags, NULL, NULL,
360
_("Unstaged changes after reset:"));
cache.h
+1
@@ -489,6 +489,7 @@ extern int add_to_index(struct index_state *, const char *path, struct stat *, i
489
extern int add_file_to_index(struct index_state *, const char *path, int flags);
490
extern struct cache_entry *make_cache_entry(unsigned int mode, const unsigned char *sha1, const char *path, int stage, int refresh);
491
extern int ce_same_name(const struct cache_entry *a, const struct cache_entry *b);
492
+extern void set_object_name_for_intent_to_add_entry(struct cache_entry *ce);
493
extern int index_name_is_other(const struct index_state *, const char *, int);
494
extern void *read_blob_data_from_index(struct index_state *, const char *, unsigned long *);
495
read-cache.c
+2
-2
@@ -579,7 +579,7 @@ static struct cache_entry *create_alias_ce(struct cache_entry *ce, struct cache_
579
return new;
580
}
581
582
-static void record_intent_to_add(struct cache_entry *ce)
582
+void set_object_name_for_intent_to_add_entry(struct cache_entry *ce)
583
{
584
unsigned char sha1[20];
585
if (write_sha1_file("", 0, blob_type, sha1))
@@ -665,7 +665,7 @@ int add_to_index(struct index_state *istate, const char *path, struct stat *st,
665
if (index_path(ce->sha1, path, st, HASH_WRITE_OBJECT))
666
return error("unable to index file %s", path);
667
} else
668
- record_intent_to_add(ce);
668
+ set_object_name_for_intent_to_add_entry(ce);
669
670
if (ignore_case && alias && different_name(ce, alias))
671
ce = create_alias_ce(ce, alias);
t/t7102-reset.sh
+15
@@ -535,4 +535,19 @@ test_expect_success 'reset with paths accepts tree' '
535
git diff HEAD --exit-code
536
'
537
538
+test_expect_success 'reset -N keeps removed files as intent-to-add' '
539
+ echo new-file >new-file &&
540
+ git add new-file &&
541
+ git reset -N HEAD &&
542
+
543
+ tree=$(git write-tree) &&
544
+ git ls-tree $tree new-file >actual &&
545
+ >expect &&
546
+ test_cmp expect actual &&
547
+
548
+ git diff --name-only >actual &&
549
+ echo new-file >expect &&
550
+ test_cmp expect actual
551
+'
552
+
553
test_done