Skip to content

Commit 0100454

Browse files
committed
Merge branch 'en/removing-untracked-fixes' into seen
Various fixes in code paths that move untracked files away to make room. * en/removing-untracked-fixes: Documentation: call out commands that nuke untracked files/directories Comment important codepaths regarding nuking untracked files/dirs unpack-trees: avoid nuking untracked dir in way of locally deleted file unpack-trees: avoid nuking untracked dir in way of unmerged file Split unpack_trees 'reset' flag into two for untracked handling t2500: add various tests for nuking untracked files
2 parents 41bcff6 + aaeef84 commit 0100454

17 files changed

Lines changed: 359 additions & 28 deletions

Documentation/git-checkout.txt

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -118,8 +118,9 @@ OPTIONS
118118
-f::
119119
--force::
120120
When switching branches, proceed even if the index or the
121-
working tree differs from `HEAD`. This is used to throw away
122-
local changes.
121+
working tree differs from `HEAD`, and even if there are untracked
122+
files in the way. This is used to throw away local changes and
123+
any untracked files or directories that are in the way.
123124
+
124125
When checking out paths from the index, do not fail upon unmerged
125126
entries; instead, unmerged entries are ignored.

Documentation/git-read-tree.txt

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -39,8 +39,9 @@ OPTIONS
3939

4040
--reset::
4141
Same as -m, except that unmerged entries are discarded instead
42-
of failing. When used with `-u`, updates leading to loss of
43-
working tree changes will not abort the operation.
42+
of failing. When used with `-u`, updates leading to loss of
43+
working tree changes or untracked files or directories will not
44+
abort the operation.
4445

4546
-u::
4647
After a successful merge, update the files in the work

Documentation/git-reset.txt

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -69,7 +69,8 @@ linkgit:git-add[1]).
6969

7070
--hard::
7171
Resets the index and working tree. Any changes to tracked files in the
72-
working tree since `<commit>` are discarded.
72+
working tree since `<commit>` are discarded. Any untracked files or
73+
directories in the way of writing any tracked files are simply deleted.
7374

7475
--merge::
7576
Resets the index and updates the files in the working tree that are

builtin/am.c

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1917,8 +1917,12 @@ static int fast_forward_to(struct tree *head, struct tree *remote, int reset)
19171917
opts.dst_index = &the_index;
19181918
opts.update = 1;
19191919
opts.merge = 1;
1920-
opts.reset = reset;
1920+
opts.reset_keep_untracked = reset;
19211921
opts.fn = twoway_merge;
1922+
/* Setup opts.dir so that ignored files in the way get overwritten */
1923+
opts.dir = xcalloc(1, sizeof(*opts.dir));
1924+
opts.dir->flags |= DIR_SHOW_IGNORED;
1925+
setup_standard_excludes(opts.dir);
19221926
init_tree_desc(&t[0], head->buffer, head->size);
19231927
init_tree_desc(&t[1], remote->buffer, remote->size);
19241928

