зеркало из https://github.com/microsoft/git.git
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>
This commit is contained in:
Родитель
be961c292f
Коммит
b4b313f94a
|
@ -10,7 +10,7 @@ SYNOPSIS
|
|||
[verse]
|
||||
'git reset' [-q] [<tree-ish>] [--] <paths>...
|
||||
'git reset' (--patch | -p) [<tree-ish>] [--] [<paths>...]
|
||||
'git reset' [--soft | --mixed | --hard | --merge | --keep] [-q] [<commit>]
|
||||
'git reset' [--soft | --mixed [-N] | --hard | --merge | --keep] [-q] [<commit>]
|
||||
|
||||
DESCRIPTION
|
||||
-----------
|
||||
|
@ -60,6 +60,9 @@ section of linkgit:git-add[1] to learn how to operate the `--patch` mode.
|
|||
Resets the index but not the working tree (i.e., the changed files
|
||||
are preserved but not marked for commit) and reports what has not
|
||||
been updated. This is the default action.
|
||||
+
|
||||
If `-N` is specified, removed paths are marked as intent-to-add (see
|
||||
linkgit:git-add[1]).
|
||||
|
||||
--hard::
|
||||
Resets the index and working tree. Any changes to tracked files in the
|
||||
|
|
|
@ -116,25 +116,34 @@ static void update_index_from_diff(struct diff_queue_struct *q,
|
|||
struct diff_options *opt, void *data)
|
||||
{
|
||||
int i;
|
||||
int intent_to_add = *(int *)data;
|
||||
|
||||
for (i = 0; i < q->nr; i++) {
|
||||
struct diff_filespec *one = q->queue[i]->one;
|
||||
if (one->mode && !is_null_sha1(one->sha1)) {
|
||||
struct cache_entry *ce;
|
||||
ce = make_cache_entry(one->mode, one->sha1, one->path,
|
||||
0, 0);
|
||||
if (!ce)
|
||||
die(_("make_cache_entry failed for path '%s'"),
|
||||
one->path);
|
||||
add_cache_entry(ce, ADD_CACHE_OK_TO_ADD |
|
||||
ADD_CACHE_OK_TO_REPLACE);
|
||||
} else
|
||||
int is_missing = !(one->mode && !is_null_sha1(one->sha1));
|
||||
struct cache_entry *ce;
|
||||
|
||||
if (is_missing && !intent_to_add) {
|
||||
remove_file_from_cache(one->path);
|
||||
continue;
|
||||
}
|
||||
|
||||
ce = make_cache_entry(one->mode, one->sha1, one->path,
|
||||
0, 0);
|
||||
if (!ce)
|
||||
die(_("make_cache_entry failed for path '%s'"),
|
||||
one->path);
|
||||
if (is_missing) {
|
||||
ce->ce_flags |= CE_INTENT_TO_ADD;
|
||||
set_object_name_for_intent_to_add_entry(ce);
|
||||
}
|
||||
add_cache_entry(ce, ADD_CACHE_OK_TO_ADD | ADD_CACHE_OK_TO_REPLACE);
|
||||
}
|
||||
}
|
||||
|
||||
static int read_from_tree(const struct pathspec *pathspec,
|
||||
unsigned char *tree_sha1)
|
||||
unsigned char *tree_sha1,
|
||||
int intent_to_add)
|
||||
{
|
||||
struct diff_options opt;
|
||||
|
||||
|
@ -142,6 +151,7 @@ static int read_from_tree(const struct pathspec *pathspec,
|
|||
copy_pathspec(&opt.pathspec, pathspec);
|
||||
opt.output_format = DIFF_FORMAT_CALLBACK;
|
||||
opt.format_callback = update_index_from_diff;
|
||||
opt.format_callback_data = &intent_to_add;
|
||||
|
||||
if (do_diff_cache(tree_sha1, &opt))
|
||||
return 1;
|
||||
|
@ -258,6 +268,7 @@ int cmd_reset(int argc, const char **argv, const char *prefix)
|
|||
const char *rev;
|
||||
unsigned char sha1[20];
|
||||
struct pathspec pathspec;
|
||||
int intent_to_add = 0;
|
||||
const struct option options[] = {
|
||||
OPT__QUIET(&quiet, N_("be quiet, only report errors")),
|
||||
OPT_SET_INT(0, "mixed", &reset_type,
|
||||
|
@ -270,6 +281,8 @@ int cmd_reset(int argc, const char **argv, const char *prefix)
|
|||
OPT_SET_INT(0, "keep", &reset_type,
|
||||
N_("reset HEAD but keep local changes"), KEEP),
|
||||
OPT_BOOL('p', "patch", &patch_mode, N_("select hunks interactively")),
|
||||
OPT_BOOL('N', "intent-to-add", &intent_to_add,
|
||||
N_("record only the fact that removed paths will be added later")),
|
||||
OPT_END()
|
||||
};
|
||||
|
||||
|
@ -327,6 +340,9 @@ int cmd_reset(int argc, const char **argv, const char *prefix)
|
|||
die(_("%s reset is not allowed in a bare repository"),
|
||||
_(reset_type_names[reset_type]));
|
||||
|
||||
if (intent_to_add && reset_type != MIXED)
|
||||
die(_("-N can only be used with --mixed"));
|
||||
|
||||
/* Soft reset does not touch the index file nor the working tree
|
||||
* at all, but requires them in a good order. Other resets reset
|
||||
* 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)
|
|||
int newfd = hold_locked_index(lock, 1);
|
||||
if (reset_type == MIXED) {
|
||||
int flags = quiet ? REFRESH_QUIET : REFRESH_IN_PORCELAIN;
|
||||
if (read_from_tree(&pathspec, sha1))
|
||||
if (read_from_tree(&pathspec, sha1, intent_to_add))
|
||||
return 1;
|
||||
refresh_index(&the_index, flags, NULL, NULL,
|
||||
_("Unstaged changes after reset:"));
|
||||
|
|
1
cache.h
1
cache.h
|
@ -489,6 +489,7 @@ extern int add_to_index(struct index_state *, const char *path, struct stat *, i
|
|||
extern int add_file_to_index(struct index_state *, const char *path, int flags);
|
||||
extern struct cache_entry *make_cache_entry(unsigned int mode, const unsigned char *sha1, const char *path, int stage, int refresh);
|
||||
extern int ce_same_name(const struct cache_entry *a, const struct cache_entry *b);
|
||||
extern void set_object_name_for_intent_to_add_entry(struct cache_entry *ce);
|
||||
extern int index_name_is_other(const struct index_state *, const char *, int);
|
||||
extern void *read_blob_data_from_index(struct index_state *, const char *, unsigned long *);
|
||||
|
||||
|
|
|
@ -579,7 +579,7 @@ static struct cache_entry *create_alias_ce(struct cache_entry *ce, struct cache_
|
|||
return new;
|
||||
}
|
||||
|
||||
static void record_intent_to_add(struct cache_entry *ce)
|
||||
void set_object_name_for_intent_to_add_entry(struct cache_entry *ce)
|
||||
{
|
||||
unsigned char sha1[20];
|
||||
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,
|
|||
if (index_path(ce->sha1, path, st, HASH_WRITE_OBJECT))
|
||||
return error("unable to index file %s", path);
|
||||
} else
|
||||
record_intent_to_add(ce);
|
||||
set_object_name_for_intent_to_add_entry(ce);
|
||||
|
||||
if (ignore_case && alias && different_name(ce, alias))
|
||||
ce = create_alias_ce(ce, alias);
|
||||
|
|
|
@ -535,4 +535,19 @@ test_expect_success 'reset with paths accepts tree' '
|
|||
git diff HEAD --exit-code
|
||||
'
|
||||
|
||||
test_expect_success 'reset -N keeps removed files as intent-to-add' '
|
||||
echo new-file >new-file &&
|
||||
git add new-file &&
|
||||
git reset -N HEAD &&
|
||||
|
||||
tree=$(git write-tree) &&
|
||||
git ls-tree $tree new-file >actual &&
|
||||
>expect &&
|
||||
test_cmp expect actual &&
|
||||
|
||||
git diff --name-only >actual &&
|
||||
echo new-file >expect &&
|
||||
test_cmp expect actual
|
||||
'
|
||||
|
||||
test_done
|
||||
|
|
Загрузка…
Ссылка в новой задаче