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

[PATCH] git add: respect core.filemode with unmerged entries

From
Johannes Schindelin <johannes.schindelin@gmx.de>
Date
Jun 29, 2007, 17:32 UTC
Message-ID
<Pine.LNX.4.64.0706291820200.4438@racer.site>
In-Reply-To
<7v3b0bf4ea.fsf@assigned-by-dhcp.pobox.com>

When a merge left unmerged entries, git add failed to pick up the file mode from the index, when core.filemode == 0. If more than one unmerged entry is there, the order of stage preference is 2, 1, 3.

Noticed by Johannes Sixt.
Signed-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>
---
	On Fri, 29 Jun 2007, Junio C Hamano wrote:
	> Johannes Schindelin <Johannes.Schindelin@gmx.de> writes:
	> 
	> > On Fri, 29 Jun 2007, Johannes Sixt wrote:
	> >
	> >> However, if only two stages are present, the file mode is 
	> >> still taken from the file instead of from the index. As that 
	> >> easy to solve (at least for the unambiguous case)?
	> >
	> > It might be related to the bug Junio found, i.e. that I assumed stage 1 to 
	> > be "ours".
	> 
	> Actually it is because (-1-pos) and (1-pos) are two apart.
	I congratulate myself. My first off-by-two bug.
	> I am all for refactoring the funny "pick up an existing entry at
	> any stage, but favor 0 then 2 then 1 and finally 3" into a
	> separate function.  It makes sense, although I do not offhand
	> know of a place that we can immediately reuse it (logically,
	> diff-files ought to do that, but I haven't checked).
	Me neither. But at least I coded it (hopefully) correctly this 
	time, even accompied it by a test verifying that I got it right.
 read-cache.c   |   30 +++++++++++++++++++++++++++++-
 t/t3700-add.sh |   26 ++++++++++++++++++++++++++
 2 files changed, 55 insertions(+), 1 deletions(-)
diff --git a/read-cache.c b/read-cache.c
index 4362b11..a363f31 100644
--- a/read-cache.c
+++ b/read-cache.c
@@ -350,6 +350,34 @@ int remove_file_from_index(struct index_state *istate, const char *path)
 	return 0;
 }
 
+static int compare_name(struct cache_entry *ce, const char *path, int namelen)
+{
+	return namelen != ce_namelen(ce) || memcmp(path, ce->name, namelen);
+}
+
+static int index_name_pos_also_unmerged(struct index_state *istate,
+	const char *path, int namelen)
+{
+	int pos = index_name_pos(istate, path, namelen);
+	struct cache_entry *ce;
+
+	if (pos >= 0)
+		return pos;
+
+	/* maybe unmerged? */
+	pos = -1 - pos;
+	if (pos >= istate->cache_nr ||
+			compare_name((ce = istate->cache[pos]), path, namelen))
+		return -1;
+
+	/* order of preference: stage 2, 1, 3 */
+	if (ce_stage(ce) == 1 && pos + 1 < istate->cache_nr &&
+			ce_stage((ce = istate->cache[pos + 1])) == 2 &&
+			!compare_name(ce, path, namelen))
+		pos++;
+	return pos;
+}
+
 int add_file_to_index(struct index_state *istate, const char *path, int verbose)
 {
 	int size, namelen;
@@ -380,7 +408,7 @@ int add_file_to_index(struct index_state *istate, const char *path, int verbose)
 		 * from it, otherwise assume unexecutable regular file.
 		 */
 		struct cache_entry *ent;
-		int pos = index_name_pos(istate, path, namelen);
+		int pos = index_name_pos_also_unmerged(istate, path, namelen);
 
 		ent = (0 <= pos) ? istate->cache[pos] : NULL;
 		ce->ce_mode = ce_mode_from_stat(ent, st.st_mode);
diff --git a/t/t3700-add.sh b/t/t3700-add.sh
index ad8cc7d..0d80c6a 100755
--- a/t/t3700-add.sh
+++ b/t/t3700-add.sh
@@ -110,4 +110,30 @@ test_expect_success 'check correct prefix detection' '
 	git add 1/2/a 1/3/b 1/2/c
 '
 
+test_expect_success 'git add and filemode=0 with unmerged entries' '
+	echo 1 > stage1 &&
+	echo 2 > stage2 &&
+	echo 3 > stage3 &&
+	for s in 1 2 3
+	do
+		echo "100755 $(git hash-object -w stage$s) $s	file"
+	done | git update-index --index-info &&
+	git config core.filemode 0 &&
+	echo new > file &&
+	git add file &&
+	git ls-files --stage | grep "^100755 .* 0	file$"
+'
+
+test_expect_success 'git add and filemode=0 prefers stage 2 over stage 1' '
+	git rm --cached -f file &&
+	(
+		echo "100644 $(git hash-object -w stage1) 1	file"
+		echo "100755 $(git hash-object -w stage2) 2	file"
+	) | git update-index --index-info &&
+	git config core.filemode 0 &&
+	echo new > file &&
+	git add file &&
+	git ls-files --stage | grep "^100755 .* 0	file$"
+'
+
 test_done
-- 
1.5.2.2.3228.g16a27
Previous: Junio C HamanoNext: Junio C Hamano
Message 18 of 26 in “most commonly used git commands?”
  1. Michael S. TsirkinJun 25, 2007
  2. Junio C HamanoJun 25, 2007
  3. Michael S. TsirkinJun 25, 2007
  4. Junio C HamanoJun 25, 2007
  5. Martin LanghoffJun 28, 2007
  6. Josh TriplettJun 28, 2007
  7. Johannes SchindelinJun 25, 2007
  8. Alex RiesenJun 28, 2007
  9. Johannes SchindelinJun 28, 2007
  10. Johannes SixtJun 28, 2007
  11. Johannes SchindelinJun 28, 2007
  12. Johannes SixtJun 28, 2007
  13. Johannes SixtJun 28, 2007
  14. git add: respect core.filemode even with unmerged entries in the indexJohannes Schindelin, Jun 28, 2007
  15. Johannes SixtJun 29, 2007
  16. Johannes SchindelinJun 29, 2007
  17. Junio C HamanoJun 29, 2007
  18. git add: respect core.filemode with unmerged entriesJohannes Schindelin, Jun 29, 2007
  19. Junio C HamanoJun 29, 2007
  20. Johannes SchindelinJun 29, 2007
  21. Alex RiesenJun 30, 2007
  22. Johannes SchindelinJun 30, 2007
  23. Alex RiesenJun 30, 2007
  24. Jan HudecJul 1, 2007
  25. Alex RiesenJul 1, 2007
  26. Josh TriplettJun 28, 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.