Skip to content

Commit a7c2daa

Browse files
committed
Merge branch 'en/removing-untracked-fixes'
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 Change unpack_trees' 'reset' flag into an enum Remove ignored files by default when they are in the way unpack-trees: make dir an internal-only struct unpack-trees: introduce preserve_ignored to unpack_trees_options read-tree, merge-recursive: overwrite ignored files by default checkout, read-tree: fix leak of unpack_trees_options.dir t2500: add various tests for nuking untracked files
2 parents 1fdfb77 + 0e29222 commit a7c2daa

23 files changed

+366
-74
lines changed

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: 4 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -10,8 +10,7 @@ SYNOPSIS
1010
--------
1111
[verse]
1212
'git read-tree' [[-m [--trivial] [--aggressive] | --reset | --prefix=<prefix>]
13-
[-u [--exclude-per-directory=<gitignore>] | -i]]
14-
[--index-output=<file>] [--no-sparse-checkout]
13+
[-u | -i]] [--index-output=<file>] [--no-sparse-checkout]
1514
(--empty | <tree-ish1> [<tree-ish2> [<tree-ish3>]])
1615

1716

@@ -39,8 +38,9 @@ OPTIONS
3938

4039
--reset::
4140
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.
41+
of failing. When used with `-u`, updates leading to loss of
42+
working tree changes or untracked files or directories will not
43+
abort the operation.
4444

4545
-u::
4646
After a successful merge, update the files in the work
@@ -88,21 +88,6 @@ OPTIONS
8888
The command will refuse to overwrite entries that already
8989
existed in the original index file.
9090

91-
--exclude-per-directory=<gitignore>::
92-
When running the command with `-u` and `-m` options, the
93-
merge result may need to overwrite paths that are not
94-
tracked in the current branch. The command usually
95-
refuses to proceed with the merge to avoid losing such a
96-
path. However this safety valve sometimes gets in the
97-
way. For example, it often happens that the other
98-
branch added a file that used to be a generated file in
99-
your branch, and the safety valve triggers when you try
100-
to switch to that branch after you ran `make` but before
101-
running `make clean` to remove the generated file. This
102-
option tells the command to read per-directory exclude
103-
file (usually '.gitignore') and allows such an untracked
104-
but explicitly ignored file to be overwritten.
105-
10691
--index-output=<file>::
10792
Instead of writing the results out to `$GIT_INDEX_FILE`,
10893
write the resulting index in the named file. While the

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: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1917,7 +1917,8 @@ 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 = reset ? UNPACK_RESET_PROTECT_UNTRACKED : 0;
1921+
opts.preserve_ignored = 0; /* FIXME: !overwrite_ignore */
19211922
opts.fn = twoway_merge;
19221923
init_tree_desc(&t[0], head->buffer, head->size);
19231924
init_tree_desc(&t[1], remote->buffer, remote->size);

builtin/checkout.c

Lines changed: 4 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -646,7 +646,9 @@ 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+
opts.reset = o->force ? UNPACK_RESET_OVERWRITE_UNTRACKED :
650+
UNPACK_RESET_PROTECT_UNTRACKED;
651+
opts.preserve_ignored = (!o->force && !o->overwrite_ignore);
650652
opts.merge = 1;
651653
opts.fn = oneway_merge;
652654
opts.verbose_update = o->show_progress;
@@ -746,11 +748,7 @@ static int merge_working_tree(const struct checkout_opts *opts,
746748
new_branch_info->commit ?
747749
&new_branch_info->commit->object.oid :
748750
&new_branch_info->oid, NULL);
749-
if (opts->overwrite_ignore) {
750-
topts.dir = xcalloc(1, sizeof(*topts.dir));
751-
topts.dir->flags |= DIR_SHOW_IGNORED;
752-
setup_standard_excludes(topts.dir);
753-
}
751+
topts.preserve_ignored = !opts->overwrite_ignore;
754752
tree = parse_tree_indirect(old_branch_info->commit ?
755753
&old_branch_info->commit->object.oid :
756754
the_hash_algo->empty_tree);

builtin/clone.c

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -687,6 +687,7 @@ static int checkout(int submodule_progress)
687687
opts.update = 1;
688688
opts.merge = 1;
689689
opts.clone = 1;
690+
opts.preserve_ignored = 0;
690691
opts.fn = oneway_merge;
691692
opts.verbose_update = (option_verbosity >= 0);
692693
opts.src_index = &the_index;

builtin/merge.c

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -680,6 +680,7 @@ static int read_tree_trivial(struct object_id *common, struct object_id *head,
680680
opts.verbose_update = 1;
681681
opts.trivial_merges_only = 1;
682682
opts.merge = 1;
683+
opts.preserve_ignored = 0; /* FIXME: !overwrite_ignore */
683684
trees[nr_trees] = parse_tree_indirect(common);
684685
if (!trees[nr_trees++])
685686
return -1;

builtin/read-tree.c

Lines changed: 11 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -38,7 +38,7 @@ static int list_tree(struct object_id *oid)
3838
}
3939