builtin/checkout.c

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -646,12 +646,20 @@ static int reset_tree(struct tree *tree, const struct checkout_opts *o,
646646
opts.head_idx = -1;
647647
opts.update = worktree;
648648
opts.skip_unmerged = !worktree;
649-
opts.reset = 1;
649+
if (o->force)
650+
opts.reset_nuke_untracked = 1;
651+
else
652+
opts.reset_keep_untracked = 1;
650653
opts.merge = 1;
651654
opts.fn = oneway_merge;
652655
opts.verbose_update = o->show_progress;
653656
opts.src_index = &the_index;
654657
opts.dst_index = &the_index;
658+
if (o->overwrite_ignore) {
659+
opts.dir = xcalloc(1, sizeof(*opts.dir));
660+
opts.dir->flags |= DIR_SHOW_IGNORED;
661+
setup_standard_excludes(opts.dir);
662+
}
655663
init_checkout_metadata(&opts.meta, info->refname,
656664
info->commit ? &info->commit->object.oid : null_oid(),
657665
NULL);

builtin/read-tree.c

Lines changed: 8 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -133,7 +133,7 @@ int cmd_read_tree(int argc, const char **argv, const char *cmd_prefix)
133133
N_("3-way merge if no file level merging required")),
134134
OPT_BOOL(0, "aggressive", &opts.aggressive,
135135
N_("3-way merge in presence of adds and removes")),
136-
OPT_BOOL(0, "reset", &opts.reset,
136+
OPT_BOOL(0, "reset", &opts.reset_keep_untracked,
137137
N_("same as -m, but discard unmerged entries")),
138138
{ OPTION_STRING, 0, "prefix", &opts.prefix, N_("<subdirectory>/"),
139139
N_("read the tree into the index under <subdirectory>/"),
@@ -162,6 +162,11 @@ int cmd_read_tree(int argc, const char **argv, const char *cmd_prefix)
162162
opts.head_idx = -1;
163163
opts.src_index = &the_index;
164164
opts.dst_index = &the_index;
165+
if (opts.reset_keep_untracked) {
166+
opts.dir = xcalloc(1, sizeof(*opts.dir));
167+
opts.dir->flags |= DIR_SHOW_IGNORED;
168+
setup_standard_excludes(opts.dir);
169+
}
165170

166171
git_config(git_read_tree_config, NULL);
167172

@@ -171,7 +176,7 @@ int cmd_read_tree(int argc, const char **argv, const char *cmd_prefix)
171176
hold_locked_index(&lock_file, LOCK_DIE_ON_ERROR);
172177

173178
prefix_set = opts.prefix ? 1 : 0;
174-
if (1 < opts.merge + opts.reset + prefix_set)
179+
if (1 < opts.merge + opts.reset_keep_untracked + prefix_set)
175180
die("Which one? -m, --reset, or --prefix?");
176181

177182
/*
@@ -183,7 +188,7 @@ int cmd_read_tree(int argc, const char **argv, const char *cmd_prefix)
183188
* mode.
184189
*/
185190

186-
if (opts.reset || opts.merge || opts.prefix) {
191+
if (opts.reset_keep_untracked || opts.merge || opts.prefix) {
187192
if (read_cache_unmerged() && (opts.prefix || opts.merge))
188193
die(_("You need to resolve your current index first"));
189194
stage = opts.merge = 1;

builtin/reset.c

Lines changed: 13 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@
1010
#define USE_THE_INDEX_COMPATIBILITY_MACROS
1111
#include "builtin.h"
1212
#include "config.h"
13+
#include "dir.h"
1314
#include "lockfile.h"
1415
#include "tag.h"
1516
#include "object.h"
@@ -70,9 +71,19 @@ static int reset_index(const char *ref, const struct object_id *oid, int reset_t
7071
break;
7172
case HARD:
7273
opts.update = 1;
73-
/* fallthrough */
74+
opts.reset_nuke_untracked = 1;
75+
break;
76+
case MIXED:
77+
opts.reset_keep_untracked = 1; /* but opts.update=0, so untracked left alone */
78+
break;
7479
default:
75-
opts.reset = 1;
80+
BUG("invalid reset_type passed to reset_index");
81+
}
82+
if (opts.reset_keep_untracked) {
83+
/* Setup opts.dir so we can overwrite ignored files */
84+
opts.dir = xcalloc(1, sizeof(*opts.dir));
85+
opts.dir->flags |= DIR_SHOW_IGNORED;
86+
setup_standard_excludes(opts.dir);
7687
}
7788

7889
read_cache_unmerged();

builtin/stash.c

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -256,7 +256,7 @@ static int reset_tree(struct object_id *i_tree, int update, int reset)
256256
opts.src_index = &the_index;
257257
opts.dst_index = &the_index;
258258
opts.merge = 1;
259-
opts.reset = reset;
259+
opts.reset_keep_untracked = reset;
260260
opts.update = update;
261261
opts.fn = oneway_merge;
262262

@@ -1533,6 +1533,7 @@ static int do_push_stash(const struct pathspec *ps, const char *stash_msg, int q
15331533
} else {
15341534
struct child_process cp = CHILD_PROCESS_INIT;
15351535
cp.git_cmd = 1;
1536+
/* BUG: this nukes untracked files in the way */
15361537
strvec_pushl(&cp.args, "reset", "--hard", "-q",
15371538
"--no-recurse-submodules", NULL);
15381539
if (run_command(&cp)) {

builtin/submodule--helper.c

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3098,6 +3098,10 @@ static int add_submodule(const struct add_data *add_data)
30983098
prepare_submodule_repo_env(&cp.env_array);
30993099
cp.git_cmd = 1;
31003100
cp.dir = add_data->sm_path;
3101+
/*
3102+
* NOTE: we only get here if add_data->force is true, so
3103+
* passing --force to checkout is reasonable.
3104+
*/
31013105
strvec_pushl(&cp.args, "checkout", "-f", "-q", NULL);
31023106

31033107
if (add_data->branch) {

builtin/worktree.c

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -356,6 +356,11 @@ static int add_worktree(const char *path, const char *refname,
356356
if (opts->checkout) {
357357
cp.argv = NULL;
358358
strvec_clear(&cp.args);
359+
/*
360+
* NOTE: reset --hard is okay here, because 'worktree add'
361+
* refuses to work in an extant non-empty directory, so there
362+
* is no risk of deleting untracked files.
363+
*/
359364
strvec_pushl(&cp.args, "reset", "--hard", "--no-recurse-submodules", NULL);
360365
if (opts->quiet)
361366
strvec_push(&cp.args, "--quiet");

0 commit comments

Comments
 (0)