git/list[1] front-page[2] threads[3] people[4] search[5] about
 

[PATCH] optionally disable overwriting of ignored files

From
Clemens Buchacher <drizzd@aon.at>
Date
Aug 18, 2010, 23:39 UTC
Message-ID
<20100818233900.GA27531@localhost>
In-Reply-To
<7viq39avay.fsf@alter.siamese.dyndns.org>

By default, checkout and fast-forward merge will overwrite ignored files. Make this behavior configurable.

If overwriting ignored files is disabled, it can still be enabled on the command line by passing -i to merge or checkout.

Signed-off-by: Clemens Buchacher <drizzd@aon.at>
---
Hi,
On Tue, Aug 17, 2010 at 12:33:25PM -0700, Junio C Hamano wrote:
Show 8 quoted lines
>
> Ancient git didn't honor gitignore and considered no files trashable,
> which caused a lot of trouble to users.  It may be illuminating to check
> discussions in the list archive during the period the following commits
> were made.  f8a9d42 (read-tree: further loosen "working file will be lost"
> check., 2006-12-04), ed93b44 (merge: loosen overcautious "working file
> will be lost" check., 2006-10-08), c819353 (Fix switching to a branch with
> D/F when current branch has file D., 2007-03-15).
I am not convinced this is something that most users want.

The fact that adding a file to .gitignore also marks it as trashable to git is quite surprising to me. This is something that the gitignore manpage should warn about loudly. Instead, I think this behavior is completely undocumented.

As far as I can tell from the code, only fast-forward merge and checkout overwrite ignored files by default. A regular merge will complain about untracked files that would be overwritten (ignored or not). I am quite familiar with that behavior and I think it's useful to be reminded of those untracked files rather than having them overwritten. I thought that by extension, other git commands would behave in the same way.

Here is a patch to optionally disable overwriting of ignored files. But I think we should even disable it by default.

Clemens
 Documentation/config.txt |    6 ++++++
 builtin/checkout.c       |    7 +++++++
 builtin/merge.c          |    9 +++++++++
 cache.h                  |    1 +
 config.c                 |    3 +++
 environment.c            |    1 +
 6 files changed, 27 insertions(+), 0 deletions(-)
diff --git a/Documentation/config.txt b/Documentation/config.txt
index f81fb91..eb9bb43 100644
--- a/Documentation/config.txt
+++ b/Documentation/config.txt
@@ -450,6 +450,12 @@ core.excludesfile::
 	to the value of `$HOME` and "{tilde}user/" to the specified user's
 	home directory.  See linkgit:gitignore[5].
 
+core.overwriteignored::
+	Untracked files can get in the way of merge or checkout. If
+	overwriteignored is enabled, such files will be overwritten
+	to let fast-forward merges and checkouts succeed. Enabled
+	by default.
+
 core.editor::
 	Commands such as `commit` and `tag` that lets you edit
 	messages by launching an editor uses the value of this