4040
static const char * const read_tree_usage[] = {
41-
N_("git read-tree [(-m [--trivial] [--aggressive] | --reset | --prefix=<prefix>) [-u [--exclude-per-directory=<gitignore>] | -i]] [--no-sparse-checkout] [--index-output=<file>] (--empty | <tree-ish1> [<tree-ish2> [<tree-ish3>]])"),
41+
N_("git read-tree [(-m [--trivial] [--aggressive] | --reset | --prefix=<prefix>) [-u | -i]] [--no-sparse-checkout] [--index-output=<file>] (--empty | <tree-ish1> [<tree-ish2> [<tree-ish3>]])"),
4242
NULL
4343
};
4444

@@ -53,24 +53,16 @@ static int index_output_cb(const struct option *opt, const char *arg,
5353
static int exclude_per_directory_cb(const struct option *opt, const char *arg,
5454
int unset)
5555
{
56-
struct dir_struct *dir;
5756
struct unpack_trees_options *opts;
5857

5958
BUG_ON_OPT_NEG(unset);
6059

6160
opts = (struct unpack_trees_options *)opt->value;
6261

63-
if (opts->dir)
64-
die("more than one --exclude-per-directory given.");
65-
66-
dir = xcalloc(1, sizeof(*opts->dir));
67-
dir->flags |= DIR_SHOW_IGNORED;
68-
dir->exclude_per_dir = arg;
69-
opts->dir = dir;
70-
/* We do not need to nor want to do read-directory
71-
* here; we are merely interested in reusing the
72-
* per directory ignore stack mechanism.
73-
*/
62+
if (!opts->update)
63+
die("--exclude-per-directory is meaningless unless -u");
64+
if (strcmp(arg, ".gitignore"))
65+
die("--exclude-per-directory argument must be .gitignore");
7466
return 0;
7567
}
7668

@@ -174,6 +166,9 @@ int cmd_read_tree(int argc, const char **argv, const char *cmd_prefix)
174166
if (1 < opts.merge + opts.reset + prefix_set)
175167
die("Which one? -m, --reset, or --prefix?");
176168

169+
if (opts.reset)
170+
opts.reset = UNPACK_RESET_OVERWRITE_UNTRACKED;
171+
177172
/*
178173
* NEEDSWORK
179174
*
@@ -209,8 +204,9 @@ int cmd_read_tree(int argc, const char **argv, const char *cmd_prefix)
209204
if ((opts.update || opts.index_only) && !opts.merge)
210205
die("%s is meaningless without -m, --reset, or --prefix",
211206
opts.update ? "-u" : "-i");
212-
if ((opts.dir && !opts.update))
213-
die("--exclude-per-directory is meaningless unless -u");
207+
if (opts.update && !opts.reset)
208+
opts.preserve_ignored = 0;
209+
/* otherwise, opts.preserve_ignored is irrelevant */
214210
if (opts.merge && !opts.index_only)
215211
setup_work_tree();
216212

builtin/reset.c

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -67,12 +67,18 @@ static int reset_index(const char *ref, const struct object_id *oid, int reset_t
6767
case KEEP:
6868
case MERGE:
6969
opts.update = 1;
70+
opts.preserve_ignored = 0; /* FIXME: !overwrite_ignore */
7071
break;
7172
case HARD:
7273
opts.update = 1;
73-
/* fallthrough */
74+
opts.reset = UNPACK_RESET_OVERWRITE_UNTRACKED;
75+
break;
76+
case MIXED:
77+
opts.reset = UNPACK_RESET_PROTECT_UNTRACKED;
78+
/* but opts.update=0, so working tree not updated */
79+
break;
7480
default:
75-
opts.reset = 1;
81+
BUG("invalid reset_type passed to reset_index");
7682
}
7783

7884
read_cache_unmerged();

builtin/stash.c

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -256,8 +256,10 @@ 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 = reset ? UNPACK_RESET_PROTECT_UNTRACKED : 0;
260260
opts.update = update;
261+
if (update)
262+
opts.preserve_ignored = 0; /* FIXME: !overwrite_ignore */
261263
opts.fn = oneway_merge;
262264

263265
if (unpack_trees(nr_trees, t, &opts))
@@ -1533,6 +1535,7 @@ static int do_push_stash(const struct pathspec *ps, const char *stash_msg, int q
15331535
} else {
15341536
struct child_process cp = CHILD_PROCESS_INIT;
15351537
cp.git_cmd = 1;
1538+
/* BUG: this nukes untracked files in the way */
15361539
strvec_pushl(&cp.args, "reset", "--hard", "-q",
15371540
"--no-recurse-submodules", NULL);
15381541
if (run_command(&cp)) {

0 commit comments

Comments
 (0)