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

Re: bug in read-tree -m on A -> A/A

From
Junio C Hamano <junkio@cox.net>
Date
Mar 16, 2007, 06:25 UTC
Message-ID
<7v6491yab1.fsf@assigned-by-dhcp.cox.net>
In-Reply-To
<7v4polzsrn.fsf@assigned-by-dhcp.cox.net>
Junio C Hamano <junkio@cox.net> writes:
Show 13 quoted lines
> "Shawn O. Pearce" <spearce@spearce.org> writes:
>
>> ....  The following test appears to
>> trigger the same failure,...
>
> You have file "A" on one branch, and file "A/A" on another
> branch.  You are on the latter branch and switching to the
> former one.
>
> The following patch illustrates where you need to implement an
> alternate, loosened check, but should not be applied to your
> tree as-is.  If you have local modification to path "A/A", this
> will lose it.

This does not do the bottom-up merge, but tries to catch the lossy case within the limit of the current framework.

Only lightly tested, and I won't be applying it as-is yet as I am not thinking very clearly tonight (no, I am not drunk, just under the weather a bit).

Testing and improvements are very much appreciated.
---
 unpack-trees.c |   75 +++++++++++++++++++++++++++++++++++++++++++++++++++++++-
 1 files changed, 74 insertions(+), 1 deletions(-)
diff --git a/unpack-trees.c b/unpack-trees.c
index 2e2232c..2288762 100644
--- a/unpack-trees.c
+++ b/unpack-trees.c
@@ -468,6 +468,60 @@ static void invalidate_ce_path(struct cache_entry *ce)
 		cache_tree_invalidate_path(active_cache_tree, ce->name);
 }
 
+static void verify_clean_subdirectory(const char *path, const char *action,
+				      struct unpack_trees_options *o)
+{
+	/*
+	 * we are about to extract "path"; we would not want to lose
+	 * anything in the existing directory there.
+	 */
+	int namelen;
+	int pos, i;
+	struct dir_struct d;
+	char *pathbuf;
+
+	/*
+	 * First let's make sure we do not have a local modification
+	 * in that directory.
+	 */
+	namelen = strlen(path);
+	pos = cache_name_pos(path, namelen);
+	if (0 <= pos)
+		return; /* we have it as nondirectory */
+	pos = -pos - 1;
+	for (i = pos; i < active_nr; i++) {
+		struct cache_entry *ce = active_cache[i];
+		int len = ce_namelen(ce);
+		if (len < namelen ||
+		    strncmp(path, ce->name, namelen) ||
+		    ce->name[namelen] != '/')
+			break;
+		/*
+		 * ce->name is an entry in the subdirectory.
+		 */
+		verify_uptodate(ce, o);
+	}
+
+	/*
+	 * Then we need to make sure that we do not lose a locally
+	 * present file that is not ignored.
+	 */
+	if (!o->dir)
+		return;
+
+	pathbuf = xmalloc(namelen + 2);
+	memcpy(pathbuf, path, namelen);
+	strcpy(pathbuf+namelen, "/");
+
+	memset(&d, 0, sizeof(d));
+	d.exclude_per_dir = o->dir->exclude_per_dir;
+	i = read_directory(&d, path, pathbuf, namelen+1);
+	if (i)
+		die("Updating '%s' would lose untracked files in it",
+		    path);
+	free(pathbuf);
+}
+
 /*
  * We do not want to remove or overwrite a working tree file that
  * is not tracked, unless it is ignored.
@@ -479,9 +533,28 @@ static void verify_absent(const char *path, const char *action,
 
 	if (o->index_only || o->reset || !o->update)
 		return;
-	if (!lstat(path, &st) && !(o->dir && excluded(o->dir, path)))
+
+	if (!lstat(path, &st)) {
+		if (o->dir && excluded(o->dir, path))
+			/*
+			 * path is explicitly excluded, so it is Ok to
+			 * overwrite it.
+			 */
+			return;
+		if (S_ISDIR(st.st_mode))
+			/*
+			 * We are checking out path "foo" and
+			 * found "foo/." in the working tree.
+			 * This is tricky -- if we have modified
+			 * files that are in "foo/" we would lose
+			 * it.
+			 */
+			verify_clean_subdirectory(path, action, o);
+			return;
+
 		die("Untracked working tree file '%s' "
 		    "would be %s by merge.", path, action);
+	}
 }
 
 static int merged_entry(struct cache_entry *merge, struct cache_entry *old,
Previous: Junio C Hamano
Message 3 of 3 in “bug in read-tree -m on A -> A/A”
  1. Shawn O. PearceMar 16, 2007
  2. Junio C HamanoMar 16, 2007
  3. Junio C HamanoMar 16, 2007

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.