Skip to content

Commit b4b313f

Browse files
pcloudsgitster
authored andcommitted
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 <[email protected]>
1 parent be961c2 commit b4b313f

File tree

5 files changed

+50
-15
lines changed

5 files changed

+50
-15
lines changed

Documentation/git-reset.txt

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@ SYNOPSIS
1010
[verse]
1111
'git reset' [-q] [<tree-ish>] [--] <paths>...
1212
'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>]
1414

1515
DESCRIPTION
1616
-----------
@@ -60,6 +60,9 @@ section of linkgit:git-add[1] to learn how to operate the `--patch` mode.
6060
Resets the index but not the working tree (i.e., the changed files
6161
are preserved but not marked for commit) and reports what has not
6262
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]).
6366

6467
--hard::
6568
Resets the index and working tree. Any changes to tracked files in the

builtin/reset.c

Lines changed: 28 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -116,32 +116,42 @@ static void update_index_from_diff(struct diff_queue_struct *q,
116116
struct diff_options *opt, void *data)
117117
{
118118
int i;
119+
int intent_to_add = *(int *)data;
119120

120121
for (i = 0; i < q->nr; i++) {
121122
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) {
132127
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);
133141
}
134142
}
135143

136144
static int read_from_tree(const struct pathspec *pathspec,
137-
unsigned char *tree_sha1)
145+
unsigned char *tree_sha1,
146+
int intent_to_add)
138147
{
139148
struct diff_options opt;
140149

141150
memset(&opt, 0, sizeof(opt));
142151
copy_pathspec(&opt.pathspec, pathspec);
143152
opt.output_format = DIFF_FORMAT_CALLBACK;
144153
opt.format_callback = update_index_from_diff;
154+
opt.format_callback_data = &intent_to_add;
145155

146156
if (do_diff_cache(tree_sha1, &opt))
147157
return 1;
@@ -258,6 +268,7 @@ int cmd_reset(int argc, const char **argv, const char *prefix)
258268
const char *rev;
259269
unsigned char sha1[20];
260270
struct pathspec pathspec;
271+
int intent_to_add = 0;
261272
const struct option options[] = {
262273
OPT__QUIET(&quiet, N_("be quiet, only report errors")),
263274
OPT_SET_INT(0, "mixed", &reset_type,
@@ -270,6 +281,8 @@ int cmd_reset(int argc, const char **argv, const char *prefix)
270281
OPT_SET_INT(0, "keep", &reset_type,
271282
N_("reset HEAD but keep local changes"), KEEP),
272283
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")),
273286
OPT_END()
274287
};
275288

@@ -327,6 +340,9 @@ int cmd_reset(int argc, const char **argv, const char *prefix)
327340
die(_("%s reset is not allowed in a bare repository"),
328341
_(reset_type_names[reset_type]));
329342

343+
if (intent_to_add && reset_type != MIXED)
344+
die(_("-N can only be used with --mixed"));
345+
330346
/* Soft reset does not touch the index file nor the working tree
331347
* at all, but requires them in a good order. Other resets reset
332348
* 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)
338354
int newfd = hold_locked_index(lock, 1);
339355
if (reset_type == MIXED) {
340356
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))
342358
return 1;
343359
refresh_index(&the_index, flags, NULL, NULL,
344360
_("Unstaged changes after reset:"));

cache.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -489,6 +489,7 @@ extern int add_to_index(struct index_state *, const char *path, struct stat *, i
489489
extern int add_file_to_index(struct index_state *, const char *path, int flags);
490490
extern struct cache_entry *make_cache_entry(unsigned int mode, const unsigned char *sha1, const char *path, int stage, int refresh);
491491
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);
492493
extern int index_name_is_other(const struct index_state *, const char *, int);
493494
extern void *read_blob_data_from_index(struct index_state *, const char *, unsigned long *);
494495

read-cache.c

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -579,7 +579,7 @@ static struct cache_entry *create_alias_ce(struct cache_entry *ce, struct cache_
579579
return new;
580580
}
581581

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)
583583
{
584584
unsigned char sha1[20];
585585
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,
665665
if (index_path(ce->sha1, path, st, HASH_WRITE_OBJECT))
666666
return error("unable to index file %s", path);
667667
} else
668-
record_intent_to_add(ce);
668+
set_object_name_for_intent_to_add_entry(ce);
669669

670670
if (ignore_case && alias && different_name(ce, alias))
671671
ce = create_alias_ce(ce, alias);

t/t7102-reset.sh

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -535,4 +535,19 @@ test_expect_success 'reset with paths accepts tree' '
535535
git diff HEAD --exit-code
536536
'
537537

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+
538553
test_done

0 commit comments

Comments
 (0)