Skip to content

Commit 491a757

Browse files
newrengitster
authored andcommitted
read-tree, merge-recursive: overwrite ignored files by default
This fixes a long-standing patchwork of ignored files handling in read-tree and merge-recursive, called out and suggested by Junio long ago. Quoting from commit dcf0c16 ("core.excludesfile clean-up" 2007-11-16): git-read-tree takes --exclude-per-directory=<gitignore>, not because the flexibility was needed. Again, this was because the option predates the standardization of the ignore files. ... On the other hand, I think it makes perfect sense to fix git-read-tree, git-merge-recursive and git-clean to follow the same rule as other commands. I do not think of a valid use case to give an exclude-per-directory that is nonstandard to read-tree command, outside a "negative" test in the t1004 test script. This patch is the first step to untangle this mess. The next step would be to teach read-tree, merge-recursive and clean (in C) to use setup_standard_excludes(). History shows each of these were partially or fully fixed: * clean was taught the new trick in 1617adc ("Teach git clean to use setup_standard_excludes()", 2007-11-14). * read-tree was primarily used by checkout & merge scripts. checkout and merge later became builtins and were both fixed to use the new setup_standard_excludes() handling in fc001b5 ("checkout,merge: loosen overwriting untracked file check based on info/exclude", 2011-11-27). So the primary users were fixed, though read-tree itself was not. * merge-recursive has now been replaced as the default merge backend by merge-ort. merge-ort fixed this by using setup_standard_excludes() starting early in its implementation; see commit 6681ce5 ("merge-ort: add implementation of checkout()", 2020-12-13), largely due to its design depending on checkout() and thus being influenced by the checkout code. However, merge-recursive itself was not fixed here, in part because its design meant it had difficulty differentiating between untracked files, ignored files, leftover tracked files that haven't been removed yet due to order of processing files, and files written by itself due to collisions). Make the conversion more complete by now handling read-tree and handling at least the unpack_trees() portion of merge-recursive. While merge-recursive is on its way out, fixing the unpack_trees() portion is easy and facilitates some of the later changes in this series. Note that fixing read-tree makes the --exclude-per-directory option to read-tree useless, so we remove it from the documentation (though we continue to accept it if passed). The read-tree changes happen to fix a bug in t1013. Signed-off-by: Elijah Newren <[email protected]> Signed-off-by: Junio C Hamano <[email protected]>
1 parent c512d27 commit 491a757

File tree

4 files changed

+21
-34
lines changed

4 files changed

+21
-34
lines changed

Documentation/git-read-tree.txt

Lines changed: 1 addition & 17 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

@@ -88,21 +87,6 @@ OPTIONS
8887
The command will refuse to overwrite entries that already
8988
existed in the original index file.
9089

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-
10690
--index-output=<file>::
10791
Instead of writing the results out to `$GIT_INDEX_FILE`,
10892
write the resulting index in the named file. While the

builtin/read-tree.c

Lines changed: 10 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

@@ -209,8 +201,11 @@ int cmd_read_tree(int argc, const char **argv, const char *cmd_prefix)
209201
if ((opts.update || opts.index_only) && !opts.merge)
210202
die("%s is meaningless without -m, --reset, or --prefix",
211203
opts.update ? "-u" : "-i");
212-
if ((opts.dir && !opts.update))
213-
die("--exclude-per-directory is meaningless unless -u");
204+
if (opts.update && !opts.reset) {
205+
CALLOC_ARRAY(opts.dir, 1);
206+
opts.dir->flags |= DIR_SHOW_IGNORED;
207+
setup_standard_excludes(opts.dir);
208+
}
214209
if (opts.merge && !opts.index_only)
215210
setup_work_tree();
216211

merge-recursive.c

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -408,8 +408,13 @@ static int unpack_trees_start(struct merge_options *opt,
408408
memset(&opt->priv->unpack_opts, 0, sizeof(opt->priv->unpack_opts));
409409
if (opt->priv->call_depth)
410410
opt->priv->unpack_opts.index_only = 1;
411-
else
411+
else {
412412
opt->priv->unpack_opts.update = 1;
413+
/* FIXME: should only do this if !overwrite_ignore */
414+
CALLOC_ARRAY(opt->priv->unpack_opts.dir, 1);
415+
opt->priv->unpack_opts.dir->flags |= DIR_SHOW_IGNORED;
416+
setup_standard_excludes(opt->priv->unpack_opts.dir);
417+
}
413418
opt->priv->unpack_opts.merge = 1;
414419
opt->priv->unpack_opts.head_idx = 2;
415420
opt->priv->unpack_opts.fn = threeway_merge;
@@ -423,6 +428,10 @@ static int unpack_trees_start(struct merge_options *opt,
423428
init_tree_desc_from_tree(t+2, merge);
424429

425430
rc = unpack_trees(3, t, &opt->priv->unpack_opts);
431+
if (opt->priv->unpack_opts.dir) {
432+
dir_clear(opt->priv->unpack_opts.dir);
433+
FREE_AND_NULL(opt->priv->unpack_opts.dir);
434+
}
426435
cache_tree_free(&opt->repo->index->cache_tree);
427436

428437
/*

t/t1013-read-tree-submodule.sh

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,6 @@ test_description='read-tree can handle submodules'
66
. "$TEST_DIRECTORY"/lib-submodule-update.sh
77

88
KNOWN_FAILURE_DIRECTORY_SUBMODULE_CONFLICTS=1
9-
KNOWN_FAILURE_SUBMODULE_OVERWRITE_IGNORED_UNTRACKED=1
109

1110
test_submodule_switch_recursing_with_args "read-tree -u -m"
1211

0 commit comments

Comments
 (0)