diff --git a/builtin/checkout.c b/builtin/checkout.c
index 5affb6f..121a6a3 100644
--- a/builtin/checkout.c
+++ b/builtin/checkout.c
@@ -389,6 +389,11 @@ static int merge_working_tree(struct checkout_opts *opts,
 		topts.gently = opts->merge && old->commit;
 		topts.verbose_update = !opts->quiet;
 		topts.fn = twoway_merge;
+		if (overwrite_ignored) {
+			topts.dir = xcalloc(1, sizeof(*topts.dir));
+			topts.dir->flags |= DIR_SHOW_IGNORED;
+			topts.dir->exclude_per_dir = ".gitignore";
+		}
 		tree = parse_tree_indirect(old->commit ?
 					   old->commit->object.sha1 :
 					   (unsigned char *)EMPTY_TREE_SHA1_BIN);
@@ -664,6 +669,8 @@ int cmd_checkout(int argc, const char **argv, const char *prefix)
 		OPT_SET_INT('3', "theirs", &opts.writeout_stage, "stage",
 			    3),
 		OPT_BOOLEAN('f', "force", &opts.force, "force"),
+		OPT_BOOLEAN('i', "overwrite-ignored", &overwrite_ignored,
+		  "allow explicitly ignored files to be overwritten"),
 		OPT_BOOLEAN('m', "merge", &opts.merge, "merge"),
 		OPT_STRING(0, "conflict", &conflict_style, "style",
 			   "conflict style (merge or diff3)"),
diff --git a/builtin/merge.c b/builtin/merge.c
index 4d31e09..47b12ba 100644
--- a/builtin/merge.c
+++ b/builtin/merge.c
@@ -185,6 +185,8 @@ static struct option builtin_merge_options[] = {
 		"allow fast-forward (default)"),
 	OPT_BOOLEAN(0, "ff-only", &fast_forward_only,
 		"abort if fast-forward is not possible"),
+	OPT_BOOLEAN('i', "overwrite-ignored", &overwrite_ignored,
+	  "allow explicitly ignored files to be overwritten"),
 	OPT_RERERE_AUTOUPDATE(&allow_rerere_auto),
 	OPT_CALLBACK('s', "strategy", &use_strategies, "strategy",
 		"merge strategy to use", option_parse_strategy),
@@ -682,6 +684,7 @@ int checkout_fast_forward(const unsigned char *head, const unsigned char *remote
 	struct unpack_trees_options opts;
 	struct tree_desc t[MAX_UNPACK_TREES];
 	int i, fd, nr_trees = 0;
+	struct dir_struct dir;
 	struct lock_file *lock_file = xcalloc(1, sizeof(struct lock_file));
 
 	refresh_cache(REFRESH_QUIET);
@@ -691,6 +694,12 @@ int checkout_fast_forward(const unsigned char *head, const unsigned char *remote
 	memset(&trees, 0, sizeof(trees));
 	memset(&opts, 0, sizeof(opts));
 	memset(&t, 0, sizeof(t));
+	memset(&dir, 0, sizeof(dir));
+	if (overwrite_ignored) {
+		dir.flags |= DIR_SHOW_IGNORED;
+		dir.exclude_per_dir = ".gitignore";
+		opts.dir = &dir;
+	}
 
 	opts.head_idx = 1;
 	opts.src_index = &the_index;
diff --git a/cache.h b/cache.h
index c9fa3df..dd1b8f7 100644
--- a/cache.h
+++ b/cache.h
@@ -548,6 +548,7 @@ extern size_t packed_git_window_size;
 extern size_t packed_git_limit;
 extern size_t delta_base_cache_limit;
 extern int read_replace_refs;
+extern int overwrite_ignored;
 extern int fsync_object_files;
 extern int core_preload_index;
 extern int core_apply_sparse_checkout;
diff --git a/config.c b/config.c
index cdcf583..bd7956e 100644
--- a/config.c
+++ b/config.c
@@ -563,6 +563,9 @@ static int git_default_core_config(const char *var, const char *value)
 	if (!strcmp(var, "core.excludesfile"))
 		return git_config_pathname(&excludes_file, var, value);
 
+	if (!strcmp(var, "core.overwriteignored"))
+		overwrite_ignored = git_config_bool(var, value);
+
 	if (!strcmp(var, "core.whitespace")) {
 		if (!value)
 			return config_error_nonbool(var);
diff --git a/environment.c b/environment.c
index 83d38d3..1b92f60 100644
--- a/environment.c
+++ b/environment.c
@@ -30,6 +30,7 @@ const char *apply_default_ignorewhitespace;
 int zlib_compression_level = Z_BEST_SPEED;
 int core_compression_level;
 int core_compression_seen;
+int overwrite_ignored = 1;
 int fsync_object_files;
 size_t packed_git_window_size = DEFAULT_PACKED_GIT_WINDOW_SIZE;
 size_t packed_git_limit = DEFAULT_PACKED_GIT_LIMIT;
-- 
1.7.2.1.1.g202c
Previous: Junio C HamanoNext: Jakub Narebski
Message 3 of 39 in “git merge, .gitignore, and silently overwriting untracked files”
  1. Joshua JensenAug 17, 2010
  2. Junio C HamanoAug 17, 2010
  3. optionally disable overwriting of ignored filesClemens Buchacher, Aug 18, 2010
  4. Jakub NarebskiAug 19, 2010
  5. Clemens BuchacherAug 20, 2010
  6. Joshua JensenAug 20, 2010
  7. Junio C HamanoAug 20, 2010
  8. Clemens BuchacherAug 21, 2010
  9. Junio C HamanoAug 22, 2010
  10. Clemens BuchacherAug 22, 2010
  11. Kevin BallardOct 9, 2010
  12. Clemens BuchacherAug 21, 2010
  13. 0/5 do not overwrite untracked files in leading pathClemens Buchacher, Oct 9, 2010
  14. 1/5 t7607: use test_commit and test_must_failClemens Buchacher, Oct 9, 2010
  15. Jonathan NiederOct 10, 2010
  16. 1/5 t7607: use test-lib functions and check MERGE_HEADClemens Buchacher, Oct 10, 2010
  17. Junio C HamanoOct 13, 2010
  18. Junio C HamanoOct 13, 2010
  19. 2/5 t7607: add leading-path testsClemens Buchacher, Oct 9, 2010
  20. Johannes SixtOct 9, 2010
  21. 2/5 t7607: add leading-path testsClemens Buchacher, Oct 10, 2010
  22. 3/5 add function check_ok_to_remove()Clemens Buchacher, Oct 9, 2010
  23. Junio C HamanoOct 13, 2010
  24. 4/5 lstat_cache: optionally return match_lenClemens Buchacher, Oct 9, 2010
  25. 5/5 do not overwrite files in leading pathClemens Buchacher, Oct 9, 2010
  26. Junio C HamanoOct 13, 2010
  27. Clemens BuchacherOct 13, 2010
  28. Clemens BuchacherOct 15, 2010
  29. Junio C HamanoOct 15, 2010
  30. Junio C HamanoAug 20, 2010
  31. optionally disable overwriting of ignored filesClemens Buchacher, Aug 21, 2010
  32. Matthieu MoyAug 23, 2010
  33. Heiko VoigtAug 31, 2010
  34. Matthieu MoyAug 23, 2010
  35. Holger HellmuthAug 23, 2010
  36. Clemens BuchacherAug 23, 2010
  37. Junio C HamanoAug 23, 2010
  38. Clemens BuchacherAug 24, 2010
  39. Junio C HamanoAug 24, 2010

Read the whole thread, see it on lore, or plain text.

$ cat FOOTERMessages come from the public archive at lore.kernel.org/git, fetched every hour. The front page is chosen and written each morning by an AI editor and can be wrong; the threads themselves are the record. About and API. For agents: an MCP server at https://gitlist.dev/mcp, and any thread, story or person page as Markdown by adding .md to its URL (or sending Accept: text/markdown). Details in /llms.txt.