git@vger.kernel.org list mirror (unofficial, one of many)
 help / color / mirror / code / Atom feed
* [PATCH] read_tree(): pass "int stage" as context to read_tree_recursive()
@ 2009-04-18  0:29 Nguyễn Thái Ngọc Duy
  2021-03-06 19:34 ` [PATCH 0/7] Move the read_tree() function to its only user Ævar Arnfjörð Bjarmason
                   ` (7 more replies)
  0 siblings, 8 replies; 262+ messages in thread
From: Nguyễn Thái Ngọc Duy @ 2009-04-18  0:29 UTC (permalink / raw)
  To: git; +Cc: Nguyễn Thái Ngọc Duy

Back in history, read_tree_recursive() did not have context argument to
pass custom parameters through. To support read_tree(), it took "stage"
from read_tree() and pass it to read_tree_fn_t function.  Then context
argument was added but "stage" remains as a read_tree_fn_t argument.

This patch converts read_tree() to pass stage as a context instead,
thus remove the last usage of "stage" argument in
read_tree_recursive() and read_tree_fn_t. When the opportunity comes,
"stage" should be removed from read_tree_fn_t and read_tree_recursive().

Signed-off-by: Nguyễn Thái Ngọc Duy <pclouds@gmail.com>
---
 tree.c |    6 +++---
 tree.h |    1 +
 2 files changed, 4 insertions(+), 3 deletions(-)

diff --git a/tree.c b/tree.c
index 0d703a0..02f2ca0 100644
--- a/tree.c
+++ b/tree.c
@@ -31,7 +31,7 @@ static int read_one_entry_opt(const unsigned char *sha1, const char *base, int b
 
 static int read_one_entry(const unsigned char *sha1, const char *base, int baselen, const char *pathname, unsigned mode, int stage, void *context)
 {
-	return read_one_entry_opt(sha1, base, baselen, pathname, mode, stage,
+	return read_one_entry_opt(sha1, base, baselen, pathname, mode, *(int *)context,
 				  ADD_CACHE_OK_TO_ADD|ADD_CACHE_SKIP_DFCHECK);
 }
 
@@ -41,7 +41,7 @@ static int read_one_entry(const unsigned char *sha1, const char *base, int basel
  */
 static int read_one_entry_quick(const unsigned char *sha1, const char *base, int baselen, const char *pathname, unsigned mode, int stage, void *context)
 {
-	return read_one_entry_opt(sha1, base, baselen, pathname, mode, stage,
+	return read_one_entry_opt(sha1, base, baselen, pathname, mode, *(int *)context,
 				  ADD_CACHE_JUST_APPEND);
 }
 
@@ -206,7 +206,7 @@ int read_tree(struct tree *tree, int stage, const char **match)
 
 	if (!fn)
 		fn = read_one_entry_quick;
-	err = read_tree_recursive(tree, "", 0, stage, match, fn, NULL);
+	err = read_tree_recursive(tree, "", 0, 0, match, fn, &stage);
 	if (fn == read_one_entry || err)
 		return err;
 
diff --git a/tree.h b/tree.h
index 2ff01a4..d0f4c9b 100644
--- a/tree.h
+++ b/tree.h
@@ -21,6 +21,7 @@ int parse_tree(struct tree *tree);
 struct tree *parse_tree_indirect(const unsigned char *sha1);
 
 #define READ_TREE_RECURSIVE 1
+/* FIXME: remove "int stage" argument from read_tree_fn_t */
 typedef int (*read_tree_fn_t)(const unsigned char *, const char *, int, const char *, unsigned int, int, void *);
 
 extern int read_tree_recursive(struct tree *tree,
-- 
1.6.2.2.693.g5a1be

^ permalink raw reply	[flat|nested] 262+ messages in thread

* [PATCH 0/7] Move the read_tree() function to its only user
  2009-04-18  0:29 [PATCH] read_tree(): pass "int stage" as context to read_tree_recursive() Nguyễn Thái Ngọc Duy
@ 2021-03-06 19:34 ` Ævar Arnfjörð Bjarmason
  2021-03-06 22:06   ` Elijah Newren
                     ` (7 more replies)
  2021-03-06 19:34 ` [PATCH 1/7] tree.c API: move read_tree() into builtin/ls-files.c Ævar Arnfjörð Bjarmason
                   ` (6 subsequent siblings)
  7 siblings, 8 replies; 262+ messages in thread
From: Ævar Arnfjörð Bjarmason @ 2021-03-06 19:34 UTC (permalink / raw)
  To: git
  Cc: Junio C Hamano, Elijah Newren,
	Nguyễn Thái Ngọc Duy,
	Ævar Arnfjörð Bjarmason

This is a small cleanup series to remove move the last user of
read_tree() over to read_tree_recursive(), and while we're at it
adjust the API of read_tree_fn_t to its current use-case.

I found out after writing this that there had been a FIXME comment
(never made it into git.git) about this from mid-2009:
https://lore.kernel.org/git/1240014568-3675-1-git-send-email-pclouds@gmail.com/

Ævar Arnfjörð Bjarmason (7):
  tree.c API: move read_tree() into builtin/ls-files.c
  ls-files: don't needlessly pass around stage variable
  ls-files: remove cache juggling + sorting
  merge-ort: move cmp_cache_name_compare() from tree.c
  ls-files: refactor read_one_entry_quick() to use a strbuf
  tree.h API: remove support for starting at prefix != ""
  tree.h API: remove "stage" parameter from read_tree_recursive()

 archive.c          |  13 +++---
 builtin/checkout.c |   4 +-
 builtin/log.c      |   6 +--
 builtin/ls-files.c |  28 +++++++++++-
 builtin/ls-tree.c  |   4 +-
 merge-ort.c        |  10 ++++
 merge-recursive.c  |   4 +-
 tree.c             | 112 ++-------------------------------------------
 tree.h             |  11 +----
 9 files changed, 60 insertions(+), 132 deletions(-)

-- 
2.31.0.rc0.126.g04f22c5b82


^ permalink raw reply	[flat|nested] 262+ messages in thread

* [PATCH 1/7] tree.c API: move read_tree() into builtin/ls-files.c
  2009-04-18  0:29 [PATCH] read_tree(): pass "int stage" as context to read_tree_recursive() Nguyễn Thái Ngọc Duy
  2021-03-06 19:34 ` [PATCH 0/7] Move the read_tree() function to its only user Ævar Arnfjörð Bjarmason
@ 2021-03-06 19:34 ` Ævar Arnfjörð Bjarmason
  2021-03-06 19:34 ` [PATCH 2/7] ls-files: don't needlessly pass around stage variable Ævar Arnfjörð Bjarmason
                   ` (5 subsequent siblings)
  7 siblings, 0 replies; 262+ messages in thread
From: Ævar Arnfjörð Bjarmason @ 2021-03-06 19:34 UTC (permalink / raw)
  To: git
  Cc: Junio C Hamano, Elijah Newren,
	Nguyễn Thái Ngọc Duy,
	Ævar Arnfjörð Bjarmason

Since the read_tree() API was added around the same time as
read_tree_recursive() in 94537c78a82 (Move "read_tree()" to
"tree.c"[...], 2005-04-22) and b12ec373b8e ([PATCH] Teach read-tree
about commit objects, 2005-04-20) things have gradually migrated over
to the read_tree_recursive() version.

Now builtin/ls-files.c is the last user of this code, let's move all
the relevant code there. This allows for subsequent simplification of
it, and an eventual move to read_tree_recursive().

Signed-off-by: Ævar Arnfjörð Bjarmason <avarab@gmail.com>
---
 builtin/ls-files.c | 91 ++++++++++++++++++++++++++++++++++++++++++++++
 tree.c             | 89 ---------------------------------------------
 tree.h             |  4 --
 3 files changed, 91 insertions(+), 93 deletions(-)

diff --git a/builtin/ls-files.c b/builtin/ls-files.c
index f6f9e483b27..a4458622813 100644
--- a/builtin/ls-files.c
+++ b/builtin/ls-files.c
@@ -12,6 +12,7 @@
 #include "dir.h"
 #include "builtin.h"
 #include "tree.h"
+#include "cache-tree.h"
 #include "parse-options.h"
 #include "resolve-undo.h"
 #include "string-list.h"
@@ -420,6 +421,96 @@ static int get_common_prefix_len(const char *common_prefix)
 	return common_prefix_len;
 }
 
+static int read_one_entry_opt(struct index_state *istate,
+			      const struct object_id *oid,
+			      const char *base, int baselen,
+			      const char *pathname,
+			      unsigned mode, int stage, int opt)
+{
+	int len;
+	struct cache_entry *ce;
+
+	if (S_ISDIR(mode))
+		return READ_TREE_RECURSIVE;
+
+	len = strlen(pathname);
+	ce = make_empty_cache_entry(istate, baselen + len);
+
+	ce->ce_mode = create_ce_mode(mode);
+	ce->ce_flags = create_ce_flags(stage);
+	ce->ce_namelen = baselen + len;
+	memcpy(ce->name, base, baselen);
+	memcpy(ce->name + baselen, pathname, len+1);
+	oidcpy(&ce->oid, oid);
+	return add_index_entry(istate, ce, opt);
+}
+
+static int read_one_entry(const struct object_id *oid, struct strbuf *base,
+			  const char *pathname, unsigned mode, int stage,
+			  void *context)
+{
+	struct index_state *istate = context;
+	return read_one_entry_opt(istate, oid, base->buf, base->len, pathname,
+				  mode, stage,
+				  ADD_CACHE_OK_TO_ADD|ADD_CACHE_SKIP_DFCHECK);
+}
+
+/*
+ * This is used when the caller knows there is no existing entries at
+ * the stage that will conflict with the entry being added.
+ */
+static int read_one_entry_quick(const struct object_id *oid, struct strbuf *base,
+				const char *pathname, unsigned mode, int stage,
+				void *context)
+{
+	struct index_state *istate = context;
+	return read_one_entry_opt(istate, oid, base->buf, base->len, pathname,
+				  mode, stage,
+				  ADD_CACHE_JUST_APPEND);
+}
+
+
+static int read_tree(struct repository *r, struct tree *tree, int stage,
+		     struct pathspec *match, struct index_state *istate)
+{
+	read_tree_fn_t fn = NULL;
+	int i, err;
+
+	/*
+	 * Currently the only existing callers of this function all
+	 * call it with stage=1 and after making sure there is nothing
+	 * at that stage; we could always use read_one_entry_quick().
+	 *
+	 * But when we decide to straighten out git-read-tree not to
+	 * use unpack_trees() in some cases, this will probably start
+	 * to matter.
+	 */
+
+	/*
+	 * See if we have cache entry at the stage.  If so,
+	 * do it the original slow way, otherwise, append and then
+	 * sort at the end.
+	 */
+	for (i = 0; !fn && i < istate->cache_nr; i++) {
+		const struct cache_entry *ce = istate->cache[i];
+		if (ce_stage(ce) == stage)
+			fn = read_one_entry;
+	}
+
+	if (!fn)
+		fn = read_one_entry_quick;
+	err = read_tree_recursive(r, tree, "", 0, stage, match, fn, istate);
+	if (fn == read_one_entry || err)
+		return err;
+
+	/*
+	 * Sort the cache entry -- we need to nuke the cache tree, though.
+	 */
+	cache_tree_free(&istate->cache_tree);
+	QSORT(istate->cache, istate->cache_nr, cmp_cache_name_compare);
+	return 0;
+}
+
 /*
  * Read the tree specified with --with-tree option
  * (typically, HEAD) into stage #1 and then
diff --git a/tree.c b/tree.c
index a52479812ce..a6c12f2745a 100644
--- a/tree.c
+++ b/tree.c
@@ -11,54 +11,6 @@
 
 const char *tree_type = "tree";
 
-static int read_one_entry_opt(struct index_state *istate,
-			      const struct object_id *oid,
-			      const char *base, int baselen,
-			      const char *pathname,
-			      unsigned mode, int stage, int opt)
-{
-	int len;
-	struct cache_entry *ce;
-
-	if (S_ISDIR(mode))
-		return READ_TREE_RECURSIVE;
-
-	len = strlen(pathname);
-	ce = make_empty_cache_entry(istate, baselen + len);
-
-	ce->ce_mode = create_ce_mode(mode);
-	ce->ce_flags = create_ce_flags(stage);
-	ce->ce_namelen = baselen + len;
-	memcpy(ce->name, base, baselen);
-	memcpy(ce->name + baselen, pathname, len+1);
-	oidcpy(&ce->oid, oid);
-	return add_index_entry(istate, ce, opt);
-}
-
-static int read_one_entry(const struct object_id *oid, struct strbuf *base,
-			  const char *pathname, unsigned mode, int stage,
-			  void *context)
-{
-	struct index_state *istate = context;
-	return read_one_entry_opt(istate, oid, base->buf, base->len, pathname,
-				  mode, stage,
-				  ADD_CACHE_OK_TO_ADD|ADD_CACHE_SKIP_DFCHECK);
-}
-
-/*
- * This is used when the caller knows there is no existing entries at
- * the stage that will conflict with the entry being added.
- */
-static int read_one_entry_quick(const struct object_id *oid, struct strbuf *base,
-				const char *pathname, unsigned mode, int stage,
-				void *context)
-{
-	struct index_state *istate = context;
-	return read_one_entry_opt(istate, oid, base->buf, base->len, pathname,
-				  mode, stage,
-				  ADD_CACHE_JUST_APPEND);
-}
-
 static int read_tree_1(struct repository *r,
 		       struct tree *tree, struct strbuf *base,
 		       int stage, const struct pathspec *pathspec,
@@ -154,47 +106,6 @@ int cmp_cache_name_compare(const void *a_, const void *b_)
 				  ce2->name, ce2->ce_namelen, ce_stage(ce2));
 }
 
-int read_tree(struct repository *r, struct tree *tree, int stage,
-	      struct pathspec *match, struct index_state *istate)
-{
-	read_tree_fn_t fn = NULL;
-	int i, err;
-
-	/*
-	 * Currently the only existing callers of this function all
-	 * call it with stage=1 and after making sure there is nothing
-	 * at that stage; we could always use read_one_entry_quick().
-	 *
-	 * But when we decide to straighten out git-read-tree not to
-	 * use unpack_trees() in some cases, this will probably start
-	 * to matter.
-	 */
-
-	/*
-	 * See if we have cache entry at the stage.  If so,
-	 * do it the original slow way, otherwise, append and then
-	 * sort at the end.
-	 */
-	for (i = 0; !fn && i < istate->cache_nr; i++) {
-		const struct cache_entry *ce = istate->cache[i];
-		if (ce_stage(ce) == stage)
-			fn = read_one_entry;
-	}
-
-	if (!fn)
-		fn = read_one_entry_quick;
-	err = read_tree_recursive(r, tree, "", 0, stage, match, fn, istate);
-	if (fn == read_one_entry || err)
-		return err;
-
-	/*
-	 * Sort the cache entry -- we need to nuke the cache tree, though.
-	 */
-	cache_tree_free(&istate->cache_tree);
-	QSORT(istate->cache, istate->cache_nr, cmp_cache_name_compare);
-	return 0;
-}
-
 struct tree *lookup_tree(struct repository *r, const struct object_id *oid)
 {
 	struct object *obj = lookup_object(r, oid);
diff --git a/tree.h b/tree.h
index 3eb0484cbf2..84d66b45538 100644
--- a/tree.h
+++ b/tree.h
@@ -39,8 +39,4 @@ int read_tree_recursive(struct repository *r,
 			int stage, const struct pathspec *pathspec,
 			read_tree_fn_t fn, void *context);
 
-int read_tree(struct repository *r, struct tree *tree,
-	      int stage, struct pathspec *pathspec,
-	      struct index_state *istate);
-
 #endif /* TREE_H */
-- 
2.31.0.rc0.126.g04f22c5b82


^ permalink raw reply	[flat|nested] 262+ messages in thread

* [PATCH 2/7] ls-files: don't needlessly pass around stage variable
  2009-04-18  0:29 [PATCH] read_tree(): pass "int stage" as context to read_tree_recursive() Nguyễn Thái Ngọc Duy
  2021-03-06 19:34 ` [PATCH 0/7] Move the read_tree() function to its only user Ævar Arnfjörð Bjarmason
  2021-03-06 19:34 ` [PATCH 1/7] tree.c API: move read_tree() into builtin/ls-files.c Ævar Arnfjörð Bjarmason
@ 2021-03-06 19:34 ` Ævar Arnfjörð Bjarmason
  2021-03-06 19:34 ` [PATCH 3/7] ls-files: remove cache juggling + sorting Ævar Arnfjörð Bjarmason
                   ` (4 subsequent siblings)
  7 siblings, 0 replies; 262+ messages in thread
From: Ævar Arnfjörð Bjarmason @ 2021-03-06 19:34 UTC (permalink / raw)
  To: git
  Cc: Junio C Hamano, Elijah Newren,
	Nguyễn Thái Ngọc Duy,
	Ævar Arnfjörð Bjarmason

Now that read_tree() has been moved to ls-files.c we can get rid of
the stage != 1 case that'll never happen.

Signed-off-by: Ævar Arnfjörð Bjarmason <avarab@gmail.com>
---
 builtin/ls-files.c | 17 ++++-------------
 1 file changed, 4 insertions(+), 13 deletions(-)

diff --git a/builtin/ls-files.c b/builtin/ls-files.c
index a4458622813..74d572a3e4a 100644
--- a/builtin/ls-files.c
+++ b/builtin/ls-files.c
@@ -470,21 +470,12 @@ static int read_one_entry_quick(const struct object_id *oid, struct strbuf *base
 }
 
 
-static int read_tree(struct repository *r, struct tree *tree, int stage,
+static int read_tree(struct repository *r, struct tree *tree,
 		     struct pathspec *match, struct index_state *istate)
 {
 	read_tree_fn_t fn = NULL;
 	int i, err;
 
-	/*
-	 * Currently the only existing callers of this function all
-	 * call it with stage=1 and after making sure there is nothing
-	 * at that stage; we could always use read_one_entry_quick().
-	 *
-	 * But when we decide to straighten out git-read-tree not to
-	 * use unpack_trees() in some cases, this will probably start
-	 * to matter.
-	 */
 
 	/*
 	 * See if we have cache entry at the stage.  If so,
@@ -493,13 +484,13 @@ static int read_tree(struct repository *r, struct tree *tree, int stage,
 	 */
 	for (i = 0; !fn && i < istate->cache_nr; i++) {
 		const struct cache_entry *ce = istate->cache[i];
-		if (ce_stage(ce) == stage)
+		if (ce_stage(ce) == 1)
 			fn = read_one_entry;
 	}
 
 	if (!fn)
 		fn = read_one_entry_quick;
-	err = read_tree_recursive(r, tree, "", 0, stage, match, fn, istate);
+	err = read_tree_recursive(r, tree, "", 0, 1, match, fn, istate);
 	if (fn == read_one_entry || err)
 		return err;
 
@@ -549,7 +540,7 @@ void overlay_tree_on_index(struct index_state *istate,
 			       PATHSPEC_PREFER_CWD, prefix, matchbuf);
 	} else
 		memset(&pathspec, 0, sizeof(pathspec));
-	if (read_tree(the_repository, tree, 1, &pathspec, istate))
+	if (read_tree(the_repository, tree, &pathspec, istate))
 		die("unable to read tree entries %s", tree_name);
 
 	for (i = 0; i < istate->cache_nr; i++) {
-- 
2.31.0.rc0.126.g04f22c5b82


^ permalink raw reply	[flat|nested] 262+ messages in thread

* [PATCH 3/7] ls-files: remove cache juggling + sorting
  2009-04-18  0:29 [PATCH] read_tree(): pass "int stage" as context to read_tree_recursive() Nguyễn Thái Ngọc Duy
                   ` (2 preceding siblings ...)
  2021-03-06 19:34 ` [PATCH 2/7] ls-files: don't needlessly pass around stage variable Ævar Arnfjörð Bjarmason
@ 2021-03-06 19:34 ` Ævar Arnfjörð Bjarmason
  2021-03-06 21:37   ` Elijah Newren
  2021-03-06 19:34 ` [PATCH 4/7] merge-ort: move cmp_cache_name_compare() from tree.c Ævar Arnfjörð Bjarmason
                   ` (3 subsequent siblings)
  7 siblings, 1 reply; 262+ messages in thread
From: Ævar Arnfjörð Bjarmason @ 2021-03-06 19:34 UTC (permalink / raw)
  To: git
  Cc: Junio C Hamano, Elijah Newren,
	Nguyễn Thái Ngọc Duy,
	Ævar Arnfjörð Bjarmason

Remove the "ce_stage(ce) == 1" and "Sort the cache entry" code from
read_tree(), which allows us to remove the function entirely and move
over to read_tree_recursive().

I don't think the "Sort the cached entry" code was needed here, see
af3785dc5a7 (Optimize "diff --cached" performance., 2007-08-09) for
the use-case it was intended for. The only user of this code is
"ls-files --with-tree", which isn't the sort of use-case that needs to
care about "ce_stage(ce) != 0" or sorting tree entries.

Signed-off-by: Ævar Arnfjörð Bjarmason <avarab@gmail.com>
---
 builtin/ls-files.c | 76 +++++++---------------------------------------
 1 file changed, 11 insertions(+), 65 deletions(-)

diff --git a/builtin/ls-files.c b/builtin/ls-files.c
index 74d572a3e4a..f5239437809 100644
--- a/builtin/ls-files.c
+++ b/builtin/ls-files.c
@@ -12,7 +12,6 @@
 #include "dir.h"
 #include "builtin.h"
 #include "tree.h"
-#include "cache-tree.h"
 #include "parse-options.h"
 #include "resolve-undo.h"
 #include "string-list.h"
@@ -421,12 +420,15 @@ static int get_common_prefix_len(const char *common_prefix)
 	return common_prefix_len;
 }
 
-static int read_one_entry_opt(struct index_state *istate,
-			      const struct object_id *oid,
-			      const char *base, int baselen,
-			      const char *pathname,
-			      unsigned mode, int stage, int opt)
+static int read_one_entry_quick(const struct object_id *oid,
+				struct strbuf *basebuf,
+				const char *pathname,
+				unsigned mode,
+				int stage, void *context)
 {
+	struct index_state *istate = context;
+	const char *base = basebuf->buf;
+	const int baselen = basebuf->len;
 	int len;
 	struct cache_entry *ce;
 
@@ -442,64 +444,7 @@ static int read_one_entry_opt(struct index_state *istate,
 	memcpy(ce->name, base, baselen);
 	memcpy(ce->name + baselen, pathname, len+1);
 	oidcpy(&ce->oid, oid);
-	return add_index_entry(istate, ce, opt);
-}
-
-static int read_one_entry(const struct object_id *oid, struct strbuf *base,
-			  const char *pathname, unsigned mode, int stage,
-			  void *context)
-{
-	struct index_state *istate = context;
-	return read_one_entry_opt(istate, oid, base->buf, base->len, pathname,
-				  mode, stage,
-				  ADD_CACHE_OK_TO_ADD|ADD_CACHE_SKIP_DFCHECK);
-}
-
-/*
- * This is used when the caller knows there is no existing entries at
- * the stage that will conflict with the entry being added.
- */
-static int read_one_entry_quick(const struct object_id *oid, struct strbuf *base,
-				const char *pathname, unsigned mode, int stage,
-				void *context)
-{
-	struct index_state *istate = context;
-	return read_one_entry_opt(istate, oid, base->buf, base->len, pathname,
-				  mode, stage,
-				  ADD_CACHE_JUST_APPEND);
-}
-
-
-static int read_tree(struct repository *r, struct tree *tree,
-		     struct pathspec *match, struct index_state *istate)
-{
-	read_tree_fn_t fn = NULL;
-	int i, err;
-
-
-	/*
-	 * See if we have cache entry at the stage.  If so,
-	 * do it the original slow way, otherwise, append and then
-	 * sort at the end.
-	 */
-	for (i = 0; !fn && i < istate->cache_nr; i++) {
-		const struct cache_entry *ce = istate->cache[i];
-		if (ce_stage(ce) == 1)
-			fn = read_one_entry;
-	}
-
-	if (!fn)
-		fn = read_one_entry_quick;
-	err = read_tree_recursive(r, tree, "", 0, 1, match, fn, istate);
-	if (fn == read_one_entry || err)
-		return err;
-
-	/*
-	 * Sort the cache entry -- we need to nuke the cache tree, though.
-	 */
-	cache_tree_free(&istate->cache_tree);
-	QSORT(istate->cache, istate->cache_nr, cmp_cache_name_compare);
-	return 0;
+	return add_index_entry(istate, ce, ADD_CACHE_JUST_APPEND);
 }
 
 /*
@@ -540,7 +485,8 @@ void overlay_tree_on_index(struct index_state *istate,
 			       PATHSPEC_PREFER_CWD, prefix, matchbuf);
 	} else
 		memset(&pathspec, 0, sizeof(pathspec));
-	if (read_tree(the_repository, tree, &pathspec, istate))
+	if (read_tree_recursive(the_repository, tree, "", 0, 1,
+				&pathspec, read_one_entry_quick, istate))
 		die("unable to read tree entries %s", tree_name);
 
 	for (i = 0; i < istate->cache_nr; i++) {
-- 
2.31.0.rc0.126.g04f22c5b82


^ permalink raw reply	[flat|nested] 262+ messages in thread

* [PATCH 4/7] merge-ort: move cmp_cache_name_compare() from tree.c
  2009-04-18  0:29 [PATCH] read_tree(): pass "int stage" as context to read_tree_recursive() Nguyễn Thái Ngọc Duy
                   ` (3 preceding siblings ...)
  2021-03-06 19:34 ` [PATCH 3/7] ls-files: remove cache juggling + sorting Ævar Arnfjörð Bjarmason
@ 2021-03-06 19:34 ` Ævar Arnfjörð Bjarmason
  2021-03-06 19:34 ` [PATCH 5/7] ls-files: refactor read_one_entry_quick() to use a strbuf Ævar Arnfjörð Bjarmason
                   ` (2 subsequent siblings)
  7 siblings, 0 replies; 262+ messages in thread
From: Ævar Arnfjörð Bjarmason @ 2021-03-06 19:34 UTC (permalink / raw)
  To: git
  Cc: Junio C Hamano, Elijah Newren,
	Nguyễn Thái Ngọc Duy,
	Ævar Arnfjörð Bjarmason

Move the cmp_cache_name_compare() function from tree.c. Now that we've
stopped using it in builtin/ls-files.c the merge-ort.c code is its
only user, let's just have it own it instead of having this API which
straddles tree.h and cache-tree.h in tree.c itself.

See these commits for its recent introduction in merge-ort.c::

 - 70912f66de7 (tree: enable cmp_cache_name_compare() to be used
   elsewhere, 2020-12-13)

 - ef2b3693870 (merge-ort: add implementation of
   record_conflicted_index_entries(), 2020-12-13)

Signed-off-by: Ævar Arnfjörð Bjarmason <avarab@gmail.com>
---
 merge-ort.c | 10 ++++++++++
 tree.c      | 11 -----------
 tree.h      |  2 --
 3 files changed, 10 insertions(+), 13 deletions(-)

diff --git a/merge-ort.c b/merge-ort.c
index 603d30c5217..d7b3ced1bec 100644
--- a/merge-ort.c
+++ b/merge-ort.c
@@ -3099,6 +3099,16 @@ static int checkout(struct merge_options *opt,
 	return ret;
 }
 
+static int cmp_cache_name_compare(const void *a_, const void *b_)
+{
+	const struct cache_entry *ce1, *ce2;
+
+	ce1 = *((const struct cache_entry **)a_);
+	ce2 = *((const struct cache_entry **)b_);
+	return cache_name_stage_compare(ce1->name, ce1->ce_namelen, ce_stage(ce1),
+				  ce2->name, ce2->ce_namelen, ce_stage(ce2));
+}
+
 static int record_conflicted_index_entries(struct merge_options *opt,
 					   struct index_state *index,
 					   struct strmap *paths,
diff --git a/tree.c b/tree.c
index a6c12f2745a..c1bde9314d0 100644
--- a/tree.c
+++ b/tree.c
@@ -1,5 +1,4 @@
 #include "cache.h"
-#include "cache-tree.h"
 #include "tree.h"
 #include "object-store.h"
 #include "blob.h"
@@ -96,16 +95,6 @@ int read_tree_recursive(struct repository *r,
 	return ret;
 }
 
-int cmp_cache_name_compare(const void *a_, const void *b_)
-{
-	const struct cache_entry *ce1, *ce2;
-
-	ce1 = *((const struct cache_entry **)a_);
-	ce2 = *((const struct cache_entry **)b_);
-	return cache_name_stage_compare(ce1->name, ce1->ce_namelen, ce_stage(ce1),
-				  ce2->name, ce2->ce_namelen, ce_stage(ce2));
-}
-
 struct tree *lookup_tree(struct repository *r, const struct object_id *oid)
 {
 	struct object *obj = lookup_object(r, oid);
diff --git a/tree.h b/tree.h
index 84d66b45538..34549c86c9f 100644
--- a/tree.h
+++ b/tree.h
@@ -28,8 +28,6 @@ void free_tree_buffer(struct tree *tree);
 /* Parses and returns the tree in the given ent, chasing tags and commits. */
 struct tree *parse_tree_indirect(const struct object_id *oid);
 
-int cmp_cache_name_compare(const void *a_, const void *b_);
-
 #define READ_TREE_RECURSIVE 1
 typedef int (*read_tree_fn_t)(const struct object_id *, struct strbuf *, const char *, unsigned int, int, void *);
 
-- 
2.31.0.rc0.126.g04f22c5b82


^ permalink raw reply	[flat|nested] 262+ messages in thread

* [PATCH 5/7] ls-files: refactor read_one_entry_quick() to use a strbuf
  2009-04-18  0:29 [PATCH] read_tree(): pass "int stage" as context to read_tree_recursive() Nguyễn Thái Ngọc Duy
                   ` (4 preceding siblings ...)
  2021-03-06 19:34 ` [PATCH 4/7] merge-ort: move cmp_cache_name_compare() from tree.c Ævar Arnfjörð Bjarmason
@ 2021-03-06 19:34 ` Ævar Arnfjörð Bjarmason
  2021-03-06 19:34 ` [PATCH 6/7] tree.h API: remove support for starting at prefix != "" Ævar Arnfjörð Bjarmason
  2021-03-06 19:34 ` [PATCH 7/7] tree.h API: remove "stage" parameter from read_tree_recursive() Ævar Arnfjörð Bjarmason
  7 siblings, 0 replies; 262+ messages in thread
From: Ævar Arnfjörð Bjarmason @ 2021-03-06 19:34 UTC (permalink / raw)
  To: git
  Cc: Junio C Hamano, Elijah Newren,
	Nguyễn Thái Ngọc Duy,
	Ævar Arnfjörð Bjarmason

Refactor the code in read_one_entry_quick() that used "base" and
"baselen" to just use the "buf" and "len" fields in the "base" strbuf
directly. Having the "basebuf" variable was a transitory step in
moving away from the old read_tree() in tree.c.

Signed-off-by: Ævar Arnfjörð Bjarmason <avarab@gmail.com>
---
 builtin/ls-files.c | 12 +++++-------
 1 file changed, 5 insertions(+), 7 deletions(-)

diff --git a/builtin/ls-files.c b/builtin/ls-files.c
index f5239437809..c0349a7b206 100644
--- a/builtin/ls-files.c
+++ b/builtin/ls-files.c
@@ -421,14 +421,12 @@ static int get_common_prefix_len(const char *common_prefix)
 }
 
 static int read_one_entry_quick(const struct object_id *oid,
-				struct strbuf *basebuf,
+				struct strbuf *base,
 				const char *pathname,
 				unsigned mode,
 				int stage, void *context)
 {
 	struct index_state *istate = context;
-	const char *base = basebuf->buf;
-	const int baselen = basebuf->len;
 	int len;
 	struct cache_entry *ce;
 
@@ -436,13 +434,13 @@ static int read_one_entry_quick(const struct object_id *oid,
 		return READ_TREE_RECURSIVE;
 
 	len = strlen(pathname);
-	ce = make_empty_cache_entry(istate, baselen + len);
+	ce = make_empty_cache_entry(istate, base->len + len);
 
 	ce->ce_mode = create_ce_mode(mode);
 	ce->ce_flags = create_ce_flags(stage);
-	ce->ce_namelen = baselen + len;
-	memcpy(ce->name, base, baselen);
-	memcpy(ce->name + baselen, pathname, len+1);
+	ce->ce_namelen = base->len + len;
+	memcpy(ce->name, base->buf, base->len);
+	memcpy(ce->name + base->len, pathname, len+1);
 	oidcpy(&ce->oid, oid);
 	return add_index_entry(istate, ce, ADD_CACHE_JUST_APPEND);
 }
-- 
2.31.0.rc0.126.g04f22c5b82


^ permalink raw reply	[flat|nested] 262+ messages in thread

* [PATCH 6/7] tree.h API: remove support for starting at prefix != ""
  2009-04-18  0:29 [PATCH] read_tree(): pass "int stage" as context to read_tree_recursive() Nguyễn Thái Ngọc Duy
                   ` (5 preceding siblings ...)
  2021-03-06 19:34 ` [PATCH 5/7] ls-files: refactor read_one_entry_quick() to use a strbuf Ævar Arnfjörð Bjarmason
@ 2021-03-06 19:34 ` Ævar Arnfjörð Bjarmason
  2021-03-06 21:55   ` Elijah Newren
  2021-03-06 19:34 ` [PATCH 7/7] tree.h API: remove "stage" parameter from read_tree_recursive() Ævar Arnfjörð Bjarmason
  7 siblings, 1 reply; 262+ messages in thread
From: Ævar Arnfjörð Bjarmason @ 2021-03-06 19:34 UTC (permalink / raw)
  To: git
  Cc: Junio C Hamano, Elijah Newren,
	Nguyễn Thái Ngọc Duy,
	Ævar Arnfjörð Bjarmason

Every caller or the read_tree_recursive() function hardcoded a
starting point of "" in the tree. So let's simply remove that
parameter.

It might be useful in the future to get this functionality back,
there's no reason we won't have a read_tree_recursive() use-case that
would want to start in a subdirectory.

But if and when that happens we can just add something like a
read_tree_recursive_subdir() and have both read_tree_recursive() and
that function be a thin wrapper for read_tree_1().

In the meantime there's no reason to keep around what amounts to dead
code just in case we need it in the future.

Signed-off-by: Ævar Arnfjörð Bjarmason <avarab@gmail.com>
---
 archive.c          | 8 ++++----
 builtin/checkout.c | 2 +-
 builtin/log.c      | 4 ++--
 builtin/ls-files.c | 2 +-
 builtin/ls-tree.c  | 2 +-
 merge-recursive.c  | 2 +-
 tree.c             | 2 --
 tree.h             | 1 -
 8 files changed, 10 insertions(+), 13 deletions(-)

diff --git a/archive.c b/archive.c
index 5919d9e5050..9394f170f7f 100644
--- a/archive.c
+++ b/archive.c
@@ -316,8 +316,8 @@ int write_archive_entries(struct archiver_args *args,
 		git_attr_set_direction(GIT_ATTR_INDEX);
 	}
 
-	err = read_tree_recursive(args->repo, args->tree, "",
-				  0, 0, &args->pathspec,
+	err = read_tree_recursive(args->repo, args->tree,
+				  0, &args->pathspec,
 				  queue_or_write_archive_entry,
 				  &context);
 	if (err == READ_TREE_RECURSIVE)
@@ -405,8 +405,8 @@ static int path_exists(struct archiver_args *args, const char *path)
 	ctx.args = args;
 	parse_pathspec(&ctx.pathspec, 0, 0, "", paths);
 	ctx.pathspec.recursive = 1;
-	ret = read_tree_recursive(args->repo, args->tree, "",
-				  0, 0, &ctx.pathspec,
+	ret = read_tree_recursive(args->repo, args->tree,
+				  0, &ctx.pathspec,
 				  reject_entry, &ctx);
 	clear_pathspec(&ctx.pathspec);
 	return ret != 0;
diff --git a/builtin/checkout.c b/builtin/checkout.c
index 2d6550bc3c8..21b742c0f07 100644
--- a/builtin/checkout.c
+++ b/builtin/checkout.c
@@ -155,7 +155,7 @@ static int update_some(const struct object_id *oid, struct strbuf *base,
 
 static int read_tree_some(struct tree *tree, const struct pathspec *pathspec)
 {
-	read_tree_recursive(the_repository, tree, "", 0, 0,
+	read_tree_recursive(the_repository, tree, 0,
 			    pathspec, update_some, NULL);
 
 	/* update the index with the given tree's info
diff --git a/builtin/log.c b/builtin/log.c
index f67b67d80ed..ffa3fb8c286 100644
--- a/builtin/log.c
+++ b/builtin/log.c
@@ -681,8 +681,8 @@ int cmd_show(int argc, const char **argv, const char *prefix)
 					diff_get_color_opt(&rev.diffopt, DIFF_COMMIT),
 					name,
 					diff_get_color_opt(&rev.diffopt, DIFF_RESET));
-			read_tree_recursive(the_repository, (struct tree *)o, "",
-					    0, 0, &match_all, show_tree_object,
+			read_tree_recursive(the_repository, (struct tree *)o,
+					    0, &match_all, show_tree_object,
 					    rev.diffopt.file);
 			rev.shown_one = 1;
 			break;
diff --git a/builtin/ls-files.c b/builtin/ls-files.c
index c0349a7b206..2c609428eea 100644
--- a/builtin/ls-files.c
+++ b/builtin/ls-files.c
@@ -483,7 +483,7 @@ void overlay_tree_on_index(struct index_state *istate,
 			       PATHSPEC_PREFER_CWD, prefix, matchbuf);
 	} else
 		memset(&pathspec, 0, sizeof(pathspec));
-	if (read_tree_recursive(the_repository, tree, "", 0, 1,
+	if (read_tree_recursive(the_repository, tree, 1,
 				&pathspec, read_one_entry_quick, istate))
 		die("unable to read tree entries %s", tree_name);
 
diff --git a/builtin/ls-tree.c b/builtin/ls-tree.c
index 7cad3f24ebd..7d3fb2e6d0f 100644
--- a/builtin/ls-tree.c
+++ b/builtin/ls-tree.c
@@ -185,6 +185,6 @@ int cmd_ls_tree(int argc, const char **argv, const char *prefix)
 	tree = parse_tree_indirect(&oid);
 	if (!tree)
 		die("not a tree object");
-	return !!read_tree_recursive(the_repository, tree, "", 0, 0,
+	return !!read_tree_recursive(the_repository, tree, 0,
 				     &pathspec, show_tree, NULL);
 }
diff --git a/merge-recursive.c b/merge-recursive.c
index b052974f191..fa7602ff0f2 100644
--- a/merge-recursive.c
+++ b/merge-recursive.c
@@ -473,7 +473,7 @@ static void get_files_dirs(struct merge_options *opt, struct tree *tree)
 {
 	struct pathspec match_all;
 	memset(&match_all, 0, sizeof(match_all));
-	read_tree_recursive(opt->repo, tree, "", 0, 0,
+	read_tree_recursive(opt->repo, tree, 0,
 			    &match_all, save_files_dirs, opt);
 }
 
diff --git a/tree.c b/tree.c
index c1bde9314d0..285633892c2 100644
--- a/tree.c
+++ b/tree.c
@@ -82,14 +82,12 @@ static int read_tree_1(struct repository *r,
 
 int read_tree_recursive(struct repository *r,
 			struct tree *tree,
-			const char *base, int baselen,
 			int stage, const struct pathspec *pathspec,
 			read_tree_fn_t fn, void *context)
 {
 	struct strbuf sb = STRBUF_INIT;
 	int ret;
 
-	strbuf_add(&sb, base, baselen);
 	ret = read_tree_1(r, tree, &sb, stage, pathspec, fn, context);
 	strbuf_release(&sb);
 	return ret;
diff --git a/tree.h b/tree.h
index 34549c86c9f..9a0fd3221e3 100644
--- a/tree.h
+++ b/tree.h
@@ -33,7 +33,6 @@ typedef int (*read_tree_fn_t)(const struct object_id *, struct strbuf *, const c
 
 int read_tree_recursive(struct repository *r,
 			struct tree *tree,
-			const char *base, int baselen,
 			int stage, const struct pathspec *pathspec,
 			read_tree_fn_t fn, void *context);
 
-- 
2.31.0.rc0.126.g04f22c5b82


^ permalink raw reply	[flat|nested] 262+ messages in thread

* [PATCH 7/7] tree.h API: remove "stage" parameter from read_tree_recursive()
  2009-04-18  0:29 [PATCH] read_tree(): pass "int stage" as context to read_tree_recursive() Nguyễn Thái Ngọc Duy
                   ` (6 preceding siblings ...)
  2021-03-06 19:34 ` [PATCH 6/7] tree.h API: remove support for starting at prefix != "" Ævar Arnfjörð Bjarmason
@ 2021-03-06 19:34 ` Ævar Arnfjörð Bjarmason
  7 siblings, 0 replies; 262+ messages in thread
From: Ævar Arnfjörð Bjarmason @ 2021-03-06 19:34 UTC (permalink / raw)
  To: git
  Cc: Junio C Hamano, Elijah Newren,
	Nguyễn Thái Ngọc Duy,
	Ævar Arnfjörð Bjarmason

The read_tree_recursive() function took a "stage" parameter that is
passed through as-is. As it turns out nothing used this parameter in a
way that they couldn't just move to the callback function they
defined, so let's get rid of it.

If anyone needs to pass such information in the future they can use
the "void *context" parameter.

Signed-off-by: Ævar Arnfjörð Bjarmason <avarab@gmail.com>
---
 archive.c          |  9 +++++----
 builtin/checkout.c |  4 ++--
 builtin/log.c      |  4 ++--
 builtin/ls-files.c |  6 +++---
 builtin/ls-tree.c  |  4 ++--
 merge-recursive.c  |  4 ++--
 tree.c             | 10 +++++-----
 tree.h             |  4 ++--
 8 files changed, 23 insertions(+), 22 deletions(-)

diff --git a/archive.c b/archive.c
index 9394f170f7f..6669a4bd147 100644
--- a/archive.c
+++ b/archive.c
@@ -231,9 +231,10 @@ static int write_directory(struct archiver_context *c)
 
 static int queue_or_write_archive_entry(const struct object_id *oid,
 		struct strbuf *base, const char *filename,
-		unsigned mode, int stage, void *context)
+		unsigned mode, void *context)
 {
 	struct archiver_context *c = context;
+	int stage = 0;
 
 	while (c->bottom &&
 	       !(base->len >= c->bottom->len &&
@@ -317,7 +318,7 @@ int write_archive_entries(struct archiver_args *args,
 	}
 
 	err = read_tree_recursive(args->repo, args->tree,
-				  0, &args->pathspec,
+				  &args->pathspec,
 				  queue_or_write_archive_entry,
 				  &context);
 	if (err == READ_TREE_RECURSIVE)
@@ -378,7 +379,7 @@ struct path_exists_context {
 
 static int reject_entry(const struct object_id *oid, struct strbuf *base,
 			const char *filename, unsigned mode,
-			int stage, void *context)
+			void *context)
 {
 	int ret = -1;
 	struct path_exists_context *ctx = context;
@@ -406,7 +407,7 @@ static int path_exists(struct archiver_args *args, const char *path)
 	parse_pathspec(&ctx.pathspec, 0, 0, "", paths);
 	ctx.pathspec.recursive = 1;
 	ret = read_tree_recursive(args->repo, args->tree,
-				  0, &ctx.pathspec,
+				  &ctx.pathspec,
 				  reject_entry, &ctx);
 	clear_pathspec(&ctx.pathspec);
 	return ret != 0;
diff --git a/builtin/checkout.c b/builtin/checkout.c
index 21b742c0f07..2c2d58a230f 100644
--- a/builtin/checkout.c
+++ b/builtin/checkout.c
@@ -114,7 +114,7 @@ static int post_checkout_hook(struct commit *old_commit, struct commit *new_comm
 }
 
 static int update_some(const struct object_id *oid, struct strbuf *base,
-		const char *pathname, unsigned mode, int stage, void *context)
+		const char *pathname, unsigned mode, void *context)
 {
 	int len;
 	struct cache_entry *ce;
@@ -155,7 +155,7 @@ static int update_some(const struct object_id *oid, struct strbuf *base,
 
 static int read_tree_some(struct tree *tree, const struct pathspec *pathspec)
 {
-	read_tree_recursive(the_repository, tree, 0,
+	read_tree_recursive(the_repository, tree,
 			    pathspec, update_some, NULL);
 
 	/* update the index with the given tree's info
diff --git a/builtin/log.c b/builtin/log.c
index ffa3fb8c286..58acb2b76ab 100644
--- a/builtin/log.c
+++ b/builtin/log.c
@@ -599,7 +599,7 @@ static int show_tag_object(const struct object_id *oid, struct rev_info *rev)
 
 static int show_tree_object(const struct object_id *oid,
 		struct strbuf *base,
-		const char *pathname, unsigned mode, int stage, void *context)
+		const char *pathname, unsigned mode, void *context)
 {
 	FILE *file = context;
 	fprintf(file, "%s%s\n", pathname, S_ISDIR(mode) ? "/" : "");
@@ -682,7 +682,7 @@ int cmd_show(int argc, const char **argv, const char *prefix)
 					name,
 					diff_get_color_opt(&rev.diffopt, DIFF_RESET));
 			read_tree_recursive(the_repository, (struct tree *)o,
-					    0, &match_all, show_tree_object,
+					    &match_all, show_tree_object,
 					    rev.diffopt.file);
 			rev.shown_one = 1;
 			break;
diff --git a/builtin/ls-files.c b/builtin/ls-files.c
index 2c609428eea..8ba13b69c97 100644
--- a/builtin/ls-files.c
+++ b/builtin/ls-files.c
@@ -424,7 +424,7 @@ static int read_one_entry_quick(const struct object_id *oid,
 				struct strbuf *base,
 				const char *pathname,
 				unsigned mode,
-				int stage, void *context)
+				void *context)
 {
 	struct index_state *istate = context;
 	int len;
@@ -437,7 +437,7 @@ static int read_one_entry_quick(const struct object_id *oid,
 	ce = make_empty_cache_entry(istate, base->len + len);
 
 	ce->ce_mode = create_ce_mode(mode);
-	ce->ce_flags = create_ce_flags(stage);
+	ce->ce_flags = create_ce_flags(1);
 	ce->ce_namelen = base->len + len;
 	memcpy(ce->name, base->buf, base->len);
 	memcpy(ce->name + base->len, pathname, len+1);
@@ -483,7 +483,7 @@ void overlay_tree_on_index(struct index_state *istate,
 			       PATHSPEC_PREFER_CWD, prefix, matchbuf);
 	} else
 		memset(&pathspec, 0, sizeof(pathspec));
-	if (read_tree_recursive(the_repository, tree, 1,
+	if (read_tree_recursive(the_repository, tree,
 				&pathspec, read_one_entry_quick, istate))
 		die("unable to read tree entries %s", tree_name);
 
diff --git a/builtin/ls-tree.c b/builtin/ls-tree.c
index 7d3fb2e6d0f..dbb31217beb 100644
--- a/builtin/ls-tree.c
+++ b/builtin/ls-tree.c
@@ -62,7 +62,7 @@ static int show_recursive(const char *base, int baselen, const char *pathname)
 }
 
 static int show_tree(const struct object_id *oid, struct strbuf *base,
-		const char *pathname, unsigned mode, int stage, void *context)
+		const char *pathname, unsigned mode, void *context)
 {
 	int retval = 0;
 	int baselen;
@@ -185,6 +185,6 @@ int cmd_ls_tree(int argc, const char **argv, const char *prefix)
 	tree = parse_tree_indirect(&oid);
 	if (!tree)
 		die("not a tree object");
-	return !!read_tree_recursive(the_repository, tree, 0,
+	return !!read_tree_recursive(the_repository, tree,
 				     &pathspec, show_tree, NULL);
 }
diff --git a/merge-recursive.c b/merge-recursive.c
index fa7602ff0f2..1593f374495 100644
--- a/merge-recursive.c
+++ b/merge-recursive.c
@@ -453,7 +453,7 @@ static void unpack_trees_finish(struct merge_options *opt)
 
 static int save_files_dirs(const struct object_id *oid,
 			   struct strbuf *base, const char *path,
-			   unsigned int mode, int stage, void *context)
+			   unsigned int mode, void *context)
 {
 	struct path_hashmap_entry *entry;
 	int baselen = base->len;
@@ -473,7 +473,7 @@ static void get_files_dirs(struct merge_options *opt, struct tree *tree)
 {
 	struct pathspec match_all;
 	memset(&match_all, 0, sizeof(match_all));
-	read_tree_recursive(opt->repo, tree, 0,
+	read_tree_recursive(opt->repo, tree,
 			    &match_all, save_files_dirs, opt);
 }
 
diff --git a/tree.c b/tree.c
index 285633892c2..3de41e37364 100644
--- a/tree.c
+++ b/tree.c
@@ -12,7 +12,7 @@ const char *tree_type = "tree";
 
 static int read_tree_1(struct repository *r,
 		       struct tree *tree, struct strbuf *base,
-		       int stage, const struct pathspec *pathspec,
+		       const struct pathspec *pathspec,
 		       read_tree_fn_t fn, void *context)
 {
 	struct tree_desc desc;
@@ -37,7 +37,7 @@ static int read_tree_1(struct repository *r,
 		}
 
 		switch (fn(&entry.oid, base,
-			   entry.path, entry.mode, stage, context)) {
+			   entry.path, entry.mode, context)) {
 		case 0:
 			continue;
 		case READ_TREE_RECURSIVE:
@@ -71,7 +71,7 @@ static int read_tree_1(struct repository *r,
 		strbuf_add(base, entry.path, len);
 		strbuf_addch(base, '/');
 		retval = read_tree_1(r, lookup_tree(r, &oid),
-				     base, stage, pathspec,
+				     base, pathspec,
 				     fn, context);
 		strbuf_setlen(base, oldlen);
 		if (retval)
@@ -82,13 +82,13 @@ static int read_tree_1(struct repository *r,
 
 int read_tree_recursive(struct repository *r,
 			struct tree *tree,
-			int stage, const struct pathspec *pathspec,
+			const struct pathspec *pathspec,
 			read_tree_fn_t fn, void *context)
 {
 	struct strbuf sb = STRBUF_INIT;
 	int ret;
 
-	ret = read_tree_1(r, tree, &sb, stage, pathspec, fn, context);
+	ret = read_tree_1(r, tree, &sb, pathspec, fn, context);
 	strbuf_release(&sb);
 	return ret;
 }
diff --git a/tree.h b/tree.h
index 9a0fd3221e3..e7b851c6abd 100644
--- a/tree.h
+++ b/tree.h
@@ -29,11 +29,11 @@ void free_tree_buffer(struct tree *tree);
 struct tree *parse_tree_indirect(const struct object_id *oid);
 
 #define READ_TREE_RECURSIVE 1
-typedef int (*read_tree_fn_t)(const struct object_id *, struct strbuf *, const char *, unsigned int, int, void *);
+typedef int (*read_tree_fn_t)(const struct object_id *, struct strbuf *, const char *, unsigned int, void *);
 
 int read_tree_recursive(struct repository *r,
 			struct tree *tree,
-			int stage, const struct pathspec *pathspec,
+			const struct pathspec *pathspec,
 			read_tree_fn_t fn, void *context);
 
 #endif /* TREE_H */
-- 
2.31.0.rc0.126.g04f22c5b82


^ permalink raw reply	[flat|nested] 262+ messages in thread

* Re: [PATCH 3/7] ls-files: remove cache juggling + sorting
  2021-03-06 19:34 ` [PATCH 3/7] ls-files: remove cache juggling + sorting Ævar Arnfjörð Bjarmason
@ 2021-03-06 21:37   ` Elijah Newren
  0 siblings, 0 replies; 262+ messages in thread
From: Elijah Newren @ 2021-03-06 21:37 UTC (permalink / raw)
  To: Ævar Arnfjörð Bjarmason
  Cc: Git Mailing List, Junio C Hamano, Nguyễn Thái Ngọc Duy

On Sat, Mar 6, 2021 at 11:35 AM Ævar Arnfjörð Bjarmason
<avarab@gmail.com> wrote:
>
> Remove the "ce_stage(ce) == 1" and "Sort the cache entry" code from
> read_tree(), which allows us to remove the function entirely and move
> over to read_tree_recursive().

Removing ce_stage(ce) == 1 and the use of read_one_entry() as the
read_tree_fn_t, keeping read_one_entry_quick() as read_tree_fn_t in
all cases.

This basically means you are assuming there are no entries with
ce_stage(ce) == 1 to start with; what if the user calls `ls-files
--with-tree` when in the middle of a merge conflict?  Will those
entries be duplicated and/or overwritten?

> I don't think the "Sort the cached entry" code was needed here, see
> af3785dc5a7 (Optimize "diff --cached" performance., 2007-08-09) for
> the use-case it was intended for. The only user of this code is
> "ls-files --with-tree", which isn't the sort of use-case that needs to
> care about "ce_stage(ce) != 0" or sorting tree entries.

Could you spell this out more?  I don't understand.  The initial index
might be something like (using the syntax of filename, stage):
    file   0
    random   0
    some   0
and after read_tree_recursive() reading into stage 1, wouldn't it be
something like
    file   0
    random   0
    some   0
    file   1
    some   1
    strange   1
when the ordering should be
    file   0
    file   1
    random   0
    some   0
    some   1
    strange   1
?

I'm probably missing something here.

>
> Signed-off-by: Ævar Arnfjörð Bjarmason <avarab@gmail.com>
> ---
>  builtin/ls-files.c | 76 +++++++---------------------------------------
>  1 file changed, 11 insertions(+), 65 deletions(-)
>
> diff --git a/builtin/ls-files.c b/builtin/ls-files.c
> index 74d572a3e4a..f5239437809 100644
> --- a/builtin/ls-files.c
> +++ b/builtin/ls-files.c
> @@ -12,7 +12,6 @@
>  #include "dir.h"
>  #include "builtin.h"
>  #include "tree.h"
> -#include "cache-tree.h"
>  #include "parse-options.h"
>  #include "resolve-undo.h"
>  #include "string-list.h"
> @@ -421,12 +420,15 @@ static int get_common_prefix_len(const char *common_prefix)
>         return common_prefix_len;
>  }
>
> -static int read_one_entry_opt(struct index_state *istate,
> -                             const struct object_id *oid,
> -                             const char *base, int baselen,
> -                             const char *pathname,
> -                             unsigned mode, int stage, int opt)
> +static int read_one_entry_quick(const struct object_id *oid,
> +                               struct strbuf *basebuf,
> +                               const char *pathname,
> +                               unsigned mode,
> +                               int stage, void *context)
>  {
> +       struct index_state *istate = context;
> +       const char *base = basebuf->buf;
> +       const int baselen = basebuf->len;
>         int len;
>         struct cache_entry *ce;
>
> @@ -442,64 +444,7 @@ static int read_one_entry_opt(struct index_state *istate,
>         memcpy(ce->name, base, baselen);
>         memcpy(ce->name + baselen, pathname, len+1);
>         oidcpy(&ce->oid, oid);
> -       return add_index_entry(istate, ce, opt);
> -}
> -
> -static int read_one_entry(const struct object_id *oid, struct strbuf *base,
> -                         const char *pathname, unsigned mode, int stage,
> -                         void *context)
> -{
> -       struct index_state *istate = context;
> -       return read_one_entry_opt(istate, oid, base->buf, base->len, pathname,
> -                                 mode, stage,
> -                                 ADD_CACHE_OK_TO_ADD|ADD_CACHE_SKIP_DFCHECK);
> -}
> -
> -/*
> - * This is used when the caller knows there is no existing entries at
> - * the stage that will conflict with the entry being added.
> - */
> -static int read_one_entry_quick(const struct object_id *oid, struct strbuf *base,
> -                               const char *pathname, unsigned mode, int stage,
> -                               void *context)
> -{
> -       struct index_state *istate = context;
> -       return read_one_entry_opt(istate, oid, base->buf, base->len, pathname,
> -                                 mode, stage,
> -                                 ADD_CACHE_JUST_APPEND);
> -}
> -
> -
> -static int read_tree(struct repository *r, struct tree *tree,
> -                    struct pathspec *match, struct index_state *istate)
> -{
> -       read_tree_fn_t fn = NULL;
> -       int i, err;
> -
> -
> -       /*
> -        * See if we have cache entry at the stage.  If so,
> -        * do it the original slow way, otherwise, append and then
> -        * sort at the end.
> -        */
> -       for (i = 0; !fn && i < istate->cache_nr; i++) {
> -               const struct cache_entry *ce = istate->cache[i];
> -               if (ce_stage(ce) == 1)
> -                       fn = read_one_entry;
> -       }
> -
> -       if (!fn)
> -               fn = read_one_entry_quick;
> -       err = read_tree_recursive(r, tree, "", 0, 1, match, fn, istate);
> -       if (fn == read_one_entry || err)
> -               return err;
> -
> -       /*
> -        * Sort the cache entry -- we need to nuke the cache tree, though.
> -        */
> -       cache_tree_free(&istate->cache_tree);
> -       QSORT(istate->cache, istate->cache_nr, cmp_cache_name_compare);
> -       return 0;
> +       return add_index_entry(istate, ce, ADD_CACHE_JUST_APPEND);
>  }
>
>  /*
> @@ -540,7 +485,8 @@ void overlay_tree_on_index(struct index_state *istate,
>                                PATHSPEC_PREFER_CWD, prefix, matchbuf);
>         } else
>                 memset(&pathspec, 0, sizeof(pathspec));
> -       if (read_tree(the_repository, tree, &pathspec, istate))
> +       if (read_tree_recursive(the_repository, tree, "", 0, 1,
> +                               &pathspec, read_one_entry_quick, istate))
>                 die("unable to read tree entries %s", tree_name);
>
>         for (i = 0; i < istate->cache_nr; i++) {
> --
> 2.31.0.rc0.126.g04f22c5b82

^ permalink raw reply	[flat|nested] 262+ messages in thread

* Re: [PATCH 6/7] tree.h API: remove support for starting at prefix != ""
  2021-03-06 19:34 ` [PATCH 6/7] tree.h API: remove support for starting at prefix != "" Ævar Arnfjörð Bjarmason
@ 2021-03-06 21:55   ` Elijah Newren
  0 siblings, 0 replies; 262+ messages in thread
From: Elijah Newren @ 2021-03-06 21:55 UTC (permalink / raw)
  To: Ævar Arnfjörð Bjarmason
  Cc: Git Mailing List, Junio C Hamano, Nguyễn Thái Ngọc Duy

On Sat, Mar 6, 2021 at 11:35 AM Ævar Arnfjörð Bjarmason
<avarab@gmail.com> wrote:
>
> Every caller or the read_tree_recursive() function hardcoded a

s/or/of/?

> starting point of "" in the tree. So let's simply remove that
> parameter.

Interesting.  It appears that read_tree_recursive() was the last
function to call read_tree_recursive() with a starting point other
than "", but that was changed in commit ffd31f661d ("Reimplement
read_tree_recursive() using tree_entry_interesting()", 2011-03-25).

The last caller of read_tree_recursive() other than itself to call it
with base != "", was ebfbdb340a ("Git archive and trailing "/" in
prefix", 2009-10-08).

> It might be useful in the future to get this functionality back,
> there's no reason we won't have a read_tree_recursive() use-case that
> would want to start in a subdirectory.

This paragraph is very hard to parse.

> But if and when that happens we can just add something like a
> read_tree_recursive_subdir() and have both read_tree_recursive() and
> that function be a thin wrapper for read_tree_1().

Starting with "But if and when that happens" suggests this shouldn't
be an independent paragraph.

> In the meantime there's no reason to keep around what amounts to dead
> code just in case we need it in the future.

Makes sense to me.

> Signed-off-by: Ævar Arnfjörð Bjarmason <avarab@gmail.com>
> ---
>  archive.c          | 8 ++++----
>  builtin/checkout.c | 2 +-
>  builtin/log.c      | 4 ++--
>  builtin/ls-files.c | 2 +-
>  builtin/ls-tree.c  | 2 +-
>  merge-recursive.c  | 2 +-
>  tree.c             | 2 --
>  tree.h             | 1 -
>  8 files changed, 10 insertions(+), 13 deletions(-)
>
> diff --git a/archive.c b/archive.c
> index 5919d9e5050..9394f170f7f 100644
> --- a/archive.c
> +++ b/archive.c
> @@ -316,8 +316,8 @@ int write_archive_entries(struct archiver_args *args,
>                 git_attr_set_direction(GIT_ATTR_INDEX);
>         }
>
> -       err = read_tree_recursive(args->repo, args->tree, "",
> -                                 0, 0, &args->pathspec,
> +       err = read_tree_recursive(args->repo, args->tree,
> +                                 0, &args->pathspec,
>                                   queue_or_write_archive_entry,
>                                   &context);
>         if (err == READ_TREE_RECURSIVE)
> @@ -405,8 +405,8 @@ static int path_exists(struct archiver_args *args, const char *path)
>         ctx.args = args;
>         parse_pathspec(&ctx.pathspec, 0, 0, "", paths);
>         ctx.pathspec.recursive = 1;
> -       ret = read_tree_recursive(args->repo, args->tree, "",
> -                                 0, 0, &ctx.pathspec,
> +       ret = read_tree_recursive(args->repo, args->tree,
> +                                 0, &ctx.pathspec,
>                                   reject_entry, &ctx);
>         clear_pathspec(&ctx.pathspec);
>         return ret != 0;
> diff --git a/builtin/checkout.c b/builtin/checkout.c
> index 2d6550bc3c8..21b742c0f07 100644
> --- a/builtin/checkout.c
> +++ b/builtin/checkout.c
> @@ -155,7 +155,7 @@ static int update_some(const struct object_id *oid, struct strbuf *base,
>
>  static int read_tree_some(struct tree *tree, const struct pathspec *pathspec)
>  {
> -       read_tree_recursive(the_repository, tree, "", 0, 0,
> +       read_tree_recursive(the_repository, tree, 0,
>                             pathspec, update_some, NULL);
>
>         /* update the index with the given tree's info
> diff --git a/builtin/log.c b/builtin/log.c
> index f67b67d80ed..ffa3fb8c286 100644
> --- a/builtin/log.c
> +++ b/builtin/log.c
> @@ -681,8 +681,8 @@ int cmd_show(int argc, const char **argv, const char *prefix)
>                                         diff_get_color_opt(&rev.diffopt, DIFF_COMMIT),
>                                         name,
>                                         diff_get_color_opt(&rev.diffopt, DIFF_RESET));
> -                       read_tree_recursive(the_repository, (struct tree *)o, "",
> -                                           0, 0, &match_all, show_tree_object,
> +                       read_tree_recursive(the_repository, (struct tree *)o,
> +                                           0, &match_all, show_tree_object,
>                                             rev.diffopt.file);
>                         rev.shown_one = 1;
>                         break;
> diff --git a/builtin/ls-files.c b/builtin/ls-files.c
> index c0349a7b206..2c609428eea 100644
> --- a/builtin/ls-files.c
> +++ b/builtin/ls-files.c
> @@ -483,7 +483,7 @@ void overlay_tree_on_index(struct index_state *istate,
>                                PATHSPEC_PREFER_CWD, prefix, matchbuf);
>         } else
>                 memset(&pathspec, 0, sizeof(pathspec));
> -       if (read_tree_recursive(the_repository, tree, "", 0, 1,
> +       if (read_tree_recursive(the_repository, tree, 1,
>                                 &pathspec, read_one_entry_quick, istate))
>                 die("unable to read tree entries %s", tree_name);
>
> diff --git a/builtin/ls-tree.c b/builtin/ls-tree.c
> index 7cad3f24ebd..7d3fb2e6d0f 100644
> --- a/builtin/ls-tree.c
> +++ b/builtin/ls-tree.c
> @@ -185,6 +185,6 @@ int cmd_ls_tree(int argc, const char **argv, const char *prefix)
>         tree = parse_tree_indirect(&oid);
>         if (!tree)
>                 die("not a tree object");
> -       return !!read_tree_recursive(the_repository, tree, "", 0, 0,
> +       return !!read_tree_recursive(the_repository, tree, 0,
>                                      &pathspec, show_tree, NULL);
>  }
> diff --git a/merge-recursive.c b/merge-recursive.c
> index b052974f191..fa7602ff0f2 100644
> --- a/merge-recursive.c
> +++ b/merge-recursive.c
> @@ -473,7 +473,7 @@ static void get_files_dirs(struct merge_options *opt, struct tree *tree)
>  {
>         struct pathspec match_all;
>         memset(&match_all, 0, sizeof(match_all));
> -       read_tree_recursive(opt->repo, tree, "", 0, 0,
> +       read_tree_recursive(opt->repo, tree, 0,
>                             &match_all, save_files_dirs, opt);
>  }
>
> diff --git a/tree.c b/tree.c
> index c1bde9314d0..285633892c2 100644
> --- a/tree.c
> +++ b/tree.c
> @@ -82,14 +82,12 @@ static int read_tree_1(struct repository *r,
>
>  int read_tree_recursive(struct repository *r,
>                         struct tree *tree,
> -                       const char *base, int baselen,
>                         int stage, const struct pathspec *pathspec,
>                         read_tree_fn_t fn, void *context)
>  {
>         struct strbuf sb = STRBUF_INIT;
>         int ret;
>
> -       strbuf_add(&sb, base, baselen);
>         ret = read_tree_1(r, tree, &sb, stage, pathspec, fn, context);
>         strbuf_release(&sb);
>         return ret;
> diff --git a/tree.h b/tree.h
> index 34549c86c9f..9a0fd3221e3 100644
> --- a/tree.h
> +++ b/tree.h
> @@ -33,7 +33,6 @@ typedef int (*read_tree_fn_t)(const struct object_id *, struct strbuf *, const c
>
>  int read_tree_recursive(struct repository *r,
>                         struct tree *tree,
> -                       const char *base, int baselen,
>                         int stage, const struct pathspec *pathspec,
>                         read_tree_fn_t fn, void *context);
>
> --
> 2.31.0.rc0.126.g04f22c5b82

Looks good.

^ permalink raw reply	[flat|nested] 262+ messages in thread

* Re: [PATCH 0/7] Move the read_tree() function to its only user
  2021-03-06 19:34 ` [PATCH 0/7] Move the read_tree() function to its only user Ævar Arnfjörð Bjarmason
@ 2021-03-06 22:06   ` Elijah Newren
  2021-03-08  2:21   ` [PATCH v2 0/6] " Ævar Arnfjörð Bjarmason
                     ` (6 subsequent siblings)
  7 siblings, 0 replies; 262+ messages in thread
From: Elijah Newren @ 2021-03-06 22:06 UTC (permalink / raw)
  To: Ævar Arnfjörð Bjarmason
  Cc: Git Mailing List, Junio C Hamano, Nguyễn Thái Ngọc Duy

On Sat, Mar 6, 2021 at 11:35 AM Ævar Arnfjörð Bjarmason
<avarab@gmail.com> wrote:
>
> This is a small cleanup series to remove move the last user of
> read_tree() over to read_tree_recursive(), and while we're at it
> adjust the API of read_tree_fn_t to its current use-case.
>
> I found out after writing this that there had been a FIXME comment
> (never made it into git.git) about this from mid-2009:
> https://lore.kernel.org/git/1240014568-3675-1-git-send-email-pclouds@gmail.com/
>
> Ævar Arnfjörð Bjarmason (7):
>   tree.c API: move read_tree() into builtin/ls-files.c
>   ls-files: don't needlessly pass around stage variable
>   ls-files: remove cache juggling + sorting
>   merge-ort: move cmp_cache_name_compare() from tree.c
>   ls-files: refactor read_one_entry_quick() to use a strbuf
>   tree.h API: remove support for starting at prefix != ""
>   tree.h API: remove "stage" parameter from read_tree_recursive()

I read over all 7 patches.  For the most part, they look good.

Some of the wording in the commit message for patch 6 seemed confusing
and could use some touch-ups; it may also be worth documenting when
the code stopped having any callers with a base other than "".

For patch 3 (the actual removal of read_tree()), either I'm
misunderstanding something, or the changes look problematic and
unsafe.  I'm hoping it's the former.

^ permalink raw reply	[flat|nested] 262+ messages in thread

* [PATCH v2 0/6] Move the read_tree() function to its only user
  2021-03-06 19:34 ` [PATCH 0/7] Move the read_tree() function to its only user Ævar Arnfjörð Bjarmason
  2021-03-06 22:06   ` Elijah Newren
@ 2021-03-08  2:21   ` Ævar Arnfjörð Bjarmason
  2021-03-08 15:06     ` [PATCH 00/30] tree-walk: mostly "mode" to "enum object_type" Ævar Arnfjörð Bjarmason
                       ` (41 more replies)
  2021-03-08  2:21   ` [PATCH v2 1/6] ls-files tests: add meaningful --with-tree tests Ævar Arnfjörð Bjarmason
                     ` (5 subsequent siblings)
  7 siblings, 42 replies; 262+ messages in thread
From: Ævar Arnfjörð Bjarmason @ 2021-03-08  2:21 UTC (permalink / raw)
  To: git; +Cc: Junio C Hamano, Elijah Newren, Ævar Arnfjörð Bjarmason

v1 of this series over-removed code supporting the "ls-files
--with-tree=*" parameter. In v2 there's no change to its behavior,
just refactoring away of read_tree() from the tree.c API and the
cleanup of read_tree_recursive(). Thanks to Elijah for spotting that.

I've added a test at the start of this series that would have caught
that regression in v1 (and more).

1. https://lore.kernel.org/git/CABPp-BF982muRS4GO=zYegvetQyrPMwaEM3uEBvcbPRP=krfmQ@mail.gmail.com/

Ævar Arnfjörð Bjarmason (6):
  ls-files tests: add meaningful --with-tree tests
  tree.c API: move read_tree() into builtin/ls-files.c
  ls-files: don't needlessly pass around stage variable
  ls-files: refactor away read_tree()
  tree.h API: remove support for starting at prefix != ""
  tree.h API: remove "stage" parameter from read_tree_recursive()

 archive.c                     |  13 +++--
 builtin/checkout.c            |   4 +-
 builtin/log.c                 |   6 +-
 builtin/ls-files.c            |  76 ++++++++++++++++++++++++-
 builtin/ls-tree.c             |   4 +-
 merge-recursive.c             |   4 +-
 t/t3060-ls-files-with-tree.sh |  41 ++++++++++++++
 tree.c                        | 101 ++--------------------------------
 tree.h                        |  10 +---
 9 files changed, 139 insertions(+), 120 deletions(-)

Range-diff:
-:  ----------- > 1:  6416da0dee2 ls-files tests: add meaningful --with-tree tests
1:  020534164d3 ! 2:  765001b44cd tree.c API: move read_tree() into builtin/ls-files.c
    @@ tree.c: int cmp_cache_name_compare(const void *a_, const void *b_)
     
      ## tree.h ##
     @@ tree.h: int read_tree_recursive(struct repository *r,
    + 			const char *base, int baselen,
      			int stage, const struct pathspec *pathspec,
      			read_tree_fn_t fn, void *context);
    - 
    +-
     -int read_tree(struct repository *r, struct tree *tree,
     -	      int stage, struct pathspec *pathspec,
     -	      struct index_state *istate);
2:  6aa6ba2fbb5 = 3:  a71ffba7d04 ls-files: don't needlessly pass around stage variable
3:  4f27e5d2970 ! 4:  e78d1810b89 ls-files: remove cache juggling + sorting
    @@ Metadata
     Author: Ævar Arnfjörð Bjarmason <avarab@gmail.com>
     
      ## Commit message ##
    -    ls-files: remove cache juggling + sorting
    +    ls-files: refactor away read_tree()
     
    -    Remove the "ce_stage(ce) == 1" and "Sort the cache entry" code from
    -    read_tree(), which allows us to remove the function entirely and move
    -    over to read_tree_recursive().
    +    Refactor away the read_tree() function into its only user,
    +    overlay_tree_on_index().
     
    -    I don't think the "Sort the cached entry" code was needed here, see
    -    af3785dc5a7 (Optimize "diff --cached" performance., 2007-08-09) for
    -    the use-case it was intended for. The only user of this code is
    -    "ls-files --with-tree", which isn't the sort of use-case that needs to
    -    care about "ce_stage(ce) != 0" or sorting tree entries.
    +    First, change read_one_entry_opt() to use the strbuf parameter
    +    read_tree_recursive() passes down in place. This finishes up a partial
    +    refactoring started in 6a0b0b6de99 (tree.c: update read_tree_recursive
    +    callback to pass strbuf as base, 2014-11-30).
    +
    +    Moving the rest into overlay_tree_on_index() makes this index juggling
    +    we're doing easier to read.
     
         Signed-off-by: Ævar Arnfjörð Bjarmason <avarab@gmail.com>
     
      ## builtin/ls-files.c ##
    -@@
    - #include "dir.h"
    - #include "builtin.h"
    - #include "tree.h"
    --#include "cache-tree.h"
    - #include "parse-options.h"
    - #include "resolve-undo.h"
    - #include "string-list.h"
     @@ builtin/ls-files.c: static int get_common_prefix_len(const char *common_prefix)
    - 	return common_prefix_len;
    - }
      
    --static int read_one_entry_opt(struct index_state *istate,
    --			      const struct object_id *oid,
    + static int read_one_entry_opt(struct index_state *istate,
    + 			      const struct object_id *oid,
     -			      const char *base, int baselen,
    --			      const char *pathname,
    --			      unsigned mode, int stage, int opt)
    -+static int read_one_entry_quick(const struct object_id *oid,
    -+				struct strbuf *basebuf,
    -+				const char *pathname,
    -+				unsigned mode,
    -+				int stage, void *context)
    ++			      struct strbuf *base,
    + 			      const char *pathname,
    + 			      unsigned mode, int stage, int opt)
      {
    -+	struct index_state *istate = context;
    -+	const char *base = basebuf->buf;
    -+	const int baselen = basebuf->len;
    - 	int len;
    - 	struct cache_entry *ce;
    - 
     @@ builtin/ls-files.c: static int read_one_entry_opt(struct index_state *istate,
    - 	memcpy(ce->name, base, baselen);
    - 	memcpy(ce->name + baselen, pathname, len+1);
    + 		return READ_TREE_RECURSIVE;
    + 
    + 	len = strlen(pathname);
    +-	ce = make_empty_cache_entry(istate, baselen + len);
    ++	ce = make_empty_cache_entry(istate, base->len + len);
    + 
    + 	ce->ce_mode = create_ce_mode(mode);
    + 	ce->ce_flags = create_ce_flags(stage);
    +-	ce->ce_namelen = baselen + len;
    +-	memcpy(ce->name, base, baselen);
    +-	memcpy(ce->name + baselen, pathname, len+1);
    ++	ce->ce_namelen = base->len + len;
    ++	memcpy(ce->name, base->buf, base->len);
    ++	memcpy(ce->name + base->len, pathname, len+1);
      	oidcpy(&ce->oid, oid);
    --	return add_index_entry(istate, ce, opt);
    --}
    --
    --static int read_one_entry(const struct object_id *oid, struct strbuf *base,
    --			  const char *pathname, unsigned mode, int stage,
    --			  void *context)
    --{
    --	struct index_state *istate = context;
    + 	return add_index_entry(istate, ce, opt);
    + }
    +@@ builtin/ls-files.c: static int read_one_entry(const struct object_id *oid, struct strbuf *base,
    + 			  void *context)
    + {
    + 	struct index_state *istate = context;
     -	return read_one_entry_opt(istate, oid, base->buf, base->len, pathname,
    --				  mode, stage,
    --				  ADD_CACHE_OK_TO_ADD|ADD_CACHE_SKIP_DFCHECK);
    --}
    --
    --/*
    -- * This is used when the caller knows there is no existing entries at
    -- * the stage that will conflict with the entry being added.
    -- */
    --static int read_one_entry_quick(const struct object_id *oid, struct strbuf *base,
    --				const char *pathname, unsigned mode, int stage,
    --				void *context)
    --{
    --	struct index_state *istate = context;
    ++	return read_one_entry_opt(istate, oid, base, pathname,
    + 				  mode, stage,
    + 				  ADD_CACHE_OK_TO_ADD|ADD_CACHE_SKIP_DFCHECK);
    + }
    +@@ builtin/ls-files.c: static int read_one_entry_quick(const struct object_id *oid, struct strbuf *base
    + 				void *context)
    + {
    + 	struct index_state *istate = context;
     -	return read_one_entry_opt(istate, oid, base->buf, base->len, pathname,
    --				  mode, stage,
    --				  ADD_CACHE_JUST_APPEND);
    --}
    --
    ++	return read_one_entry_opt(istate, oid, base, pathname,
    + 				  mode, stage,
    + 				  ADD_CACHE_JUST_APPEND);
    + }
    + 
     -
     -static int read_tree(struct repository *r, struct tree *tree,
     -		     struct pathspec *match, struct index_state *istate)
    @@ builtin/ls-files.c: static int read_one_entry_opt(struct index_state *istate,
     -	cache_tree_free(&istate->cache_tree);
     -	QSORT(istate->cache, istate->cache_nr, cmp_cache_name_compare);
     -	return 0;
    -+	return add_index_entry(istate, ce, ADD_CACHE_JUST_APPEND);
    - }
    - 
    +-}
    +-
      /*
    +  * Read the tree specified with --with-tree option
    +  * (typically, HEAD) into stage #1 and then
    +@@ builtin/ls-files.c: void overlay_tree_on_index(struct index_state *istate,
    + 	struct pathspec pathspec;
    + 	struct cache_entry *last_stage0 = NULL;
    + 	int i;
    ++	read_tree_fn_t fn = NULL;
    ++	int err;
    + 
    + 	if (get_oid(tree_name, &oid))
    + 		die("tree-ish %s not found.", tree_name);
     @@ builtin/ls-files.c: void overlay_tree_on_index(struct index_state *istate,
      			       PATHSPEC_PREFER_CWD, prefix, matchbuf);
      	} else
      		memset(&pathspec, 0, sizeof(pathspec));
     -	if (read_tree(the_repository, tree, &pathspec, istate))
    -+	if (read_tree_recursive(the_repository, tree, "", 0, 1,
    -+				&pathspec, read_one_entry_quick, istate))
    ++
    ++	/*
    ++	 * See if we have cache entry at the stage.  If so,
    ++	 * do it the original slow way, otherwise, append and then
    ++	 * sort at the end.
    ++	 */
    ++	for (i = 0; !fn && i < istate->cache_nr; i++) {
    ++		const struct cache_entry *ce = istate->cache[i];
    ++		if (ce_stage(ce) == 1)
    ++			fn = read_one_entry;
    ++	}
    ++
    ++	if (!fn)
    ++		fn = read_one_entry_quick;
    ++	err = read_tree_recursive(the_repository, tree, "", 0, 1, &pathspec, fn, istate);
    ++	if (err)
      		die("unable to read tree entries %s", tree_name);
      
    ++	/*
    ++	 * Sort the cache entry -- we need to nuke the cache tree, though.
    ++	 */
    ++	if (fn == read_one_entry_quick) {
    ++		cache_tree_free(&istate->cache_tree);
    ++		QSORT(istate->cache, istate->cache_nr, cmp_cache_name_compare);
    ++	}
    ++
      	for (i = 0; i < istate->cache_nr; i++) {
    + 		struct cache_entry *ce = istate->cache[i];
    + 		switch (ce_stage(ce)) {
4:  33810d3c10c < -:  ----------- merge-ort: move cmp_cache_name_compare() from tree.c
5:  fb10246b85b < -:  ----------- ls-files: refactor read_one_entry_quick() to use a strbuf
6:  0c065615aec ! 5:  05eecdd7519 tree.h API: remove support for starting at prefix != ""
    @@ Metadata
      ## Commit message ##
         tree.h API: remove support for starting at prefix != ""
     
    -    Every caller or the read_tree_recursive() function hardcoded a
    +    Every caller of the read_tree_recursive() function hardcoded a
         starting point of "" in the tree. So let's simply remove that
         parameter.
     
    -    It might be useful in the future to get this functionality back,
    -    there's no reason we won't have a read_tree_recursive() use-case that
    -    would want to start in a subdirectory.
    +    The last function to call read_tree_recursive() with a non-"" path was
    +    read_tree_recursive() itself, but that was changed in
    +    ffd31f661d5 (Reimplement read_tree_recursive() using
    +    tree_entry_interesting(), 2011-03-25).
     
    -    But if and when that happens we can just add something like a
    -    read_tree_recursive_subdir() and have both read_tree_recursive() and
    -    that function be a thin wrapper for read_tree_1().
    +    If in the future we need to support recursively reading trees without
    +    starting at the root we can easily add a read_tree_recursive_subdir(),
    +    and make that function a thin wrapper for read_tree_1().
     
         In the meantime there's no reason to keep around what amounts to dead
    -    code just in case we need it in the future.
    +    code, just in case we need it in the future.
     
         Signed-off-by: Ævar Arnfjörð Bjarmason <avarab@gmail.com>
     
    @@ builtin/log.c: int cmd_show(int argc, const char **argv, const char *prefix)
     
      ## builtin/ls-files.c ##
     @@ builtin/ls-files.c: void overlay_tree_on_index(struct index_state *istate,
    - 			       PATHSPEC_PREFER_CWD, prefix, matchbuf);
    - 	} else
    - 		memset(&pathspec, 0, sizeof(pathspec));
    --	if (read_tree_recursive(the_repository, tree, "", 0, 1,
    -+	if (read_tree_recursive(the_repository, tree, 1,
    - 				&pathspec, read_one_entry_quick, istate))
    + 
    + 	if (!fn)
    + 		fn = read_one_entry_quick;
    +-	err = read_tree_recursive(the_repository, tree, "", 0, 1, &pathspec, fn, istate);
    ++	err = read_tree_recursive(the_repository, tree, 1, &pathspec, fn, istate);
    + 	if (err)
      		die("unable to read tree entries %s", tree_name);
      
     
    @@ tree.h: typedef int (*read_tree_fn_t)(const struct object_id *, struct strbuf *,
     -			const char *base, int baselen,
      			int stage, const struct pathspec *pathspec,
      			read_tree_fn_t fn, void *context);
    - 
    + #endif /* TREE_H */
7:  9685c7c5c50 ! 6:  fcecc82e1c8 tree.h API: remove "stage" parameter from read_tree_recursive()
    @@ builtin/log.c: int cmd_show(int argc, const char **argv, const char *prefix)
      			break;
     
      ## builtin/ls-files.c ##
    -@@ builtin/ls-files.c: static int read_one_entry_quick(const struct object_id *oid,
    - 				struct strbuf *base,
    - 				const char *pathname,
    - 				unsigned mode,
    --				int stage, void *context)
    -+				void *context)
    +@@ builtin/ls-files.c: static int read_one_entry_opt(struct index_state *istate,
    + 			      const struct object_id *oid,
    + 			      struct strbuf *base,
    + 			      const char *pathname,
    +-			      unsigned mode, int stage, int opt)
    ++			      unsigned mode, int opt)
      {
    - 	struct index_state *istate = context;
      	int len;
    -@@ builtin/ls-files.c: static int read_one_entry_quick(const struct object_id *oid,
    + 	struct cache_entry *ce;
    +@@ builtin/ls-files.c: static int read_one_entry_opt(struct index_state *istate,
      	ce = make_empty_cache_entry(istate, base->len + len);
      
      	ce->ce_mode = create_ce_mode(mode);
    @@ builtin/ls-files.c: static int read_one_entry_quick(const struct object_id *oid,
      	ce->ce_namelen = base->len + len;
      	memcpy(ce->name, base->buf, base->len);
      	memcpy(ce->name + base->len, pathname, len+1);
    +@@ builtin/ls-files.c: static int read_one_entry_opt(struct index_state *istate,
    + }
    + 
    + static int read_one_entry(const struct object_id *oid, struct strbuf *base,
    +-			  const char *pathname, unsigned mode, int stage,
    ++			  const char *pathname, unsigned mode,
    + 			  void *context)
    + {
    + 	struct index_state *istate = context;
    + 	return read_one_entry_opt(istate, oid, base, pathname,
    +-				  mode, stage,
    ++				  mode,
    + 				  ADD_CACHE_OK_TO_ADD|ADD_CACHE_SKIP_DFCHECK);
    + }
    + 
    +@@ builtin/ls-files.c: static int read_one_entry(const struct object_id *oid, struct strbuf *base,
    +  * the stage that will conflict with the entry being added.
    +  */
    + static int read_one_entry_quick(const struct object_id *oid, struct strbuf *base,
    +-				const char *pathname, unsigned mode, int stage,
    ++				const char *pathname, unsigned mode,
    + 				void *context)
    + {
    + 	struct index_state *istate = context;
    + 	return read_one_entry_opt(istate, oid, base, pathname,
    +-				  mode, stage,
    ++				  mode,
    + 				  ADD_CACHE_JUST_APPEND);
    + }
    + 
     @@ builtin/ls-files.c: void overlay_tree_on_index(struct index_state *istate,
    - 			       PATHSPEC_PREFER_CWD, prefix, matchbuf);
    - 	} else
    - 		memset(&pathspec, 0, sizeof(pathspec));
    --	if (read_tree_recursive(the_repository, tree, 1,
    -+	if (read_tree_recursive(the_repository, tree,
    - 				&pathspec, read_one_entry_quick, istate))
    + 
    + 	if (!fn)
    + 		fn = read_one_entry_quick;
    +-	err = read_tree_recursive(the_repository, tree, 1, &pathspec, fn, istate);
    ++	err = read_tree_recursive(the_repository, tree, &pathspec, fn, istate);
    + 	if (err)
      		die("unable to read tree entries %s", tree_name);
      
     
    @@ tree.c: static int read_tree_1(struct repository *r,
      }
     
      ## tree.h ##
    -@@ tree.h: void free_tree_buffer(struct tree *tree);
    - struct tree *parse_tree_indirect(const struct object_id *oid);
    +@@ tree.h: struct tree *parse_tree_indirect(const struct object_id *oid);
    + int cmp_cache_name_compare(const void *a_, const void *b_);
      
      #define READ_TREE_RECURSIVE 1
     -typedef int (*read_tree_fn_t)(const struct object_id *, struct strbuf *, const char *, unsigned int, int, void *);
    @@ tree.h: void free_tree_buffer(struct tree *tree);
     -			int stage, const struct pathspec *pathspec,
     +			const struct pathspec *pathspec,
      			read_tree_fn_t fn, void *context);
    - 
      #endif /* TREE_H */
-- 
2.31.0.rc0.126.g04f22c5b82


^ permalink raw reply	[flat|nested] 262+ messages in thread

* [PATCH v2 1/6] ls-files tests: add meaningful --with-tree tests
  2021-03-06 19:34 ` [PATCH 0/7] Move the read_tree() function to its only user Ævar Arnfjörð Bjarmason
  2021-03-06 22:06   ` Elijah Newren
  2021-03-08  2:21   ` [PATCH v2 0/6] " Ævar Arnfjörð Bjarmason
@ 2021-03-08  2:21   ` Ævar Arnfjörð Bjarmason
  2021-03-08  2:21   ` [PATCH v2 2/6] tree.c API: move read_tree() into builtin/ls-files.c Ævar Arnfjörð Bjarmason
                     ` (4 subsequent siblings)
  7 siblings, 0 replies; 262+ messages in thread
From: Ævar Arnfjörð Bjarmason @ 2021-03-08  2:21 UTC (permalink / raw)
  To: git; +Cc: Junio C Hamano, Elijah Newren, Ævar Arnfjörð Bjarmason

Add tests for "ls-files --with-tree". There was effectively no
coverage for any normal usage of this command, only the tests added in
54e1abce90e (Add test case for ls-files --with-tree, 2007-10-03) for
an obscure bug.

Signed-off-by: Ævar Arnfjörð Bjarmason <avarab@gmail.com>
---
 t/t3060-ls-files-with-tree.sh | 41 +++++++++++++++++++++++++++++++++++
 1 file changed, 41 insertions(+)

diff --git a/t/t3060-ls-files-with-tree.sh b/t/t3060-ls-files-with-tree.sh
index 52ed665fcd2..b257c792a46 100755
--- a/t/t3060-ls-files-with-tree.sh
+++ b/t/t3060-ls-files-with-tree.sh
@@ -47,6 +47,12 @@ test_expect_success setup '
 	git add .
 '
 
+test_expect_success 'usage' '
+	test_expect_code 128 git ls-files --with-tree=HEAD -u &&
+	test_expect_code 128 git ls-files --with-tree=HEAD -s &&
+	test_expect_code 128 git ls-files --recurse-submodules --with-tree=HEAD
+'
+
 test_expect_success 'git ls-files --with-tree should succeed from subdir' '
 	# We have to run from a sub-directory to trigger prune_path
 	# Then we finally get to run our --with-tree test
@@ -60,4 +66,39 @@ test_expect_success \
     'git ls-files --with-tree should add entries from named tree.' \
     'test_cmp expected output'
 
+test_expect_success 'no duplicates in --with-tree output' '
+	git ls-files --with-tree=HEAD >actual &&
+	sort -u actual >expected &&
+	test_cmp expected actual
+'
+
+test_expect_success 'setup: output in a conflict' '
+	test_create_repo conflict &&
+	test_commit -C conflict BASE file &&
+	test_commit -C conflict A file foo &&
+	git -C conflict reset --hard BASE &&
+	test_commit -C conflict B file bar
+'
+
+test_expect_success 'output in a conflict' '
+	test_must_fail git -C conflict merge A B &&
+	cat >expected <<-\EOF &&
+	file
+	file
+	file
+	file
+	EOF
+	git -C conflict ls-files --with-tree=HEAD >actual &&
+	test_cmp expected actual
+'
+
+test_expect_success 'output with removed .git/index' '
+	cat >expected <<-\EOF &&
+	file
+	EOF
+	rm conflict/.git/index &&
+	git -C conflict ls-files --with-tree=HEAD >actual &&
+	test_cmp expected actual
+'
+
 test_done
-- 
2.31.0.rc0.126.g04f22c5b82


^ permalink raw reply	[flat|nested] 262+ messages in thread

* [PATCH v2 2/6] tree.c API: move read_tree() into builtin/ls-files.c
  2021-03-06 19:34 ` [PATCH 0/7] Move the read_tree() function to its only user Ævar Arnfjörð Bjarmason
                     ` (2 preceding siblings ...)
  2021-03-08  2:21   ` [PATCH v2 1/6] ls-files tests: add meaningful --with-tree tests Ævar Arnfjörð Bjarmason
@ 2021-03-08  2:21   ` Ævar Arnfjörð Bjarmason
  2021-03-08 18:06     ` Junio C Hamano
  2021-03-12 21:41     ` Junio C Hamano
  2021-03-08  2:21   ` [PATCH v2 3/6] ls-files: don't needlessly pass around stage variable Ævar Arnfjörð Bjarmason
                     ` (3 subsequent siblings)
  7 siblings, 2 replies; 262+ messages in thread
From: Ævar Arnfjörð Bjarmason @ 2021-03-08  2:21 UTC (permalink / raw)
  To: git; +Cc: Junio C Hamano, Elijah Newren, Ævar Arnfjörð Bjarmason

Since the read_tree() API was added around the same time as
read_tree_recursive() in 94537c78a82 (Move "read_tree()" to
"tree.c"[...], 2005-04-22) and b12ec373b8e ([PATCH] Teach read-tree
about commit objects, 2005-04-20) things have gradually migrated over
to the read_tree_recursive() version.

Now builtin/ls-files.c is the last user of this code, let's move all
the relevant code there. This allows for subsequent simplification of
it, and an eventual move to read_tree_recursive().

Signed-off-by: Ævar Arnfjörð Bjarmason <avarab@gmail.com>
---
 builtin/ls-files.c | 91 ++++++++++++++++++++++++++++++++++++++++++++++
 tree.c             | 89 ---------------------------------------------
 tree.h             |  5 ---
 3 files changed, 91 insertions(+), 94 deletions(-)

diff --git a/builtin/ls-files.c b/builtin/ls-files.c
index f6f9e483b27..a4458622813 100644
--- a/builtin/ls-files.c
+++ b/builtin/ls-files.c
@@ -12,6 +12,7 @@
 #include "dir.h"
 #include "builtin.h"
 #include "tree.h"
+#include "cache-tree.h"
 #include "parse-options.h"
 #include "resolve-undo.h"
 #include "string-list.h"
@@ -420,6 +421,96 @@ static int get_common_prefix_len(const char *common_prefix)
 	return common_prefix_len;
 }
 
+static int read_one_entry_opt(struct index_state *istate,
+			      const struct object_id *oid,
+			      const char *base, int baselen,
+			      const char *pathname,
+			      unsigned mode, int stage, int opt)
+{
+	int len;
+	struct cache_entry *ce;
+
+	if (S_ISDIR(mode))
+		return READ_TREE_RECURSIVE;
+
+	len = strlen(pathname);
+	ce = make_empty_cache_entry(istate, baselen + len);
+
+	ce->ce_mode = create_ce_mode(mode);
+	ce->ce_flags = create_ce_flags(stage);
+	ce->ce_namelen = baselen + len;
+	memcpy(ce->name, base, baselen);
+	memcpy(ce->name + baselen, pathname, len+1);
+	oidcpy(&ce->oid, oid);
+	return add_index_entry(istate, ce, opt);
+}
+
+static int read_one_entry(const struct object_id *oid, struct strbuf *base,
+			  const char *pathname, unsigned mode, int stage,
+			  void *context)
+{
+	struct index_state *istate = context;
+	return read_one_entry_opt(istate, oid, base->buf, base->len, pathname,
+				  mode, stage,
+				  ADD_CACHE_OK_TO_ADD|ADD_CACHE_SKIP_DFCHECK);
+}
+
+/*
+ * This is used when the caller knows there is no existing entries at
+ * the stage that will conflict with the entry being added.
+ */
+static int read_one_entry_quick(const struct object_id *oid, struct strbuf *base,
+				const char *pathname, unsigned mode, int stage,
+				void *context)
+{
+	struct index_state *istate = context;
+	return read_one_entry_opt(istate, oid, base->buf, base->len, pathname,
+				  mode, stage,
+				  ADD_CACHE_JUST_APPEND);
+}
+
+
+static int read_tree(struct repository *r, struct tree *tree, int stage,
+		     struct pathspec *match, struct index_state *istate)
+{
+	read_tree_fn_t fn = NULL;
+	int i, err;
+
+	/*
+	 * Currently the only existing callers of this function all
+	 * call it with stage=1 and after making sure there is nothing
+	 * at that stage; we could always use read_one_entry_quick().
+	 *
+	 * But when we decide to straighten out git-read-tree not to
+	 * use unpack_trees() in some cases, this will probably start
+	 * to matter.
+	 */
+
+	/*
+	 * See if we have cache entry at the stage.  If so,
+	 * do it the original slow way, otherwise, append and then
+	 * sort at the end.
+	 */
+	for (i = 0; !fn && i < istate->cache_nr; i++) {
+		const struct cache_entry *ce = istate->cache[i];
+		if (ce_stage(ce) == stage)
+			fn = read_one_entry;
+	}
+
+	if (!fn)
+		fn = read_one_entry_quick;
+	err = read_tree_recursive(r, tree, "", 0, stage, match, fn, istate);
+	if (fn == read_one_entry || err)
+		return err;
+
+	/*
+	 * Sort the cache entry -- we need to nuke the cache tree, though.
+	 */
+	cache_tree_free(&istate->cache_tree);
+	QSORT(istate->cache, istate->cache_nr, cmp_cache_name_compare);
+	return 0;
+}
+
 /*
  * Read the tree specified with --with-tree option
  * (typically, HEAD) into stage #1 and then
diff --git a/tree.c b/tree.c
index a52479812ce..a6c12f2745a 100644
--- a/tree.c
+++ b/tree.c
@@ -11,54 +11,6 @@
 
 const char *tree_type = "tree";
 
-static int read_one_entry_opt(struct index_state *istate,
-			      const struct object_id *oid,
-			      const char *base, int baselen,
-			      const char *pathname,
-			      unsigned mode, int stage, int opt)
-{
-	int len;
-	struct cache_entry *ce;
-
-	if (S_ISDIR(mode))
-		return READ_TREE_RECURSIVE;
-
-	len = strlen(pathname);
-	ce = make_empty_cache_entry(istate, baselen + len);
-
-	ce->ce_mode = create_ce_mode(mode);
-	ce->ce_flags = create_ce_flags(stage);
-	ce->ce_namelen = baselen + len;
-	memcpy(ce->name, base, baselen);
-	memcpy(ce->name + baselen, pathname, len+1);
-	oidcpy(&ce->oid, oid);
-	return add_index_entry(istate, ce, opt);
-}
-
-static int read_one_entry(const struct object_id *oid, struct strbuf *base,
-			  const char *pathname, unsigned mode, int stage,
-			  void *context)
-{
-	struct index_state *istate = context;
-	return read_one_entry_opt(istate, oid, base->buf, base->len, pathname,
-				  mode, stage,
-				  ADD_CACHE_OK_TO_ADD|ADD_CACHE_SKIP_DFCHECK);
-}
-
-/*
- * This is used when the caller knows there is no existing entries at
- * the stage that will conflict with the entry being added.
- */
-static int read_one_entry_quick(const struct object_id *oid, struct strbuf *base,
-				const char *pathname, unsigned mode, int stage,
-				void *context)
-{
-	struct index_state *istate = context;
-	return read_one_entry_opt(istate, oid, base->buf, base->len, pathname,
-				  mode, stage,
-				  ADD_CACHE_JUST_APPEND);
-}
-
 static int read_tree_1(struct repository *r,
 		       struct tree *tree, struct strbuf *base,
 		       int stage, const struct pathspec *pathspec,
@@ -154,47 +106,6 @@ int cmp_cache_name_compare(const void *a_, const void *b_)
 				  ce2->name, ce2->ce_namelen, ce_stage(ce2));
 }
 
-int read_tree(struct repository *r, struct tree *tree, int stage,
-	      struct pathspec *match, struct index_state *istate)
-{
-	read_tree_fn_t fn = NULL;
-	int i, err;
-
-	/*
-	 * Currently the only existing callers of this function all
-	 * call it with stage=1 and after making sure there is nothing
-	 * at that stage; we could always use read_one_entry_quick().
-	 *
-	 * But when we decide to straighten out git-read-tree not to
-	 * use unpack_trees() in some cases, this will probably start
-	 * to matter.
-	 */
-
-	/*
-	 * See if we have cache entry at the stage.  If so,
-	 * do it the original slow way, otherwise, append and then
-	 * sort at the end.
-	 */
-	for (i = 0; !fn && i < istate->cache_nr; i++) {
-		const struct cache_entry *ce = istate->cache[i];
-		if (ce_stage(ce) == stage)
-			fn = read_one_entry;
-	}
-
-	if (!fn)
-		fn = read_one_entry_quick;
-	err = read_tree_recursive(r, tree, "", 0, stage, match, fn, istate);
-	if (fn == read_one_entry || err)
-		return err;
-
-	/*
-	 * Sort the cache entry -- we need to nuke the cache tree, though.
-	 */
-	cache_tree_free(&istate->cache_tree);
-	QSORT(istate->cache, istate->cache_nr, cmp_cache_name_compare);
-	return 0;
-}
-
 struct tree *lookup_tree(struct repository *r, const struct object_id *oid)
 {
 	struct object *obj = lookup_object(r, oid);
diff --git a/tree.h b/tree.h
index 3eb0484cbf2..6b0b1dc211a 100644
--- a/tree.h
+++ b/tree.h
@@ -38,9 +38,4 @@ int read_tree_recursive(struct repository *r,
 			const char *base, int baselen,
 			int stage, const struct pathspec *pathspec,
 			read_tree_fn_t fn, void *context);
-
-int read_tree(struct repository *r, struct tree *tree,
-	      int stage, struct pathspec *pathspec,
-	      struct index_state *istate);
-
 #endif /* TREE_H */
-- 
2.31.0.rc0.126.g04f22c5b82


^ permalink raw reply	[flat|nested] 262+ messages in thread

* [PATCH v2 3/6] ls-files: don't needlessly pass around stage variable
  2021-03-06 19:34 ` [PATCH 0/7] Move the read_tree() function to its only user Ævar Arnfjörð Bjarmason
                     ` (3 preceding siblings ...)
  2021-03-08  2:21   ` [PATCH v2 2/6] tree.c API: move read_tree() into builtin/ls-files.c Ævar Arnfjörð Bjarmason
@ 2021-03-08  2:21   ` Ævar Arnfjörð Bjarmason
  2021-03-08 18:18     ` Junio C Hamano
  2021-03-08  2:21   ` [PATCH v2 4/6] ls-files: refactor away read_tree() Ævar Arnfjörð Bjarmason
                     ` (2 subsequent siblings)
  7 siblings, 1 reply; 262+ messages in thread
From: Ævar Arnfjörð Bjarmason @ 2021-03-08  2:21 UTC (permalink / raw)
  To: git; +Cc: Junio C Hamano, Elijah Newren, Ævar Arnfjörð Bjarmason

Now that read_tree() has been moved to ls-files.c we can get rid of
the stage != 1 case that'll never happen.

Signed-off-by: Ævar Arnfjörð Bjarmason <avarab@gmail.com>
---
 builtin/ls-files.c | 17 ++++-------------
 1 file changed, 4 insertions(+), 13 deletions(-)

diff --git a/builtin/ls-files.c b/builtin/ls-files.c
index a4458622813..74d572a3e4a 100644
--- a/builtin/ls-files.c
+++ b/builtin/ls-files.c
@@ -470,21 +470,12 @@ static int read_one_entry_quick(const struct object_id *oid, struct strbuf *base
 }
 
 
-static int read_tree(struct repository *r, struct tree *tree, int stage,
+static int read_tree(struct repository *r, struct tree *tree,
 		     struct pathspec *match, struct index_state *istate)
 {
 	read_tree_fn_t fn = NULL;
 	int i, err;
 
-	/*
-	 * Currently the only existing callers of this function all
-	 * call it with stage=1 and after making sure there is nothing
-	 * at that stage; we could always use read_one_entry_quick().
-	 *
-	 * But when we decide to straighten out git-read-tree not to
-	 * use unpack_trees() in some cases, this will probably start
-	 * to matter.
-	 */
 
 	/*
 	 * See if we have cache entry at the stage.  If so,
@@ -493,13 +484,13 @@ static int read_tree(struct repository *r, struct tree *tree, int stage,
 	 */
 	for (i = 0; !fn && i < istate->cache_nr; i++) {
 		const struct cache_entry *ce = istate->cache[i];
-		if (ce_stage(ce) == stage)
+		if (ce_stage(ce) == 1)
 			fn = read_one_entry;
 	}
 
 	if (!fn)
 		fn = read_one_entry_quick;
-	err = read_tree_recursive(r, tree, "", 0, stage, match, fn, istate);
+	err = read_tree_recursive(r, tree, "", 0, 1, match, fn, istate);
 	if (fn == read_one_entry || err)
 		return err;
 
@@ -549,7 +540,7 @@ void overlay_tree_on_index(struct index_state *istate,
 			       PATHSPEC_PREFER_CWD, prefix, matchbuf);
 	} else
 		memset(&pathspec, 0, sizeof(pathspec));
-	if (read_tree(the_repository, tree, 1, &pathspec, istate))
+	if (read_tree(the_repository, tree, &pathspec, istate))
 		die("unable to read tree entries %s", tree_name);
 
 	for (i = 0; i < istate->cache_nr; i++) {
-- 
2.31.0.rc0.126.g04f22c5b82


^ permalink raw reply	[flat|nested] 262+ messages in thread

* [PATCH v2 4/6] ls-files: refactor away read_tree()
  2021-03-06 19:34 ` [PATCH 0/7] Move the read_tree() function to its only user Ævar Arnfjörð Bjarmason
                     ` (4 preceding siblings ...)
  2021-03-08  2:21   ` [PATCH v2 3/6] ls-files: don't needlessly pass around stage variable Ævar Arnfjörð Bjarmason
@ 2021-03-08  2:21   ` Ævar Arnfjörð Bjarmason
  2021-03-08 18:19     ` Junio C Hamano
  2021-03-08  2:21   ` [PATCH v2 5/6] tree.h API: remove support for starting at prefix != "" Ævar Arnfjörð Bjarmason
  2021-03-08  2:21   ` [PATCH v2 6/6] tree.h API: remove "stage" parameter from read_tree_recursive() Ævar Arnfjörð Bjarmason
  7 siblings, 1 reply; 262+ messages in thread
From: Ævar Arnfjörð Bjarmason @ 2021-03-08  2:21 UTC (permalink / raw)
  To: git; +Cc: Junio C Hamano, Elijah Newren, Ævar Arnfjörð Bjarmason

Refactor away the read_tree() function into its only user,
overlay_tree_on_index().

First, change read_one_entry_opt() to use the strbuf parameter
read_tree_recursive() passes down in place. This finishes up a partial
refactoring started in 6a0b0b6de99 (tree.c: update read_tree_recursive
callback to pass strbuf as base, 2014-11-30).

Moving the rest into overlay_tree_on_index() makes this index juggling
we're doing easier to read.

Signed-off-by: Ævar Arnfjörð Bjarmason <avarab@gmail.com>
---
 builtin/ls-files.c | 74 +++++++++++++++++++++-------------------------
 1 file changed, 33 insertions(+), 41 deletions(-)

diff --git a/builtin/ls-files.c b/builtin/ls-files.c
index 74d572a3e4a..db53e2c8e6d 100644
--- a/builtin/ls-files.c
+++ b/builtin/ls-files.c
@@ -423,7 +423,7 @@ static int get_common_prefix_len(const char *common_prefix)
 
 static int read_one_entry_opt(struct index_state *istate,
 			      const struct object_id *oid,
-			      const char *base, int baselen,
+			      struct strbuf *base,
 			      const char *pathname,
 			      unsigned mode, int stage, int opt)
 {
@@ -434,13 +434,13 @@ static int read_one_entry_opt(struct index_state *istate,
 		return READ_TREE_RECURSIVE;
 
 	len = strlen(pathname);
-	ce = make_empty_cache_entry(istate, baselen + len);
+	ce = make_empty_cache_entry(istate, base->len + len);
 
 	ce->ce_mode = create_ce_mode(mode);
 	ce->ce_flags = create_ce_flags(stage);
-	ce->ce_namelen = baselen + len;
-	memcpy(ce->name, base, baselen);
-	memcpy(ce->name + baselen, pathname, len+1);
+	ce->ce_namelen = base->len + len;
+	memcpy(ce->name, base->buf, base->len);
+	memcpy(ce->name + base->len, pathname, len+1);
 	oidcpy(&ce->oid, oid);
 	return add_index_entry(istate, ce, opt);
 }
@@ -450,7 +450,7 @@ static int read_one_entry(const struct object_id *oid, struct strbuf *base,
 			  void *context)
 {
 	struct index_state *istate = context;
-	return read_one_entry_opt(istate, oid, base->buf, base->len, pathname,
+	return read_one_entry_opt(istate, oid, base, pathname,
 				  mode, stage,
 				  ADD_CACHE_OK_TO_ADD|ADD_CACHE_SKIP_DFCHECK);
 }
@@ -464,44 +464,11 @@ static int read_one_entry_quick(const struct object_id *oid, struct strbuf *base
 				void *context)
 {
 	struct index_state *istate = context;
-	return read_one_entry_opt(istate, oid, base->buf, base->len, pathname,
+	return read_one_entry_opt(istate, oid, base, pathname,
 				  mode, stage,
 				  ADD_CACHE_JUST_APPEND);
 }
 
-
-static int read_tree(struct repository *r, struct tree *tree,
-		     struct pathspec *match, struct index_state *istate)
-{
-	read_tree_fn_t fn = NULL;
-	int i, err;
-
-
-	/*
-	 * See if we have cache entry at the stage.  If so,
-	 * do it the original slow way, otherwise, append and then
-	 * sort at the end.
-	 */
-	for (i = 0; !fn && i < istate->cache_nr; i++) {
-		const struct cache_entry *ce = istate->cache[i];
-		if (ce_stage(ce) == 1)
-			fn = read_one_entry;
-	}
-
-	if (!fn)
-		fn = read_one_entry_quick;
-	err = read_tree_recursive(r, tree, "", 0, 1, match, fn, istate);
-	if (fn == read_one_entry || err)
-		return err;
-
-	/*
-	 * Sort the cache entry -- we need to nuke the cache tree, though.
-	 */
-	cache_tree_free(&istate->cache_tree);
-	QSORT(istate->cache, istate->cache_nr, cmp_cache_name_compare);
-	return 0;
-}
-
 /*
  * Read the tree specified with --with-tree option
  * (typically, HEAD) into stage #1 and then
@@ -518,6 +485,8 @@ void overlay_tree_on_index(struct index_state *istate,
 	struct pathspec pathspec;
 	struct cache_entry *last_stage0 = NULL;
 	int i;
+	read_tree_fn_t fn = NULL;
+	int err;
 
 	if (get_oid(tree_name, &oid))
 		die("tree-ish %s not found.", tree_name);
@@ -540,9 +509,32 @@ void overlay_tree_on_index(struct index_state *istate,
 			       PATHSPEC_PREFER_CWD, prefix, matchbuf);
 	} else
 		memset(&pathspec, 0, sizeof(pathspec));
-	if (read_tree(the_repository, tree, &pathspec, istate))
+
+	/*
+	 * See if we have cache entry at the stage.  If so,
+	 * do it the original slow way, otherwise, append and then
+	 * sort at the end.
+	 */
+	for (i = 0; !fn && i < istate->cache_nr; i++) {
+		const struct cache_entry *ce = istate->cache[i];
+		if (ce_stage(ce) == 1)
+			fn = read_one_entry;
+	}
+
+	if (!fn)
+		fn = read_one_entry_quick;
+	err = read_tree_recursive(the_repository, tree, "", 0, 1, &pathspec, fn, istate);
+	if (err)
 		die("unable to read tree entries %s", tree_name);
 
+	/*
+	 * Sort the cache entry -- we need to nuke the cache tree, though.
+	 */
+	if (fn == read_one_entry_quick) {
+		cache_tree_free(&istate->cache_tree);
+		QSORT(istate->cache, istate->cache_nr, cmp_cache_name_compare);
+	}
+
 	for (i = 0; i < istate->cache_nr; i++) {
 		struct cache_entry *ce = istate->cache[i];
 		switch (ce_stage(ce)) {
-- 
2.31.0.rc0.126.g04f22c5b82


^ permalink raw reply	[flat|nested] 262+ messages in thread

* [PATCH v2 5/6] tree.h API: remove support for starting at prefix != ""
  2021-03-06 19:34 ` [PATCH 0/7] Move the read_tree() function to its only user Ævar Arnfjörð Bjarmason
                     ` (5 preceding siblings ...)
  2021-03-08  2:21   ` [PATCH v2 4/6] ls-files: refactor away read_tree() Ævar Arnfjörð Bjarmason
@ 2021-03-08  2:21   ` Ævar Arnfjörð Bjarmason
  2021-03-08  2:21   ` [PATCH v2 6/6] tree.h API: remove "stage" parameter from read_tree_recursive() Ævar Arnfjörð Bjarmason
  7 siblings, 0 replies; 262+ messages in thread
From: Ævar Arnfjörð Bjarmason @ 2021-03-08  2:21 UTC (permalink / raw)
  To: git; +Cc: Junio C Hamano, Elijah Newren, Ævar Arnfjörð Bjarmason

Every caller of the read_tree_recursive() function hardcoded a
starting point of "" in the tree. So let's simply remove that
parameter.

The last function to call read_tree_recursive() with a non-"" path was
read_tree_recursive() itself, but that was changed in
ffd31f661d5 (Reimplement read_tree_recursive() using
tree_entry_interesting(), 2011-03-25).

If in the future we need to support recursively reading trees without
starting at the root we can easily add a read_tree_recursive_subdir(),
and make that function a thin wrapper for read_tree_1().

In the meantime there's no reason to keep around what amounts to dead
code, just in case we need it in the future.

Signed-off-by: Ævar Arnfjörð Bjarmason <avarab@gmail.com>
---
 archive.c          | 8 ++++----
 builtin/checkout.c | 2 +-
 builtin/log.c      | 4 ++--
 builtin/ls-files.c | 2 +-
 builtin/ls-tree.c  | 2 +-
 merge-recursive.c  | 2 +-
 tree.c             | 2 --
 tree.h             | 1 -
 8 files changed, 10 insertions(+), 13 deletions(-)

diff --git a/archive.c b/archive.c
index 5919d9e5050..9394f170f7f 100644
--- a/archive.c
+++ b/archive.c
@@ -316,8 +316,8 @@ int write_archive_entries(struct archiver_args *args,
 		git_attr_set_direction(GIT_ATTR_INDEX);
 	}
 
-	err = read_tree_recursive(args->repo, args->tree, "",
-				  0, 0, &args->pathspec,
+	err = read_tree_recursive(args->repo, args->tree,
+				  0, &args->pathspec,
 				  queue_or_write_archive_entry,
 				  &context);
 	if (err == READ_TREE_RECURSIVE)
@@ -405,8 +405,8 @@ static int path_exists(struct archiver_args *args, const char *path)
 	ctx.args = args;
 	parse_pathspec(&ctx.pathspec, 0, 0, "", paths);
 	ctx.pathspec.recursive = 1;
-	ret = read_tree_recursive(args->repo, args->tree, "",
-				  0, 0, &ctx.pathspec,
+	ret = read_tree_recursive(args->repo, args->tree,
+				  0, &ctx.pathspec,
 				  reject_entry, &ctx);
 	clear_pathspec(&ctx.pathspec);
 	return ret != 0;
diff --git a/builtin/checkout.c b/builtin/checkout.c
index 2d6550bc3c8..21b742c0f07 100644
--- a/builtin/checkout.c
+++ b/builtin/checkout.c
@@ -155,7 +155,7 @@ static int update_some(const struct object_id *oid, struct strbuf *base,
 
 static int read_tree_some(struct tree *tree, const struct pathspec *pathspec)
 {
-	read_tree_recursive(the_repository, tree, "", 0, 0,
+	read_tree_recursive(the_repository, tree, 0,
 			    pathspec, update_some, NULL);
 
 	/* update the index with the given tree's info
diff --git a/builtin/log.c b/builtin/log.c
index f67b67d80ed..ffa3fb8c286 100644
--- a/builtin/log.c
+++ b/builtin/log.c
@@ -681,8 +681,8 @@ int cmd_show(int argc, const char **argv, const char *prefix)
 					diff_get_color_opt(&rev.diffopt, DIFF_COMMIT),
 					name,
 					diff_get_color_opt(&rev.diffopt, DIFF_RESET));
-			read_tree_recursive(the_repository, (struct tree *)o, "",
-					    0, 0, &match_all, show_tree_object,
+			read_tree_recursive(the_repository, (struct tree *)o,
+					    0, &match_all, show_tree_object,
 					    rev.diffopt.file);
 			rev.shown_one = 1;
 			break;
diff --git a/builtin/ls-files.c b/builtin/ls-files.c
index db53e2c8e6d..cd432ac03cd 100644
--- a/builtin/ls-files.c
+++ b/builtin/ls-files.c
@@ -523,7 +523,7 @@ void overlay_tree_on_index(struct index_state *istate,
 
 	if (!fn)
 		fn = read_one_entry_quick;
-	err = read_tree_recursive(the_repository, tree, "", 0, 1, &pathspec, fn, istate);
+	err = read_tree_recursive(the_repository, tree, 1, &pathspec, fn, istate);
 	if (err)
 		die("unable to read tree entries %s", tree_name);
 
diff --git a/builtin/ls-tree.c b/builtin/ls-tree.c
index 7cad3f24ebd..7d3fb2e6d0f 100644
--- a/builtin/ls-tree.c
+++ b/builtin/ls-tree.c
@@ -185,6 +185,6 @@ int cmd_ls_tree(int argc, const char **argv, const char *prefix)
 	tree = parse_tree_indirect(&oid);
 	if (!tree)
 		die("not a tree object");
-	return !!read_tree_recursive(the_repository, tree, "", 0, 0,
+	return !!read_tree_recursive(the_repository, tree, 0,
 				     &pathspec, show_tree, NULL);
 }
diff --git a/merge-recursive.c b/merge-recursive.c
index b052974f191..fa7602ff0f2 100644
--- a/merge-recursive.c
+++ b/merge-recursive.c
@@ -473,7 +473,7 @@ static void get_files_dirs(struct merge_options *opt, struct tree *tree)
 {
 	struct pathspec match_all;
 	memset(&match_all, 0, sizeof(match_all));
-	read_tree_recursive(opt->repo, tree, "", 0, 0,
+	read_tree_recursive(opt->repo, tree, 0,
 			    &match_all, save_files_dirs, opt);
 }
 
diff --git a/tree.c b/tree.c
index a6c12f2745a..04eb11aed31 100644
--- a/tree.c
+++ b/tree.c
@@ -83,14 +83,12 @@ static int read_tree_1(struct repository *r,
 
 int read_tree_recursive(struct repository *r,
 			struct tree *tree,
-			const char *base, int baselen,
 			int stage, const struct pathspec *pathspec,
 			read_tree_fn_t fn, void *context)
 {
 	struct strbuf sb = STRBUF_INIT;
 	int ret;
 
-	strbuf_add(&sb, base, baselen);
 	ret = read_tree_1(r, tree, &sb, stage, pathspec, fn, context);
 	strbuf_release(&sb);
 	return ret;
diff --git a/tree.h b/tree.h
index 6b0b1dc211a..5252b5139dd 100644
--- a/tree.h
+++ b/tree.h
@@ -35,7 +35,6 @@ typedef int (*read_tree_fn_t)(const struct object_id *, struct strbuf *, const c
 
 int read_tree_recursive(struct repository *r,
 			struct tree *tree,
-			const char *base, int baselen,
 			int stage, const struct pathspec *pathspec,
 			read_tree_fn_t fn, void *context);
 #endif /* TREE_H */
-- 
2.31.0.rc0.126.g04f22c5b82


^ permalink raw reply	[flat|nested] 262+ messages in thread

* [PATCH v2 6/6] tree.h API: remove "stage" parameter from read_tree_recursive()
  2021-03-06 19:34 ` [PATCH 0/7] Move the read_tree() function to its only user Ævar Arnfjörð Bjarmason
                     ` (6 preceding siblings ...)
  2021-03-08  2:21   ` [PATCH v2 5/6] tree.h API: remove support for starting at prefix != "" Ævar Arnfjörð Bjarmason
@ 2021-03-08  2:21   ` Ævar Arnfjörð Bjarmason
  7 siblings, 0 replies; 262+ messages in thread
From: Ævar Arnfjörð Bjarmason @ 2021-03-08  2:21 UTC (permalink / raw)
  To: git; +Cc: Junio C Hamano, Elijah Newren, Ævar Arnfjörð Bjarmason

The read_tree_recursive() function took a "stage" parameter that is
passed through as-is. As it turns out nothing used this parameter in a
way that they couldn't just move to the callback function they
defined, so let's get rid of it.

If anyone needs to pass such information in the future they can use
the "void *context" parameter.

Signed-off-by: Ævar Arnfjörð Bjarmason <avarab@gmail.com>
---
 archive.c          |  9 +++++----
 builtin/checkout.c |  4 ++--
 builtin/log.c      |  4 ++--
 builtin/ls-files.c | 14 +++++++-------
 builtin/ls-tree.c  |  4 ++--
 merge-recursive.c  |  4 ++--
 tree.c             | 10 +++++-----
 tree.h             |  4 ++--
 8 files changed, 27 insertions(+), 26 deletions(-)

diff --git a/archive.c b/archive.c
index 9394f170f7f..6669a4bd147 100644
--- a/archive.c
+++ b/archive.c
@@ -231,9 +231,10 @@ static int write_directory(struct archiver_context *c)
 
 static int queue_or_write_archive_entry(const struct object_id *oid,
 		struct strbuf *base, const char *filename,
-		unsigned mode, int stage, void *context)
+		unsigned mode, void *context)
 {
 	struct archiver_context *c = context;
+	int stage = 0;
 
 	while (c->bottom &&
 	       !(base->len >= c->bottom->len &&
@@ -317,7 +318,7 @@ int write_archive_entries(struct archiver_args *args,
 	}
 
 	err = read_tree_recursive(args->repo, args->tree,
-				  0, &args->pathspec,
+				  &args->pathspec,
 				  queue_or_write_archive_entry,
 				  &context);
 	if (err == READ_TREE_RECURSIVE)
@@ -378,7 +379,7 @@ struct path_exists_context {
 
 static int reject_entry(const struct object_id *oid, struct strbuf *base,
 			const char *filename, unsigned mode,
-			int stage, void *context)
+			void *context)
 {
 	int ret = -1;
 	struct path_exists_context *ctx = context;
@@ -406,7 +407,7 @@ static int path_exists(struct archiver_args *args, const char *path)
 	parse_pathspec(&ctx.pathspec, 0, 0, "", paths);
 	ctx.pathspec.recursive = 1;
 	ret = read_tree_recursive(args->repo, args->tree,
-				  0, &ctx.pathspec,
+				  &ctx.pathspec,
 				  reject_entry, &ctx);
 	clear_pathspec(&ctx.pathspec);
 	return ret != 0;
diff --git a/builtin/checkout.c b/builtin/checkout.c
index 21b742c0f07..2c2d58a230f 100644
--- a/builtin/checkout.c
+++ b/builtin/checkout.c
@@ -114,7 +114,7 @@ static int post_checkout_hook(struct commit *old_commit, struct commit *new_comm
 }
 
 static int update_some(const struct object_id *oid, struct strbuf *base,
-		const char *pathname, unsigned mode, int stage, void *context)
+		const char *pathname, unsigned mode, void *context)
 {
 	int len;
 	struct cache_entry *ce;
@@ -155,7 +155,7 @@ static int update_some(const struct object_id *oid, struct strbuf *base,
 
 static int read_tree_some(struct tree *tree, const struct pathspec *pathspec)
 {
-	read_tree_recursive(the_repository, tree, 0,
+	read_tree_recursive(the_repository, tree,
 			    pathspec, update_some, NULL);
 
 	/* update the index with the given tree's info
diff --git a/builtin/log.c b/builtin/log.c
index ffa3fb8c286..58acb2b76ab 100644
--- a/builtin/log.c
+++ b/builtin/log.c
@@ -599,7 +599,7 @@ static int show_tag_object(const struct object_id *oid, struct rev_info *rev)
 
 static int show_tree_object(const struct object_id *oid,
 		struct strbuf *base,
-		const char *pathname, unsigned mode, int stage, void *context)
+		const char *pathname, unsigned mode, void *context)
 {
 	FILE *file = context;
 	fprintf(file, "%s%s\n", pathname, S_ISDIR(mode) ? "/" : "");
@@ -682,7 +682,7 @@ int cmd_show(int argc, const char **argv, const char *prefix)
 					name,
 					diff_get_color_opt(&rev.diffopt, DIFF_RESET));
 			read_tree_recursive(the_repository, (struct tree *)o,
-					    0, &match_all, show_tree_object,
+					    &match_all, show_tree_object,
 					    rev.diffopt.file);
 			rev.shown_one = 1;
 			break;
diff --git a/builtin/ls-files.c b/builtin/ls-files.c
index cd432ac03cd..fa9b01b6cc7 100644
--- a/builtin/ls-files.c
+++ b/builtin/ls-files.c
@@ -425,7 +425,7 @@ static int read_one_entry_opt(struct index_state *istate,
 			      const struct object_id *oid,
 			      struct strbuf *base,
 			      const char *pathname,
-			      unsigned mode, int stage, int opt)
+			      unsigned mode, int opt)
 {
 	int len;
 	struct cache_entry *ce;
@@ -437,7 +437,7 @@ static int read_one_entry_opt(struct index_state *istate,
 	ce = make_empty_cache_entry(istate, base->len + len);
 
 	ce->ce_mode = create_ce_mode(mode);
-	ce->ce_flags = create_ce_flags(stage);
+	ce->ce_flags = create_ce_flags(1);
 	ce->ce_namelen = base->len + len;
 	memcpy(ce->name, base->buf, base->len);
 	memcpy(ce->name + base->len, pathname, len+1);
@@ -446,12 +446,12 @@ static int read_one_entry_opt(struct index_state *istate,
 }
 
 static int read_one_entry(const struct object_id *oid, struct strbuf *base,
-			  const char *pathname, unsigned mode, int stage,
+			  const char *pathname, unsigned mode,
 			  void *context)
 {
 	struct index_state *istate = context;
 	return read_one_entry_opt(istate, oid, base, pathname,
-				  mode, stage,
+				  mode,
 				  ADD_CACHE_OK_TO_ADD|ADD_CACHE_SKIP_DFCHECK);
 }
 
@@ -460,12 +460,12 @@ static int read_one_entry(const struct object_id *oid, struct strbuf *base,
  * the stage that will conflict with the entry being added.
  */
 static int read_one_entry_quick(const struct object_id *oid, struct strbuf *base,
-				const char *pathname, unsigned mode, int stage,
+				const char *pathname, unsigned mode,
 				void *context)
 {
 	struct index_state *istate = context;
 	return read_one_entry_opt(istate, oid, base, pathname,
-				  mode, stage,
+				  mode,
 				  ADD_CACHE_JUST_APPEND);
 }
 
@@ -523,7 +523,7 @@ void overlay_tree_on_index(struct index_state *istate,
 
 	if (!fn)
 		fn = read_one_entry_quick;
-	err = read_tree_recursive(the_repository, tree, 1, &pathspec, fn, istate);
+	err = read_tree_recursive(the_repository, tree, &pathspec, fn, istate);
 	if (err)
 		die("unable to read tree entries %s", tree_name);
 
diff --git a/builtin/ls-tree.c b/builtin/ls-tree.c
index 7d3fb2e6d0f..dbb31217beb 100644
--- a/builtin/ls-tree.c
+++ b/builtin/ls-tree.c
@@ -62,7 +62,7 @@ static int show_recursive(const char *base, int baselen, const char *pathname)
 }
 
 static int show_tree(const struct object_id *oid, struct strbuf *base,
-		const char *pathname, unsigned mode, int stage, void *context)
+		const char *pathname, unsigned mode, void *context)
 {
 	int retval = 0;
 	int baselen;
@@ -185,6 +185,6 @@ int cmd_ls_tree(int argc, const char **argv, const char *prefix)
 	tree = parse_tree_indirect(&oid);
 	if (!tree)
 		die("not a tree object");
-	return !!read_tree_recursive(the_repository, tree, 0,
+	return !!read_tree_recursive(the_repository, tree,
 				     &pathspec, show_tree, NULL);
 }
diff --git a/merge-recursive.c b/merge-recursive.c
index fa7602ff0f2..1593f374495 100644
--- a/merge-recursive.c
+++ b/merge-recursive.c
@@ -453,7 +453,7 @@ static void unpack_trees_finish(struct merge_options *opt)
 
 static int save_files_dirs(const struct object_id *oid,
 			   struct strbuf *base, const char *path,
-			   unsigned int mode, int stage, void *context)
+			   unsigned int mode, void *context)
 {
 	struct path_hashmap_entry *entry;
 	int baselen = base->len;
@@ -473,7 +473,7 @@ static void get_files_dirs(struct merge_options *opt, struct tree *tree)
 {
 	struct pathspec match_all;
 	memset(&match_all, 0, sizeof(match_all));
-	read_tree_recursive(opt->repo, tree, 0,
+	read_tree_recursive(opt->repo, tree,
 			    &match_all, save_files_dirs, opt);
 }
 
diff --git a/tree.c b/tree.c
index 04eb11aed31..fb4985f22ca 100644
--- a/tree.c
+++ b/tree.c
@@ -13,7 +13,7 @@ const char *tree_type = "tree";
 
 static int read_tree_1(struct repository *r,
 		       struct tree *tree, struct strbuf *base,
-		       int stage, const struct pathspec *pathspec,
+		       const struct pathspec *pathspec,
 		       read_tree_fn_t fn, void *context)
 {
 	struct tree_desc desc;
@@ -38,7 +38,7 @@ static int read_tree_1(struct repository *r,
 		}
 
 		switch (fn(&entry.oid, base,
-			   entry.path, entry.mode, stage, context)) {
+			   entry.path, entry.mode, context)) {
 		case 0:
 			continue;
 		case READ_TREE_RECURSIVE:
@@ -72,7 +72,7 @@ static int read_tree_1(struct repository *r,
 		strbuf_add(base, entry.path, len);
 		strbuf_addch(base, '/');
 		retval = read_tree_1(r, lookup_tree(r, &oid),
-				     base, stage, pathspec,
+				     base, pathspec,
 				     fn, context);
 		strbuf_setlen(base, oldlen);
 		if (retval)
@@ -83,13 +83,13 @@ static int read_tree_1(struct repository *r,
 
 int read_tree_recursive(struct repository *r,
 			struct tree *tree,
-			int stage, const struct pathspec *pathspec,
+			const struct pathspec *pathspec,
 			read_tree_fn_t fn, void *context)
 {
 	struct strbuf sb = STRBUF_INIT;
 	int ret;
 
-	ret = read_tree_1(r, tree, &sb, stage, pathspec, fn, context);
+	ret = read_tree_1(r, tree, &sb, pathspec, fn, context);
 	strbuf_release(&sb);
 	return ret;
 }
diff --git a/tree.h b/tree.h
index 5252b5139dd..1309ab997e5 100644
--- a/tree.h
+++ b/tree.h
@@ -31,10 +31,10 @@ struct tree *parse_tree_indirect(const struct object_id *oid);
 int cmp_cache_name_compare(const void *a_, const void *b_);
 
 #define READ_TREE_RECURSIVE 1
-typedef int (*read_tree_fn_t)(const struct object_id *, struct strbuf *, const char *, unsigned int, int, void *);
+typedef int (*read_tree_fn_t)(const struct object_id *, struct strbuf *, const char *, unsigned int, void *);
 
 int read_tree_recursive(struct repository *r,
 			struct tree *tree,
-			int stage, const struct pathspec *pathspec,
+			const struct pathspec *pathspec,
 			read_tree_fn_t fn, void *context);
 #endif /* TREE_H */
-- 
2.31.0.rc0.126.g04f22c5b82


^ permalink raw reply	[flat|nested] 262+ messages in thread

* [PATCH 00/30] tree-walk: mostly "mode" to "enum object_type"
  2021-03-08  2:21   ` [PATCH v2 0/6] " Ævar Arnfjörð Bjarmason
@ 2021-03-08 15:06     ` Ævar Arnfjörð Bjarmason
  2021-03-09  0:10       ` Elijah Newren
                         ` (31 more replies)
  2021-03-08 15:06     ` [PATCH 01/30] diff.c: remove redundant canon_mode() call Ævar Arnfjörð Bjarmason
                       ` (40 subsequent siblings)
  41 siblings, 32 replies; 262+ messages in thread
From: Ævar Arnfjörð Bjarmason @ 2021-03-08 15:06 UTC (permalink / raw)
  To: git
  Cc: Junio C Hamano, Elijah Newren, Kirill Smelkov,
	Nguyễn Thái Ngọc Duy,
	Ævar Arnfjörð Bjarmason

This large series goes on top of my 6 patch series for
read_tree_recursive() as this one further refactors that function. See
https://lore.kernel.org/git/20210308022138.28166-1-avarab@gmail.com/
for that series.

I noticed that since 2014 or so we haven't been doing the fsck checks
for bad file modes in trees. This series fixes that. I plan to add
tests etc. for that in another follow-up series.

I wanted to get this out for review sooner than later, particularly
since the fsck testing will probably get me down another refactoring
path (fsck testing in general in this area is pretty bad...).

As noted in 30/30 it would have been way easier to simply do an
isolated fix for that bug by introducing some fsck-specific API for
raw tree reading.

But I thought the bug was symptomatic of a wider problem in our
codebase. Namely that we pass around the tree's mode *a lot*.

But almost everything that then deals with the mode doesn't per-se
care about the mode bits in the tree, but using them to map that mode
to a tree entry for one of of OBJ_{BLOB,TREE,COMMIT}.

So this is a large refactoring of all users of the widely used
tree-walk.h API to "enum obj2ect_type", finally in 29/30 I rename the
field to a scary "raw_mode".

At that point we have just ~30-50 grep hits left for "raw_mode" in the
codebase (depending on whether we count names in function parameters).

Hopefully being in that state alleviates e.g. Elijah's concerns
expressed in
https://lore.kernel.org/git/CABPp-BEdu1PqV5W=FuL0f08iFhGzvzV8oSUybNj4eF0aAwTnAw@mail.gmail.com/
I agree that doing the equivalent of 30/30 on top of master would be
way too scary, but once we're at 29/30 I think it's sane.

I tested this in combination with his on-list series to add more
merge-ort testing:
https://lore.kernel.org/git/pull.973.git.git.1614905738.gitgitgadget@gmail.com/

I found a regression I'd caused in the merge-ort.c code with those
tests, fixed here. See the comment in merge-ort.c in 30/30.

Ævar Arnfjörð Bjarmason (30):
  diff.c: remove redundant canon_mode() call
  notes & match-trees: use name_entry's "pathlen" member
  cache.h: add a comment to object_type()
  tree-walk.h: add object_type member to name_entry
  tree-walk.c: migrate to using new "object_type" field when possible
  cache.h: have base_name_compare() take "is tree?", not "mode"
  tree-walk.h users: switch object_type(...) to new .object_type
  tree.h: format argument lists of read_tree_recursive() users
  tree.h users: format argument lists in archive.c
  archive: get rid of 'stage' parameter
  tree.h API: make read_tree_fn_t take an "enum object_type"
  tree-walk.h users: migrate "p->mode &&" pattern
  tree-walk.h users: refactor chained "mode" if/else into switch
  tree-walk.h users: migrate miscellaneous "mode" to "object_type"
  merge-tree tests: test for the mode comparison in same_entry()
  merge-ort: correct reference to test in 62fdec17a11
  fsck.c: switch on "object_type" in fsck_walk_tree()
  tree-walk.h users: use temporary variable(s) for "mode"
  tree-walk.h API: formatting changes for subsequent commit
  tree-walk.h API: rename get_tree_entry() to get_tree_entry_mode()
  tree-walk.h API users: use "tmp" for mode in shift_tree_by()
  tree-walk.h API: Add get_tree_entry_type()
  tree-walk.h API: add a get_tree_entry_path() function
  tree-walk.h API: document and format tree_entry_extract()
  tree-entry.h API: rename tree_entry_extract() to
    tree_entry_extract_mode()
  tree-walk.h API: add a tree_entry_extract_all() function
  tree-walk.h API: add a tree_entry_extract_type() function
  tree-walk.h API users: rename "struct name_entry"'s "mode" to
    "raw_mode"
  tree.h API users: rename read_tree_fn_t's "mode" to "raw_mode"
  tree-walk.h API: move canon_mode() back out of decode_tree_entry()

 archive.c              | 51 +++++++++++++-----------
 blame.c                |  9 +++--
 builtin/checkout.c     |  7 +++-
 builtin/fast-import.c  |  8 ++--
 builtin/grep.c         |  6 +--
 builtin/log.c          |  7 ++--
 builtin/ls-files.c     | 13 +++---
 builtin/ls-tree.c      | 18 ++++-----
 builtin/merge-tree.c   | 32 +++++++++------
 builtin/mktree.c       |  4 +-
 builtin/pack-objects.c |  6 +--
 builtin/reflog.c       |  3 +-
 builtin/rm.c           |  2 +-
 builtin/update-index.c |  7 +++-
 cache-tree.c           |  2 +-
 cache.h                | 11 ++++--
 combine-diff.c         |  8 ++--
 delta-islands.c        |  2 +-
 diff.c                 |  2 +-
 fsck.c                 | 23 +++++------
 http-push.c            |  6 ++-
 line-log.c             |  2 +-
 list-objects.c         | 20 +++++++---
 match-trees.c          | 52 ++++++++++++------------
 merge-ort.c            | 34 ++++++++++------
 merge-recursive.c      | 33 ++++++++--------
 notes.c                | 15 +++----
 object-name.c          |  7 ++--
 pack-bitmap-write.c    |  8 ++--
 read-cache.c           | 16 ++++----
 revision.c             | 12 ++++--
 t/t4300-merge-tree.sh  | 44 +++++++++++++++++++++
 tree-diff.c            | 44 ++++++++++++---------
 tree-walk.c            | 89 +++++++++++++++++++++++++++++++-----------
 tree-walk.h            | 67 ++++++++++++++++++++++++++-----
 tree.c                 | 19 +++++----
 tree.h                 |  5 ++-
 unpack-trees.c         | 30 ++++++++------
 walker.c               | 22 ++++++-----
 39 files changed, 482 insertions(+), 264 deletions(-)

-- 
2.31.0.rc0.126.g04f22c5b82


^ permalink raw reply	[flat|nested] 262+ messages in thread

* [PATCH 01/30] diff.c: remove redundant canon_mode() call
  2021-03-08  2:21   ` [PATCH v2 0/6] " Ævar Arnfjörð Bjarmason
  2021-03-08 15:06     ` [PATCH 00/30] tree-walk: mostly "mode" to "enum object_type" Ævar Arnfjörð Bjarmason
@ 2021-03-08 15:06     ` Ævar Arnfjörð Bjarmason
  2021-03-08 15:06     ` [PATCH 02/30] notes & match-trees: use name_entry's "pathlen" member Ævar Arnfjörð Bjarmason
                       ` (39 subsequent siblings)
  41 siblings, 0 replies; 262+ messages in thread
From: Ævar Arnfjörð Bjarmason @ 2021-03-08 15:06 UTC (permalink / raw)
  To: git
  Cc: Junio C Hamano, Elijah Newren, Kirill Smelkov,
	Nguyễn Thái Ngọc Duy,
	Ævar Arnfjörð Bjarmason

Remove a call to canon_mode() from fill_filespec(). This has been
redundant since the tree-walk.c API supplies it pre-canonicalized
since 7146e66f086 (tree-walk: finally switch over tree descriptors to
contain a pre-parsed entry, 2014-02-06).

This call to the predecessor of canon_mode() was added back in
4130b995719 ([PATCH] Diff updates to express type changes,
2005-05-26).

This was the only such call in the codebase. The rest are all either
one of these sorts of forms:

    canon_mode(st.st_mode); /* a stat(2) struct */
    canon_mode(S_IFREG | 0644) /* A compile-time literal */

Signed-off-by: Ævar Arnfjörð Bjarmason <avarab@gmail.com>
---
 diff.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/diff.c b/diff.c
index 6956f5e335c..bf46e6a4d8c 100644
--- a/diff.c
+++ b/diff.c
@@ -3846,7 +3846,7 @@ void fill_filespec(struct diff_filespec *spec, const struct object_id *oid,
 		   int oid_valid, unsigned short mode)
 {
 	if (mode) {
-		spec->mode = canon_mode(mode);
+		spec->mode = mode;
 		oidcpy(&spec->oid, oid);
 		spec->oid_valid = oid_valid;
 	}
-- 
2.31.0.rc0.126.g04f22c5b82


^ permalink raw reply	[flat|nested] 262+ messages in thread

* [PATCH 02/30] notes & match-trees: use name_entry's "pathlen" member
  2021-03-08  2:21   ` [PATCH v2 0/6] " Ævar Arnfjörð Bjarmason
  2021-03-08 15:06     ` [PATCH 00/30] tree-walk: mostly "mode" to "enum object_type" Ævar Arnfjörð Bjarmason
  2021-03-08 15:06     ` [PATCH 01/30] diff.c: remove redundant canon_mode() call Ævar Arnfjörð Bjarmason
@ 2021-03-08 15:06     ` Ævar Arnfjörð Bjarmason
  2021-03-08 15:06     ` [PATCH 03/30] cache.h: add a comment to object_type() Ævar Arnfjörð Bjarmason
                       ` (38 subsequent siblings)
  41 siblings, 0 replies; 262+ messages in thread
From: Ævar Arnfjörð Bjarmason @ 2021-03-08 15:06 UTC (permalink / raw)
  To: git
  Cc: Junio C Hamano, Elijah Newren, Kirill Smelkov,
	Nguyễn Thái Ngọc Duy,
	Ævar Arnfjörð Bjarmason

Change code that was doing a strlen() on the "path" from a name_entry
struct to instead use the pathlen given to us by decode_tree_entry().

Signed-off-by: Ævar Arnfjörð Bjarmason <avarab@gmail.com>
---
 match-trees.c | 7 +++----
 notes.c       | 4 ++--
 2 files changed, 5 insertions(+), 6 deletions(-)

diff --git a/match-trees.c b/match-trees.c
index f6c194c1cca..1011357ad0c 100644
--- a/match-trees.c
+++ b/match-trees.c
@@ -197,9 +197,10 @@ static int splice_tree(const struct object_id *oid1, const char *prefix,
 	while (desc.size) {
 		const char *name;
 		unsigned short mode;
+		int len = tree_entry_len(&desc.entry);
 
 		tree_entry_extract(&desc, &name, &mode);
-		if (strlen(name) == toplen &&
+		if (len == toplen &&
 		    !memcmp(name, prefix, toplen)) {
 			if (!S_ISDIR(mode))
 				die("entry %s in tree %s is not a tree", name,
@@ -214,9 +215,7 @@ static int splice_tree(const struct object_id *oid1, const char *prefix,
 			 *   - to discard the "const"; this is OK because we
 			 *     know it points into our non-const "buf"
 			 */
-			rewrite_here = (unsigned char *)(desc.entry.path +
-							 strlen(desc.entry.path) +
-							 1);
+			rewrite_here = (unsigned char *)(name + len + 1);
 			break;
 		}
 		update_tree_entry(&desc);
diff --git a/notes.c b/notes.c
index d5ac081e76d..0a5b4fa1dbb 100644
--- a/notes.c
+++ b/notes.c
@@ -413,7 +413,7 @@ static void load_subtree(struct notes_tree *t, struct leaf_node *subtree,
 	while (tree_entry(&desc, &entry)) {
 		unsigned char type;
 		struct leaf_node *l;
-		size_t path_len = strlen(entry.path);
+		int path_len = entry.pathlen;
 
 		if (path_len == 2 * (hashsz - prefix_len)) {
 			/* This is potentially the remainder of the SHA-1 */
@@ -483,7 +483,7 @@ static void load_subtree(struct notes_tree *t, struct leaf_node *subtree,
 				strbuf_addch(&non_note_path, *q++);
 				strbuf_addch(&non_note_path, '/');
 			}
-			strbuf_addstr(&non_note_path, entry.path);
+			strbuf_add(&non_note_path, entry.path, path_len);
 			add_non_note(t, strbuf_detach(&non_note_path, NULL),
 				     entry.mode, entry.oid.hash);
 		}
-- 
2.31.0.rc0.126.g04f22c5b82


^ permalink raw reply	[flat|nested] 262+ messages in thread

* [PATCH 03/30] cache.h: add a comment to object_type()
  2021-03-08  2:21   ` [PATCH v2 0/6] " Ævar Arnfjörð Bjarmason
                       ` (2 preceding siblings ...)
  2021-03-08 15:06     ` [PATCH 02/30] notes & match-trees: use name_entry's "pathlen" member Ævar Arnfjörð Bjarmason
@ 2021-03-08 15:06     ` Ævar Arnfjörð Bjarmason
  2021-03-09 16:40       ` Elijah Newren
  2021-03-08 15:06     ` [PATCH 04/30] tree-walk.h: add object_type member to name_entry Ævar Arnfjörð Bjarmason
                       ` (37 subsequent siblings)
  41 siblings, 1 reply; 262+ messages in thread
From: Ævar Arnfjörð Bjarmason @ 2021-03-08 15:06 UTC (permalink / raw)
  To: git
  Cc: Junio C Hamano, Elijah Newren, Kirill Smelkov,
	Nguyễn Thái Ngọc Duy,
	Ævar Arnfjörð Bjarmason

Add a comment to the object_type() function to explain what it
returns, and whet the "mode" is in the "else" case.

The object_type() function dates back to 4d1012c3709 (Fix rev-list
when showing objects involving submodules, 2007-11-11). It's not
immediately obvious to someone looking at its history and how it's
come to be used.

Despite what Linus noted in 4d1012c3709 (Fix rev-list when showing
objects involving submodules, 2007-11-11) about wanting to move away
from users of object_type() relying on S_ISLNK(mode) being true here
we do currently rely on that. If this is changed to a condition to
only return OBJ_BLOB on S_ISREG(mode) then t4008, t4023 and t7415 will
have failing tests.

Signed-off-by: Ævar Arnfjörð Bjarmason <avarab@gmail.com>
---
 cache.h | 7 ++++++-
 1 file changed, 6 insertions(+), 1 deletion(-)

diff --git a/cache.h b/cache.h
index d9281496140..e513f0ee5b4 100644
--- a/cache.h
+++ b/cache.h
@@ -451,11 +451,16 @@ enum object_type {
 	OBJ_MAX
 };
 
+/*
+ * object_type() returns an object of a type that'll appear in a tree,
+ * so no OBJ_TAG is possible. This is mostly (and dates back to)
+ * consumers of the tree-walk.h API's "mode" field.
+ */
 static inline enum object_type object_type(unsigned int mode)
 {
 	return S_ISDIR(mode) ? OBJ_TREE :
 		S_ISGITLINK(mode) ? OBJ_COMMIT :
-		OBJ_BLOB;
+		OBJ_BLOB; /* S_ISREG(mode) || S_ISLNK(mode) */
 }
 
 /* Double-check local_repo_env below if you add to this list. */
-- 
2.31.0.rc0.126.g04f22c5b82


^ permalink raw reply	[flat|nested] 262+ messages in thread

* [PATCH 04/30] tree-walk.h: add object_type member to name_entry
  2021-03-08  2:21   ` [PATCH v2 0/6] " Ævar Arnfjörð Bjarmason
                       ` (3 preceding siblings ...)
  2021-03-08 15:06     ` [PATCH 03/30] cache.h: add a comment to object_type() Ævar Arnfjörð Bjarmason
@ 2021-03-08 15:06     ` Ævar Arnfjörð Bjarmason
  2021-03-08 15:06     ` [PATCH 05/30] tree-walk.c: migrate to using new "object_type" field when possible Ævar Arnfjörð Bjarmason
                       ` (36 subsequent siblings)
  41 siblings, 0 replies; 262+ messages in thread
From: Ævar Arnfjörð Bjarmason @ 2021-03-08 15:06 UTC (permalink / raw)
  To: git
  Cc: Junio C Hamano, Elijah Newren, Kirill Smelkov,
	Nguyễn Thái Ngọc Duy,
	Ævar Arnfjörð Bjarmason

Most users of the tree walking API don't care what the specific mode
of an object in a tree is (e.g. if it's executable), they care if it's
one of OBJ_{TREE,BLOB,COMMIT}.

Let's add an "object_type" enum to the "name_entry" struct to help
such callers.

Ideally we'd have some subset of "enum object_type" here with just
those three entries, so we could rely on the C compiler to
exhaustively check our "switch" statements, but I don't know how to
create such a enum subset without re-labeling OBJ_{TREE,BLOB,COMMIT}
to e.g. "NE_OBJ_*" (an enum is just an int under the hood, so you can
use such a struct with "OBJ_*", but the compiler will complain...).

Signed-off-by: Ævar Arnfjörð Bjarmason <avarab@gmail.com>
---
 tree-walk.c | 4 +++-
 tree-walk.h | 2 ++
 2 files changed, 5 insertions(+), 1 deletion(-)

diff --git a/tree-walk.c b/tree-walk.c
index 2d6226d5f18..b210967b73b 100644
--- a/tree-walk.c
+++ b/tree-walk.c
@@ -47,7 +47,9 @@ static int decode_tree_entry(struct tree_desc *desc, const char *buf, unsigned l
 
 	/* Initialize the descriptor entry */
 	desc->entry.path = path;
-	desc->entry.mode = canon_mode(mode);
+	mode = canon_mode(mode);
+	desc->entry.mode = mode;
+	desc->entry.object_type = object_type(mode);
 	desc->entry.pathlen = len - 1;
 	hashcpy(desc->entry.oid.hash, (const unsigned char *)path + len);
 
diff --git a/tree-walk.h b/tree-walk.h
index a5058469e9b..9f3825d2773 100644
--- a/tree-walk.h
+++ b/tree-walk.h
@@ -17,6 +17,8 @@ struct name_entry {
 	const char *path;
 	int pathlen;
 	unsigned int mode;
+	/* simple 'mode': Only OBJ_{BLOB,TREE,COMMIT} */
+	enum object_type object_type;
 };
 
 /**
-- 
2.31.0.rc0.126.g04f22c5b82


^ permalink raw reply	[flat|nested] 262+ messages in thread

* [PATCH 05/30] tree-walk.c: migrate to using new "object_type" field when possible
  2021-03-08  2:21   ` [PATCH v2 0/6] " Ævar Arnfjörð Bjarmason
                       ` (4 preceding siblings ...)
  2021-03-08 15:06     ` [PATCH 04/30] tree-walk.h: add object_type member to name_entry Ævar Arnfjörð Bjarmason
@ 2021-03-08 15:06     ` Ævar Arnfjörð Bjarmason
  2021-03-09 16:44       ` Elijah Newren
  2021-03-08 15:06     ` [PATCH 06/30] cache.h: have base_name_compare() take "is tree?", not "mode" Ævar Arnfjörð Bjarmason
                       ` (35 subsequent siblings)
  41 siblings, 1 reply; 262+ messages in thread
From: Ævar Arnfjörð Bjarmason @ 2021-03-08 15:06 UTC (permalink / raw)
  To: git
  Cc: Junio C Hamano, Elijah Newren, Kirill Smelkov,
	Nguyễn Thái Ngọc Duy,
	Ævar Arnfjörð Bjarmason

Signed-off-by: Ævar Arnfjörð Bjarmason <avarab@gmail.com>
---
 tree-walk.c | 24 +++++++++++++-----------
 1 file changed, 13 insertions(+), 11 deletions(-)

diff --git a/tree-walk.c b/tree-walk.c
index b210967b73b..6e9161901d8 100644
--- a/tree-walk.c
+++ b/tree-walk.c
@@ -521,7 +521,7 @@ int traverse_trees(struct index_state *istate,
 			if (!entry[i].path)
 				continue;
 			mask |= 1ul << i;
-			if (S_ISDIR(entry[i].mode))
+			if (entry[i].object_type == OBJ_TREE)
 				dirmask |= 1ul << i;
 			e = &entry[i];
 		}
@@ -892,8 +892,8 @@ static int match_entry(const struct pathspec_item *item,
 		 * nothing else (to handle 'submod/' and 'submod'
 		 * uniformly).
 		 */
-		if (!S_ISDIR(entry->mode) &&
-		    (!S_ISGITLINK(entry->mode) || matchlen > pathlen + 1))
+		if (entry->object_type != OBJ_TREE &&
+		    (entry->object_type != OBJ_COMMIT || matchlen > pathlen + 1))
 			return 0;
 	}
 
@@ -1038,7 +1038,7 @@ static enum interesting do_match(struct index_state *istate,
 		    ps->max_depth == -1)
 			return all_entries_interesting;
 		return within_depth(base->buf + base_offset, baselen,
-				    !!S_ISDIR(entry->mode),
+				    entry->object_type == OBJ_TREE,
 				    ps->max_depth) ?
 			entry_interesting : entry_not_interesting;
 	}
@@ -1071,7 +1071,7 @@ static enum interesting do_match(struct index_state *istate,
 
 			if (within_depth(base_str + matchlen + 1,
 					 baselen - matchlen - 1,
-					 !!S_ISDIR(entry->mode),
+					 entry->object_type == OBJ_TREE,
 					 ps->max_depth))
 				goto interesting;
 			else
@@ -1094,7 +1094,8 @@ static enum interesting do_match(struct index_state *istate,
 				 * Match all directories. We'll try to
 				 * match files later on.
 				 */
-				if (ps->recursive && S_ISDIR(entry->mode))
+				if (ps->recursive &&
+				    entry->object_type == OBJ_TREE)
 					return entry_interesting;
 
 				/*
@@ -1105,7 +1106,7 @@ static enum interesting do_match(struct index_state *istate,
 				 * be performed in the submodule itself.
 				 */
 				if (ps->recurse_submodules &&
-				    S_ISGITLINK(entry->mode) &&
+				    entry->object_type == OBJ_COMMIT &&
 				    !ps_strncmp(item, match + baselen,
 						entry->path,
 						item->nowildcard_len - baselen))
@@ -1154,7 +1155,8 @@ static enum interesting do_match(struct index_state *istate,
 		 * character.  More accurate matching can then
 		 * be performed in the submodule itself.
 		 */
-		if (ps->recurse_submodules && S_ISGITLINK(entry->mode) &&
+		if (ps->recurse_submodules &&
+		    entry->object_type == OBJ_COMMIT &&
 		    !ps_strncmp(item, match, base->buf + base_offset,
 				item->nowildcard_len)) {
 			strbuf_setlen(base, base_offset + baselen);
@@ -1170,7 +1172,7 @@ static enum interesting do_match(struct index_state *istate,
 		 * in future, see
 		 * https://lore.kernel.org/git/7vmxo5l2g4.fsf@alter.siamese.dyndns.org/
 		 */
-		if (ps->recursive && S_ISDIR(entry->mode))
+		if (ps->recursive && entry->object_type == OBJ_TREE)
 			return entry_interesting;
 		continue;
 interesting:
@@ -1193,7 +1195,7 @@ static enum interesting do_match(struct index_state *istate,
 			 * can probably return all_entries_interesting or
 			 * all_entries_not_interesting here if matched.
 			 */
-			if (S_ISDIR(entry->mode))
+			if (entry->object_type == OBJ_TREE)
 				return entry_interesting;
 
 			strbuf_add(base, entry->path, pathlen);
@@ -1269,7 +1271,7 @@ enum interesting tree_entry_interesting(struct index_state *istate,
 		return positive;
 
 	/* #15, #19 */
-	if (S_ISDIR(entry->mode) &&
+	if (entry->object_type == OBJ_TREE &&
 	    positive >= entry_interesting &&
 	    negative == entry_interesting)
 		return entry_interesting;
-- 
2.31.0.rc0.126.g04f22c5b82


^ permalink raw reply	[flat|nested] 262+ messages in thread

* [PATCH 06/30] cache.h: have base_name_compare() take "is tree?", not "mode"
  2021-03-08  2:21   ` [PATCH v2 0/6] " Ævar Arnfjörð Bjarmason
                       ` (5 preceding siblings ...)
  2021-03-08 15:06     ` [PATCH 05/30] tree-walk.c: migrate to using new "object_type" field when possible Ævar Arnfjörð Bjarmason
@ 2021-03-08 15:06     ` Ævar Arnfjörð Bjarmason
  2021-03-09 16:56       ` Elijah Newren
  2021-03-08 15:06     ` [PATCH 07/30] tree-walk.h users: switch object_type(...) to new .object_type Ævar Arnfjörð Bjarmason
                       ` (34 subsequent siblings)
  41 siblings, 1 reply; 262+ messages in thread
From: Ævar Arnfjörð Bjarmason @ 2021-03-08 15:06 UTC (permalink / raw)
  To: git
  Cc: Junio C Hamano, Elijah Newren, Kirill Smelkov,
	Nguyễn Thái Ngọc Duy,
	Ævar Arnfjörð Bjarmason

Change the base_name_compare() API and the related df_name_compare()
function to take a boolean argument indicating whether the entry is a
tree or not, instead of having them call S_ISDIR(mode) on their own.

This makes use of the new "object_type" field in the "name_entry".

The API being modified here was originally added way back in
958ba6c96eb (Introduce "base_name_compare()" helper function,
2005-05-20).

Signed-off-by: Ævar Arnfjörð Bjarmason <avarab@gmail.com>
---
 builtin/fast-import.c |  8 ++++----
 builtin/mktree.c      |  4 ++--
 cache.h               |  4 ++--
 combine-diff.c        |  8 +++++---
 match-trees.c         |  6 ++++--
 merge-ort.c           |  4 ++--
 merge-recursive.c     |  6 +++---
 read-cache.c          | 16 ++++++++--------
 tree-diff.c           |  7 +++++--
 unpack-trees.c        | 15 ++++++++-------
 10 files changed, 43 insertions(+), 35 deletions(-)

diff --git a/builtin/fast-import.c b/builtin/fast-import.c
index dd4d09ceceb..ce4613c1595 100644
--- a/builtin/fast-import.c
+++ b/builtin/fast-import.c
@@ -1288,8 +1288,8 @@ static int tecmp0 (const void *_a, const void *_b)
 	struct tree_entry *a = *((struct tree_entry**)_a);
 	struct tree_entry *b = *((struct tree_entry**)_b);
 	return base_name_compare(
-		a->name->str_dat, a->name->str_len, a->versions[0].mode,
-		b->name->str_dat, b->name->str_len, b->versions[0].mode);
+		a->name->str_dat, a->name->str_len, 1,
+		b->name->str_dat, b->name->str_len, 1);
 }
 
 static int tecmp1 (const void *_a, const void *_b)
@@ -1297,8 +1297,8 @@ static int tecmp1 (const void *_a, const void *_b)
 	struct tree_entry *a = *((struct tree_entry**)_a);
 	struct tree_entry *b = *((struct tree_entry**)_b);
 	return base_name_compare(
-		a->name->str_dat, a->name->str_len, a->versions[1].mode,
-		b->name->str_dat, b->name->str_len, b->versions[1].mode);
+		a->name->str_dat, a->name->str_len, 1,
+		b->name->str_dat, b->name->str_len, 1);
 }
 
 static void mktree(struct tree_content *t, int v, struct strbuf *b)
diff --git a/builtin/mktree.c b/builtin/mktree.c
index 891991b00d6..2c1973229ac 100644
--- a/builtin/mktree.c
+++ b/builtin/mktree.c
@@ -37,8 +37,8 @@ static int ent_compare(const void *a_, const void *b_)
 {
 	struct treeent *a = *(struct treeent **)a_;
 	struct treeent *b = *(struct treeent **)b_;
-	return base_name_compare(a->name, a->len, a->mode,
-				 b->name, b->len, b->mode);
+	return base_name_compare(a->name, a->len, S_ISDIR(a->mode),
+				 b->name, b->len, S_ISDIR(b->mode));
 }
 
 static void write_tree(struct object_id *oid)
diff --git a/cache.h b/cache.h
index e513f0ee5b4..49994dae916 100644
--- a/cache.h
+++ b/cache.h
@@ -1506,8 +1506,8 @@ int repo_interpret_branch_name(struct repository *r,
 
 int validate_headref(const char *ref);
 
-int base_name_compare(const char *name1, int len1, int mode1, const char *name2, int len2, int mode2);
-int df_name_compare(const char *name1, int len1, int mode1, const char *name2, int len2, int mode2);
+int base_name_compare(const char *name1, int len1, int isdir1, const char *name2, int len2, int isdir2);
+int df_name_compare(const char *name1, int len1, int isdir1, const char *name2, int len2, int isdir2);
 int name_compare(const char *name1, size_t len1, const char *name2, size_t len2);
 int cache_name_stage_compare(const char *name1, int len1, int stage1, const char *name2, int len2, int stage2);
 
diff --git a/combine-diff.c b/combine-diff.c
index 9228aebc16b..64d7aaf1710 100644
--- a/combine-diff.c
+++ b/combine-diff.c
@@ -16,11 +16,13 @@
 static int compare_paths(const struct combine_diff_path *one,
 			  const struct diff_filespec *two)
 {
-	if (!S_ISDIR(one->mode) && !S_ISDIR(two->mode))
+	int isdir_one = S_ISDIR(one->mode);
+	int isdir_two = S_ISDIR(two->mode);
+	if (!isdir_one && !isdir_two)
 		return strcmp(one->path, two->path);
 
-	return base_name_compare(one->path, strlen(one->path), one->mode,
-				 two->path, strlen(two->path), two->mode);
+	return base_name_compare(one->path, strlen(one->path), isdir_one,
+				 two->path, strlen(two->path), isdir_two);
 }
 
 static int filename_changed(char status)
diff --git a/match-trees.c b/match-trees.c
index 1011357ad0c..4d124a0fd1b 100644
--- a/match-trees.c
+++ b/match-trees.c
@@ -67,8 +67,10 @@ static void *fill_tree_desc_strict(struct tree_desc *desc,
 static int base_name_entries_compare(const struct name_entry *a,
 				     const struct name_entry *b)
 {
-	return base_name_compare(a->path, tree_entry_len(a), a->mode,
-				 b->path, tree_entry_len(b), b->mode);
+	int isdira = a->object_type == OBJ_TREE;
+	int isdirb = b->object_type == OBJ_TREE;
+	return base_name_compare(a->path, tree_entry_len(a), isdira,
+				 b->path, tree_entry_len(b), isdirb);
 }
 
 /*
diff --git a/merge-ort.c b/merge-ort.c
index 603d30c5217..4075d13aaab 100644
--- a/merge-ort.c
+++ b/merge-ort.c
@@ -2390,8 +2390,8 @@ static int tree_entry_order(const void *a_, const void *b_)
 
 	const struct merged_info *ami = a->util;
 	const struct merged_info *bmi = b->util;
-	return base_name_compare(a->string, strlen(a->string), ami->result.mode,
-				 b->string, strlen(b->string), bmi->result.mode);
+	return base_name_compare(a->string, strlen(a->string), S_ISDIR(ami->result.mode),
+				 b->string, strlen(b->string), S_ISDIR(bmi->result.mode));
 }
 
 static void write_tree(struct object_id *result_oid,
diff --git a/merge-recursive.c b/merge-recursive.c
index 1593f374495..0baa6b5ca56 100644
--- a/merge-recursive.c
+++ b/merge-recursive.c
@@ -554,12 +554,12 @@ static int string_list_df_name_compare(const char *one, const char *two)
 	 *
 	 * To achieve this, we sort with df_name_compare and provide
 	 * the mode S_IFDIR so that D/F conflicts will sort correctly.
-	 * We use the mode S_IFDIR for everything else for simplicity,
+	 * We say we have a directory for everything else for simplicity,
 	 * since in other cases any changes in their order due to
 	 * sorting cause no problems for us.
 	 */
-	int cmp = df_name_compare(one, onelen, S_IFDIR,
-				  two, twolen, S_IFDIR);
+	int cmp = df_name_compare(one, onelen, 1, two, twolen, 1);
+
 	/*
 	 * Now that 'foo' and 'foo/bar' compare equal, we have to make sure
 	 * that 'foo' comes before 'foo/bar'.
diff --git a/read-cache.c b/read-cache.c
index 1e9a50c6c73..edfce1f0cb8 100644
--- a/read-cache.c
+++ b/read-cache.c
@@ -462,8 +462,8 @@ int ie_modified(struct index_state *istate,
 	return 0;
 }
 
-int base_name_compare(const char *name1, int len1, int mode1,
-		      const char *name2, int len2, int mode2)
+int base_name_compare(const char *name1, int len1, int isdir1,
+		      const char *name2, int len2, int isdir2)
 {
 	unsigned char c1, c2;
 	int len = len1 < len2 ? len1 : len2;
@@ -474,9 +474,9 @@ int base_name_compare(const char *name1, int len1, int mode1,
 		return cmp;
 	c1 = name1[len];
 	c2 = name2[len];
-	if (!c1 && S_ISDIR(mode1))
+	if (!c1 && isdir1)
 		c1 = '/';
-	if (!c2 && S_ISDIR(mode2))
+	if (!c2 && isdir2)
 		c2 = '/';
 	return (c1 < c2) ? -1 : (c1 > c2) ? 1 : 0;
 }
@@ -491,8 +491,8 @@ int base_name_compare(const char *name1, int len1, int mode1,
  * This is used by routines that want to traverse the git namespace
  * but then handle conflicting entries together when possible.
  */
-int df_name_compare(const char *name1, int len1, int mode1,
-		    const char *name2, int len2, int mode2)
+int df_name_compare(const char *name1, int len1, int isdir1,
+		    const char *name2, int len2, int isdir2)
 {
 	int len = len1 < len2 ? len1 : len2, cmp;
 	unsigned char c1, c2;
@@ -504,10 +504,10 @@ int df_name_compare(const char *name1, int len1, int mode1,
 	if (len1 == len2)
 		return 0;
 	c1 = name1[len];
-	if (!c1 && S_ISDIR(mode1))
+	if (!c1 && isdir1)
 		c1 = '/';
 	c2 = name2[len];
-	if (!c2 && S_ISDIR(mode2))
+	if (!c2 && isdir2)
 		c2 = '/';
 	if (c1 == '/' && !c2)
 		return 0;
diff --git a/tree-diff.c b/tree-diff.c
index 7cebbb327e2..f133834597c 100644
--- a/tree-diff.c
+++ b/tree-diff.c
@@ -50,6 +50,7 @@ static int tree_entry_pathcmp(struct tree_desc *t1, struct tree_desc *t2)
 {
 	struct name_entry *e1, *e2;
 	int cmp;
+	int e1_is_tree, e2_is_tree;
 
 	/* empty descriptors sort after valid tree entries */
 	if (!t1->size)
@@ -58,9 +59,11 @@ static int tree_entry_pathcmp(struct tree_desc *t1, struct tree_desc *t2)
 		return -1;
 
 	e1 = &t1->entry;
+	e1_is_tree = e1->object_type == OBJ_TREE;
 	e2 = &t2->entry;
-	cmp = base_name_compare(e1->path, tree_entry_len(e1), e1->mode,
-				e2->path, tree_entry_len(e2), e2->mode);
+	e2_is_tree = e2->object_type == OBJ_TREE;
+	cmp = base_name_compare(e1->path, tree_entry_len(e1), e1_is_tree,
+				e2->path, tree_entry_len(e2), e2_is_tree);
 	return cmp;
 }
 
diff --git a/unpack-trees.c b/unpack-trees.c
index f5f668f532d..802f7771d75 100644
--- a/unpack-trees.c
+++ b/unpack-trees.c
@@ -922,7 +922,7 @@ static int traverse_trees_recursive(int n, unsigned long dirmask,
 static int do_compare_entry_piecewise(const struct cache_entry *ce,
 				      const struct traverse_info *info,
 				      const char *name, size_t namelen,
-				      unsigned mode)
+				      unsigned is_tree)
 {
 	int pathlen, ce_len;
 	const char *ce_name;
@@ -930,7 +930,7 @@ static int do_compare_entry_piecewise(const struct cache_entry *ce,
 	if (info->prev) {
 		int cmp = do_compare_entry_piecewise(ce, info->prev,
 						     info->name, info->namelen,
-						     info->mode);
+						     S_ISDIR(info->mode));
 		if (cmp)
 			return cmp;
 	}
@@ -944,13 +944,13 @@ static int do_compare_entry_piecewise(const struct cache_entry *ce,
 	ce_len -= pathlen;
 	ce_name = ce->name + pathlen;
 
-	return df_name_compare(ce_name, ce_len, S_IFREG, name, namelen, mode);
+	return df_name_compare(ce_name, ce_len, 0, name, namelen, is_tree);
 }
 
 static int do_compare_entry(const struct cache_entry *ce,
 			    const struct traverse_info *info,
 			    const char *name, size_t namelen,
-			    unsigned mode)
+			    unsigned is_tree)
 {
 	int pathlen, ce_len;
 	const char *ce_name;
@@ -962,7 +962,7 @@ static int do_compare_entry(const struct cache_entry *ce,
 	 * it is quicker to use the precomputed version.
 	 */
 	if (!info->traverse_path)
-		return do_compare_entry_piecewise(ce, info, name, namelen, mode);
+		return do_compare_entry_piecewise(ce, info, name, namelen, is_tree);
 
 	cmp = strncmp(ce->name, info->traverse_path, info->pathlen);
 	if (cmp)
@@ -977,12 +977,13 @@ static int do_compare_entry(const struct cache_entry *ce,
 	ce_len -= pathlen;
 	ce_name = ce->name + pathlen;
 
-	return df_name_compare(ce_name, ce_len, S_IFREG, name, namelen, mode);
+	return df_name_compare(ce_name, ce_len, 0, name, namelen, is_tree);
 }
 
 static int compare_entry(const struct cache_entry *ce, const struct traverse_info *info, const struct name_entry *n)
 {
-	int cmp = do_compare_entry(ce, info, n->path, n->pathlen, n->mode);
+	int is_tree = n->object_type == OBJ_TREE;
+	int cmp = do_compare_entry(ce, info, n->path, n->pathlen, is_tree);
 	if (cmp)
 		return cmp;
 
-- 
2.31.0.rc0.126.g04f22c5b82


^ permalink raw reply	[flat|nested] 262+ messages in thread

* [PATCH 07/30] tree-walk.h users: switch object_type(...) to new .object_type
  2021-03-08  2:21   ` [PATCH v2 0/6] " Ævar Arnfjörð Bjarmason
                       ` (6 preceding siblings ...)
  2021-03-08 15:06     ` [PATCH 06/30] cache.h: have base_name_compare() take "is tree?", not "mode" Ævar Arnfjörð Bjarmason
@ 2021-03-08 15:06     ` Ævar Arnfjörð Bjarmason
  2021-03-08 15:06     ` [PATCH 08/30] tree.h: format argument lists of read_tree_recursive() users Ævar Arnfjörð Bjarmason
                       ` (33 subsequent siblings)
  41 siblings, 0 replies; 262+ messages in thread
From: Ævar Arnfjörð Bjarmason @ 2021-03-08 15:06 UTC (permalink / raw)
  To: git
  Cc: Junio C Hamano, Elijah Newren, Kirill Smelkov,
	Nguyễn Thái Ngọc Duy,
	Ævar Arnfjörð Bjarmason

Change uses of object_type(entry.mode) to use the new
entry.object_type field.

Signed-off-by: Ævar Arnfjörð Bjarmason <avarab@gmail.com>
---
 builtin/pack-objects.c |  2 +-
 http-push.c            |  6 ++++--
 pack-bitmap-write.c    |  8 +++++---
 revision.c             | 12 ++++++++----
 4 files changed, 18 insertions(+), 10 deletions(-)

diff --git a/builtin/pack-objects.c b/builtin/pack-objects.c
index 6d62aaf59a0..d3ba1d4a4a6 100644
--- a/builtin/pack-objects.c
+++ b/builtin/pack-objects.c
@@ -1534,7 +1534,7 @@ static void add_pbase_object(struct tree_desc *tree,
 			return;
 		if (name[cmplen] != '/') {
 			add_object_entry(&entry.oid,
-					 object_type(entry.mode),
+					 entry.object_type,
 					 fullname, 1);
 			return;
 		}
diff --git a/http-push.c b/http-push.c
index 6a4a43e07f2..234b79a5dba 100644
--- a/http-push.c
+++ b/http-push.c
@@ -1314,7 +1314,7 @@ static struct object_list **process_tree(struct tree *tree,
 	init_tree_desc(&desc, tree->buffer, tree->size);
 
 	while (tree_entry(&desc, &entry))
-		switch (object_type(entry.mode)) {
+		switch (entry.object_type) {
 		case OBJ_TREE:
 			p = process_tree(lookup_tree(the_repository, &entry.oid),
 					 p);
@@ -1323,9 +1323,11 @@ static struct object_list **process_tree(struct tree *tree,
 			p = process_blob(lookup_blob(the_repository, &entry.oid),
 					 p);
 			break;
-		default:
+		case OBJ_COMMIT:
 			/* Subproject commit - not in this repository */
 			break;
+		default:
+			BUG("unreachable");
 		}
 
 	free_tree_buffer(tree);
diff --git a/pack-bitmap-write.c b/pack-bitmap-write.c
index 88d9e696a54..ac32bf2242c 100644
--- a/pack-bitmap-write.c
+++ b/pack-bitmap-write.c
@@ -353,7 +353,7 @@ static void fill_bitmap_tree(struct bitmap *bitmap,
 	init_tree_desc(&desc, tree->buffer, tree->size);
 
 	while (tree_entry(&desc, &entry)) {
-		switch (object_type(entry.mode)) {
+		switch (entry.object_type) {
 		case OBJ_TREE:
 			fill_bitmap_tree(bitmap,
 					 lookup_tree(the_repository, &entry.oid));
@@ -361,9 +361,11 @@ static void fill_bitmap_tree(struct bitmap *bitmap,
 		case OBJ_BLOB:
 			bitmap_set(bitmap, find_object_pos(&entry.oid));
 			break;
-		default:
-			/* Gitlink, etc; not reachable */
+		case OBJ_COMMIT:
+			/* submodule commit - not in this repository */
 			break;
+		default:
+			BUG("unreachable");
 		}
 	}
 
diff --git a/revision.c b/revision.c
index b78733f5089..1db4e4e90a2 100644
--- a/revision.c
+++ b/revision.c
@@ -72,16 +72,18 @@ static void mark_tree_contents_uninteresting(struct repository *r,
 
 	init_tree_desc(&desc, tree->buffer, tree->size);
 	while (tree_entry(&desc, &entry)) {
-		switch (object_type(entry.mode)) {
+		switch (entry.object_type) {
 		case OBJ_TREE:
 			mark_tree_uninteresting(r, lookup_tree(r, &entry.oid));
 			break;
 		case OBJ_BLOB:
 			mark_blob_uninteresting(lookup_blob(r, &entry.oid));
 			break;
-		default:
+		case OBJ_COMMIT:
 			/* Subproject commit - not in this repository */
 			break;
+		default:
+			BUG("unreachable");
 		}
 	}
 
@@ -179,7 +181,7 @@ static void add_children_by_path(struct repository *r,
 
 	init_tree_desc(&desc, tree->buffer, tree->size);
 	while (tree_entry(&desc, &entry)) {
-		switch (object_type(entry.mode)) {
+		switch (entry.object_type) {
 		case OBJ_TREE:
 			paths_and_oids_insert(map, entry.path, &entry.oid);
 
@@ -196,9 +198,11 @@ static void add_children_by_path(struct repository *r,
 					child->object.flags |= UNINTERESTING;
 			}
 			break;
-		default:
+		case OBJ_COMMIT:
 			/* Subproject commit - not in this repository */
 			break;
+		default:
+			BUG("unreachable");
 		}
 	}
 
-- 
2.31.0.rc0.126.g04f22c5b82


^ permalink raw reply	[flat|nested] 262+ messages in thread

* [PATCH 08/30] tree.h: format argument lists of read_tree_recursive() users
  2021-03-08  2:21   ` [PATCH v2 0/6] " Ævar Arnfjörð Bjarmason
                       ` (7 preceding siblings ...)
  2021-03-08 15:06     ` [PATCH 07/30] tree-walk.h users: switch object_type(...) to new .object_type Ævar Arnfjörð Bjarmason
@ 2021-03-08 15:06     ` Ævar Arnfjörð Bjarmason
  2021-03-08 15:06     ` [PATCH 09/30] tree.h users: format argument lists in archive.c Ævar Arnfjörð Bjarmason
                       ` (32 subsequent siblings)
  41 siblings, 0 replies; 262+ messages in thread
From: Ævar Arnfjörð Bjarmason @ 2021-03-08 15:06 UTC (permalink / raw)
  To: git
  Cc: Junio C Hamano, Elijah Newren, Kirill Smelkov,
	Nguyễn Thái Ngọc Duy,
	Ævar Arnfjörð Bjarmason

In preparation for adding a new argument to read_tree_fn_t re-indent
and format the argument list of read_tree_recursive() callbacks, and
the relevant functions they call.

This is a whitespace-only change to make reading subsequent commits
easier. I'll be adding a new argument on the "mode" line, so leave
space on it.

Signed-off-by: Ævar Arnfjörð Bjarmason <avarab@gmail.com>
---
 archive.c          | 13 ++++++++-----
 builtin/checkout.c |  4 +++-
 builtin/log.c      |  5 +++--
 builtin/ls-tree.c  |  4 +++-
 merge-recursive.c  |  3 ++-
 tree.h             |  5 ++++-
 6 files changed, 23 insertions(+), 11 deletions(-)

diff --git a/archive.c b/archive.c
index 6669a4bd147..db69a8acadb 100644
--- a/archive.c
+++ b/archive.c
@@ -138,8 +138,9 @@ static int check_attr_export_subst(const struct attr_check *check)
 }
 
 static int write_archive_entry(const struct object_id *oid, const char *base,
-		int baselen, const char *filename, unsigned mode, int stage,
-		void *context)
+			       int baselen, const char *filename,
+			       unsigned mode,
+			       int stage, void *context)
 {
 	static struct strbuf path = STRBUF_INIT;
 	struct archiver_context *c = context;
@@ -230,8 +231,9 @@ static int write_directory(struct archiver_context *c)
 }
 
 static int queue_or_write_archive_entry(const struct object_id *oid,
-		struct strbuf *base, const char *filename,
-		unsigned mode, void *context)
+					struct strbuf *base, const char *filename,
+					unsigned mode,
+					void *context)
 {
 	struct archiver_context *c = context;
 	int stage = 0;
@@ -378,7 +380,8 @@ struct path_exists_context {
 };
 
 static int reject_entry(const struct object_id *oid, struct strbuf *base,
-			const char *filename, unsigned mode,
+			const char *filename,
+			unsigned mode,
 			void *context)
 {
 	int ret = -1;
diff --git a/builtin/checkout.c b/builtin/checkout.c
index 2c2d58a230f..a78b54624b0 100644
--- a/builtin/checkout.c
+++ b/builtin/checkout.c
@@ -114,7 +114,9 @@ static int post_checkout_hook(struct commit *old_commit, struct commit *new_comm
 }
 
 static int update_some(const struct object_id *oid, struct strbuf *base,
-		const char *pathname, unsigned mode, void *context)
+		       const char *pathname,
+		       unsigned mode,
+		       void *context)
 {
 	int len;
 	struct cache_entry *ce;
diff --git a/builtin/log.c b/builtin/log.c
index 58acb2b76ab..3766f553971 100644
--- a/builtin/log.c
+++ b/builtin/log.c
@@ -598,8 +598,9 @@ static int show_tag_object(const struct object_id *oid, struct rev_info *rev)
 }
 
 static int show_tree_object(const struct object_id *oid,
-		struct strbuf *base,
-		const char *pathname, unsigned mode, void *context)
+			    struct strbuf *base, const char *pathname,
+			    unsigned mode,
+			    void *context)
 {
 	FILE *file = context;
 	fprintf(file, "%s%s\n", pathname, S_ISDIR(mode) ? "/" : "");
diff --git a/builtin/ls-tree.c b/builtin/ls-tree.c
index dbb31217beb..aaa41e66234 100644
--- a/builtin/ls-tree.c
+++ b/builtin/ls-tree.c
@@ -62,7 +62,9 @@ static int show_recursive(const char *base, int baselen, const char *pathname)
 }
 
 static int show_tree(const struct object_id *oid, struct strbuf *base,
-		const char *pathname, unsigned mode, void *context)
+		     const char *pathname,
+		     unsigned mode,
+		     void *context)
 {
 	int retval = 0;
 	int baselen;
diff --git a/merge-recursive.c b/merge-recursive.c
index 0baa6b5ca56..aa12543ecc9 100644
--- a/merge-recursive.c
+++ b/merge-recursive.c
@@ -453,7 +453,8 @@ static void unpack_trees_finish(struct merge_options *opt)
 
 static int save_files_dirs(const struct object_id *oid,
 			   struct strbuf *base, const char *path,
-			   unsigned int mode, void *context)
+			   unsigned int mode,
+			   void *context)
 {
 	struct path_hashmap_entry *entry;
 	int baselen = base->len;
diff --git a/tree.h b/tree.h
index 1309ab997e5..a7030e52679 100644
--- a/tree.h
+++ b/tree.h
@@ -31,7 +31,10 @@ struct tree *parse_tree_indirect(const struct object_id *oid);
 int cmp_cache_name_compare(const void *a_, const void *b_);
 
 #define READ_TREE_RECURSIVE 1
-typedef int (*read_tree_fn_t)(const struct object_id *, struct strbuf *, const char *, unsigned int, void *);
+typedef int (*read_tree_fn_t)(const struct object_id *, struct strbuf *,
+			      const char *,
+			      unsigned int,
+			      void *);
 
 int read_tree_recursive(struct repository *r,
 			struct tree *tree,
-- 
2.31.0.rc0.126.g04f22c5b82


^ permalink raw reply	[flat|nested] 262+ messages in thread

* [PATCH 09/30] tree.h users: format argument lists in archive.c
  2021-03-08  2:21   ` [PATCH v2 0/6] " Ævar Arnfjörð Bjarmason
                       ` (8 preceding siblings ...)
  2021-03-08 15:06     ` [PATCH 08/30] tree.h: format argument lists of read_tree_recursive() users Ævar Arnfjörð Bjarmason
@ 2021-03-08 15:06     ` Ævar Arnfjörð Bjarmason
  2021-03-09 17:04       ` Elijah Newren
  2021-03-08 15:06     ` [PATCH 10/30] archive: get rid of 'stage' parameter Ævar Arnfjörð Bjarmason
                       ` (31 subsequent siblings)
  41 siblings, 1 reply; 262+ messages in thread
From: Ævar Arnfjörð Bjarmason @ 2021-03-08 15:06 UTC (permalink / raw)
  To: git
  Cc: Junio C Hamano, Elijah Newren, Kirill Smelkov,
	Nguyễn Thái Ngọc Duy,
	Ævar Arnfjörð Bjarmason

Re-indent and re-flow the argument lists archive.c has downstream of
its read_tree_recursive() call to make subsequent commits easier to
read, as I only expect to be modifying the "stage" and "mode" lines.

Signed-off-by: Ævar Arnfjörð Bjarmason <avarab@gmail.com>
---
 archive.c | 25 +++++++++++++++++--------
 1 file changed, 17 insertions(+), 8 deletions(-)

diff --git a/archive.c b/archive.c
index db69a8acadb..e245c0d5a54 100644
--- a/archive.c
+++ b/archive.c
@@ -140,7 +140,8 @@ static int check_attr_export_subst(const struct attr_check *check)
 static int write_archive_entry(const struct object_id *oid, const char *base,
 			       int baselen, const char *filename,
 			       unsigned mode,
-			       int stage, void *context)
+			       int stage,
+			       void *context)
 {
 	static struct strbuf path = STRBUF_INIT;
 	struct archiver_context *c = context;
@@ -197,8 +198,10 @@ static int write_archive_entry(const struct object_id *oid, const char *base,
 }
 
 static void queue_directory(const unsigned char *sha1,
-		struct strbuf *base, const char *filename,
-		unsigned mode, int stage, struct archiver_context *c)
+			    struct strbuf *base, const char *filename,
+			    unsigned mode,
+			    int stage,
+			    struct archiver_context *c)
 {
 	struct directory *d;
 	size_t len = st_add4(base->len, 1, strlen(filename), 1);
@@ -224,8 +227,10 @@ static int write_directory(struct archiver_context *c)
 	ret =
 		write_directory(c) ||
 		write_archive_entry(&d->oid, d->path, d->baselen,
-				    d->path + d->baselen, d->mode,
-				    d->stage, c) != READ_TREE_RECURSIVE;
+				    d->path + d->baselen,
+				    d->mode,
+				    d->stage,
+				    c) != READ_TREE_RECURSIVE;
 	free(d);
 	return ret ? -1 : 0;
 }
@@ -259,14 +264,18 @@ static int queue_or_write_archive_entry(const struct object_id *oid,
 		if (check_attr_export_ignore(check))
 			return 0;
 		queue_directory(oid->hash, base, filename,
-				mode, stage, c);
+				mode,
+				stage,
+				c);
 		return READ_TREE_RECURSIVE;
 	}
 
 	if (write_directory(c))
 		return -1;
-	return write_archive_entry(oid, base->buf, base->len, filename, mode,
-				   stage, context);
+	return write_archive_entry(oid, base->buf, base->len, filename,
+				   mode,
+				   stage,
+				   context);
 }
 
 struct extra_file_info {
-- 
2.31.0.rc0.126.g04f22c5b82


^ permalink raw reply	[flat|nested] 262+ messages in thread

* [PATCH 10/30] archive: get rid of 'stage' parameter
  2021-03-08  2:21   ` [PATCH v2 0/6] " Ævar Arnfjörð Bjarmason
                       ` (9 preceding siblings ...)
  2021-03-08 15:06     ` [PATCH 09/30] tree.h users: format argument lists in archive.c Ævar Arnfjörð Bjarmason
@ 2021-03-08 15:06     ` Ævar Arnfjörð Bjarmason
  2021-03-08 15:06     ` [PATCH 11/30] tree.h API: make read_tree_fn_t take an "enum object_type" Ævar Arnfjörð Bjarmason
                       ` (30 subsequent siblings)
  41 siblings, 0 replies; 262+ messages in thread
From: Ævar Arnfjörð Bjarmason @ 2021-03-08 15:06 UTC (permalink / raw)
  To: git
  Cc: Junio C Hamano, Elijah Newren, Kirill Smelkov,
	Nguyễn Thái Ngọc Duy,
	Ævar Arnfjörð Bjarmason

Stop passing the "stage" parameter around in archive.c. This parameter
existed because the read_tree_recursive() function used to provide it,
but no longer does. See my in-flight commit to remove it. (tree.h API:
remove "stage" parameter from read_tree_recursive(), 2021-03-06).

As can be seen in 562e25abea9 (archive: centralize archive entry
writing, 2008-07-14) and ed22b4173bd (archive: support filtering paths
with glob, 2014-09-21) it was never used by this code. We simply added
it as a boilerplate, and then later added it to our own "directory
"struct.

Signed-off-by: Ævar Arnfjörð Bjarmason <avarab@gmail.com>
---
 archive.c | 8 --------
 1 file changed, 8 deletions(-)

diff --git a/archive.c b/archive.c
index e245c0d5a54..26534a30d3b 100644
--- a/archive.c
+++ b/archive.c
@@ -107,7 +107,6 @@ struct directory {
 	struct object_id oid;
 	int baselen, len;
 	unsigned mode;
-	int stage;
 	char path[FLEX_ARRAY];
 };
 
@@ -140,7 +139,6 @@ static int check_attr_export_subst(const struct attr_check *check)
 static int write_archive_entry(const struct object_id *oid, const char *base,
 			       int baselen, const char *filename,
 			       unsigned mode,
-			       int stage,
 			       void *context)
 {
 	static struct strbuf path = STRBUF_INIT;
@@ -200,7 +198,6 @@ static int write_archive_entry(const struct object_id *oid, const char *base,
 static void queue_directory(const unsigned char *sha1,
 			    struct strbuf *base, const char *filename,
 			    unsigned mode,
-			    int stage,
 			    struct archiver_context *c)
 {
 	struct directory *d;
@@ -209,7 +206,6 @@ static void queue_directory(const unsigned char *sha1,
 	d->up	   = c->bottom;
 	d->baselen = base->len;
 	d->mode	   = mode;
-	d->stage   = stage;
 	c->bottom  = d;
 	d->len = xsnprintf(d->path, len, "%.*s%s/", (int)base->len, base->buf, filename);
 	hashcpy(d->oid.hash, sha1);
@@ -229,7 +225,6 @@ static int write_directory(struct archiver_context *c)
 		write_archive_entry(&d->oid, d->path, d->baselen,
 				    d->path + d->baselen,
 				    d->mode,
-				    d->stage,
 				    c) != READ_TREE_RECURSIVE;
 	free(d);
 	return ret ? -1 : 0;
@@ -241,7 +236,6 @@ static int queue_or_write_archive_entry(const struct object_id *oid,
 					void *context)
 {
 	struct archiver_context *c = context;
-	int stage = 0;
 
 	while (c->bottom &&
 	       !(base->len >= c->bottom->len &&
@@ -265,7 +259,6 @@ static int queue_or_write_archive_entry(const struct object_id *oid,
 			return 0;
 		queue_directory(oid->hash, base, filename,
 				mode,
-				stage,
 				c);
 		return READ_TREE_RECURSIVE;
 	}
@@ -274,7 +267,6 @@ static int queue_or_write_archive_entry(const struct object_id *oid,
 		return -1;
 	return write_archive_entry(oid, base->buf, base->len, filename,
 				   mode,
-				   stage,
 				   context);
 }
 
-- 
2.31.0.rc0.126.g04f22c5b82


^ permalink raw reply	[flat|nested] 262+ messages in thread

* [PATCH 11/30] tree.h API: make read_tree_fn_t take an "enum object_type"
  2021-03-08  2:21   ` [PATCH v2 0/6] " Ævar Arnfjörð Bjarmason
                       ` (10 preceding siblings ...)
  2021-03-08 15:06     ` [PATCH 10/30] archive: get rid of 'stage' parameter Ævar Arnfjörð Bjarmason
@ 2021-03-08 15:06     ` Ævar Arnfjörð Bjarmason
  2021-03-08 15:06     ` [PATCH 12/30] tree-walk.h users: migrate "p->mode &&" pattern Ævar Arnfjörð Bjarmason
                       ` (29 subsequent siblings)
  41 siblings, 0 replies; 262+ messages in thread
From: Ævar Arnfjörð Bjarmason @ 2021-03-08 15:06 UTC (permalink / raw)
  To: git
  Cc: Junio C Hamano, Elijah Newren, Kirill Smelkov,
	Nguyễn Thái Ngọc Duy,
	Ævar Arnfjörð Bjarmason

Most of the users of the read_tree_fn_t callback do not care about the
"mode" per-se, they just care what type it resolves to.

Amend this callback mechanism added in 3c5e8468a93 (ls-tree: major
rewrite to do pathspec, 2005-11-26) to pass the object_type, and use
it whenever possible.

In the archive.c code we could go much deeper with this refactoring,
after getting the "mode" that code will pass it around itself and into
archive-{tar,zip}.c. As far as I can tell we could drop the mode
early, and just pass "enum_object_type type, int is_executable". That
would be slightly redundant space-wise, but would assure us that we're
not writing out raw modes found in trees, but are normalizing them.

But that particular refactoring would be larger than what I'm trying
to accomplish here, so let's leave it for now.

Signed-off-by: Ævar Arnfjörð Bjarmason <avarab@gmail.com>
---
 archive.c          |  8 ++++----
 builtin/checkout.c |  4 ++--
 builtin/log.c      |  4 ++--
 builtin/ls-files.c |  6 ++++--
 builtin/ls-tree.c  | 12 +++++-------
 merge-recursive.c  |  6 ++++--
 tree.c             | 19 ++++++++++++-------
 tree.h             |  2 +-
 8 files changed, 34 insertions(+), 27 deletions(-)

diff --git a/archive.c b/archive.c
index 26534a30d3b..64abe736f93 100644
--- a/archive.c
+++ b/archive.c
@@ -232,7 +232,7 @@ static int write_directory(struct archiver_context *c)
 
 static int queue_or_write_archive_entry(const struct object_id *oid,
 					struct strbuf *base, const char *filename,
-					unsigned mode,
+					enum object_type object_type, unsigned mode,
 					void *context)
 {
 	struct archiver_context *c = context;
@@ -245,7 +245,7 @@ static int queue_or_write_archive_entry(const struct object_id *oid,
 		c->bottom = next;
 	}
 
-	if (S_ISDIR(mode)) {
+	if (object_type == OBJ_TREE) {
 		size_t baselen = base->len;
 		const struct attr_check *check;
 
@@ -382,13 +382,13 @@ struct path_exists_context {
 
 static int reject_entry(const struct object_id *oid, struct strbuf *base,
 			const char *filename,
-			unsigned mode,
+			enum object_type object_type, unsigned mode,
 			void *context)
 {
 	int ret = -1;
 	struct path_exists_context *ctx = context;
 
-	if (S_ISDIR(mode)) {
+	if (object_type == OBJ_TREE) {
 		struct strbuf sb = STRBUF_INIT;
 		strbuf_addbuf(&sb, base);
 		strbuf_addstr(&sb, filename);
diff --git a/builtin/checkout.c b/builtin/checkout.c
index a78b54624b0..d4adfdb5046 100644
--- a/builtin/checkout.c
+++ b/builtin/checkout.c
@@ -115,14 +115,14 @@ static int post_checkout_hook(struct commit *old_commit, struct commit *new_comm
 
 static int update_some(const struct object_id *oid, struct strbuf *base,
 		       const char *pathname,
-		       unsigned mode,
+		       enum object_type object_type, unsigned mode,
 		       void *context)
 {
 	int len;
 	struct cache_entry *ce;
 	int pos;
 
-	if (S_ISDIR(mode))
+	if (object_type == OBJ_TREE)
 		return READ_TREE_RECURSIVE;
 
 	len = base->len + strlen(pathname);
diff --git a/builtin/log.c b/builtin/log.c
index 3766f553971..19a916221d5 100644
--- a/builtin/log.c
+++ b/builtin/log.c
@@ -599,11 +599,11 @@ static int show_tag_object(const struct object_id *oid, struct rev_info *rev)
 
 static int show_tree_object(const struct object_id *oid,
 			    struct strbuf *base, const char *pathname,
-			    unsigned mode,
+			    enum object_type object_type, unsigned mode,
 			    void *context)
 {
 	FILE *file = context;
-	fprintf(file, "%s%s\n", pathname, S_ISDIR(mode) ? "/" : "");
+	fprintf(file, "%s%s\n", pathname, object_type == OBJ_TREE ? "/" : "");
 	return 0;
 }
 
diff --git a/builtin/ls-files.c b/builtin/ls-files.c
index fa9b01b6cc7..f38df439410 100644
--- a/builtin/ls-files.c
+++ b/builtin/ls-files.c
@@ -446,7 +446,8 @@ static int read_one_entry_opt(struct index_state *istate,
 }
 
 static int read_one_entry(const struct object_id *oid, struct strbuf *base,
-			  const char *pathname, unsigned mode,
+			  const char *pathname,
+			  enum object_type object_type, unsigned mode,
 			  void *context)
 {
 	struct index_state *istate = context;
@@ -460,7 +461,8 @@ static int read_one_entry(const struct object_id *oid, struct strbuf *base,
  * the stage that will conflict with the entry being added.
  */
 static int read_one_entry_quick(const struct object_id *oid, struct strbuf *base,
-				const char *pathname, unsigned mode,
+				const char *pathname,
+				enum object_type object_type, unsigned mode,
 				void *context)
 {
 	struct index_state *istate = context;
diff --git a/builtin/ls-tree.c b/builtin/ls-tree.c
index aaa41e66234..c6ec3ca751e 100644
--- a/builtin/ls-tree.c
+++ b/builtin/ls-tree.c
@@ -63,14 +63,13 @@ static int show_recursive(const char *base, int baselen, const char *pathname)
 
 static int show_tree(const struct object_id *oid, struct strbuf *base,
 		     const char *pathname,
-		     unsigned mode,
+		     enum object_type object_type, unsigned mode,
 		     void *context)
 {
 	int retval = 0;
 	int baselen;
-	const char *type = blob_type;
 
-	if (S_ISGITLINK(mode)) {
+	if (object_type == OBJ_COMMIT) {
 		/*
 		 * Maybe we want to have some recursive version here?
 		 *
@@ -80,22 +79,21 @@ static int show_tree(const struct object_id *oid, struct strbuf *base,
 			retval = READ_TREE_RECURSIVE;
 		 *
 		 */
-		type = commit_type;
-	} else if (S_ISDIR(mode)) {
+	} else if (object_type == OBJ_TREE) {
 		if (show_recursive(base->buf, base->len, pathname)) {
 			retval = READ_TREE_RECURSIVE;
 			if (!(ls_options & LS_SHOW_TREES))
 				return retval;
 		}
-		type = tree_type;
 	}
 	else if (ls_options & LS_TREE_ONLY)
 		return 0;
 
 	if (!(ls_options & LS_NAME_ONLY)) {
+		const char *type = type_name(object_type);
 		if (ls_options & LS_SHOW_SIZE) {
 			char size_text[24];
-			if (!strcmp(type, blob_type)) {
+			if (object_type == OBJ_BLOB) {
 				unsigned long size;
 				if (oid_object_info(the_repository, oid, &size) == OBJ_BAD)
 					xsnprintf(size_text, sizeof(size_text),
diff --git a/merge-recursive.c b/merge-recursive.c
index aa12543ecc9..31c080538ef 100644
--- a/merge-recursive.c
+++ b/merge-recursive.c
@@ -453,7 +453,7 @@ static void unpack_trees_finish(struct merge_options *opt)
 
 static int save_files_dirs(const struct object_id *oid,
 			   struct strbuf *base, const char *path,
-			   unsigned int mode,
+			   enum object_type object_type, unsigned int mode,
 			   void *context)
 {
 	struct path_hashmap_entry *entry;
@@ -467,7 +467,9 @@ static int save_files_dirs(const struct object_id *oid,
 	hashmap_add(&opt->priv->current_file_dir_set, &entry->e);
 
 	strbuf_setlen(base, baselen);
-	return (S_ISDIR(mode) ? READ_TREE_RECURSIVE : 0);
+	if (object_type != OBJ_TREE)
+		return 0;
+	return READ_TREE_RECURSIVE;
 }
 
 static void get_files_dirs(struct merge_options *opt, struct tree *tree)
diff --git a/tree.c b/tree.c
index fb4985f22ca..e4402fad69b 100644
--- a/tree.c
+++ b/tree.c
@@ -28,6 +28,8 @@ static int read_tree_1(struct repository *r,
 	init_tree_desc(&desc, tree->buffer, tree->size);
 
 	while (tree_entry(&desc, &entry)) {
+		struct commit *commit;
+
 		if (retval != all_entries_interesting) {
 			retval = tree_entry_interesting(r->index, &entry,
 							base, 0, pathspec);
@@ -38,7 +40,7 @@ static int read_tree_1(struct repository *r,
 		}
 
 		switch (fn(&entry.oid, base,
-			   entry.path, entry.mode, context)) {
+			   entry.path, entry.object_type, entry.mode, context)) {
 		case 0:
 			continue;
 		case READ_TREE_RECURSIVE:
@@ -47,11 +49,11 @@ static int read_tree_1(struct repository *r,
 			return -1;
 		}
 
-		if (S_ISDIR(entry.mode))
+		switch (entry.object_type) {
+		case OBJ_TREE:
 			oidcpy(&oid, &entry.oid);
-		else if (S_ISGITLINK(entry.mode)) {
-			struct commit *commit;
-
+			break;
+		case OBJ_COMMIT:
 			commit = lookup_commit(r, &entry.oid);
 			if (!commit)
 				die("Commit %s in submodule path %s%s not found",
@@ -64,9 +66,12 @@ static int read_tree_1(struct repository *r,
 				    base->buf, entry.path);
 
 			oidcpy(&oid, get_commit_tree_oid(commit));
-		}
-		else
+			break;
+		case OBJ_BLOB:
 			continue;
+		default:
+			BUG("unreachable");
+		}
 
 		len = tree_entry_len(&entry);
 		strbuf_add(base, entry.path, len);
diff --git a/tree.h b/tree.h
index a7030e52679..eba51417d26 100644
--- a/tree.h
+++ b/tree.h
@@ -33,7 +33,7 @@ int cmp_cache_name_compare(const void *a_, const void *b_);
 #define READ_TREE_RECURSIVE 1
 typedef int (*read_tree_fn_t)(const struct object_id *, struct strbuf *,
 			      const char *,
-			      unsigned int,
+			      enum object_type, unsigned int,
 			      void *);
 
 int read_tree_recursive(struct repository *r,
-- 
2.31.0.rc0.126.g04f22c5b82


^ permalink raw reply	[flat|nested] 262+ messages in thread

* [PATCH 12/30] tree-walk.h users: migrate "p->mode &&" pattern
  2021-03-08  2:21   ` [PATCH v2 0/6] " Ævar Arnfjörð Bjarmason
                       ` (11 preceding siblings ...)
  2021-03-08 15:06     ` [PATCH 11/30] tree.h API: make read_tree_fn_t take an "enum object_type" Ævar Arnfjörð Bjarmason
@ 2021-03-08 15:06     ` Ævar Arnfjörð Bjarmason
  2021-03-09 17:09       ` Elijah Newren
  2021-03-08 15:06     ` [PATCH 13/30] tree-walk.h users: refactor chained "mode" if/else into switch Ævar Arnfjörð Bjarmason
                       ` (28 subsequent siblings)
  41 siblings, 1 reply; 262+ messages in thread
From: Ævar Arnfjörð Bjarmason @ 2021-03-08 15:06 UTC (permalink / raw)
  To: git
  Cc: Junio C Hamano, Elijah Newren, Kirill Smelkov,
	Nguyễn Thái Ngọc Duy,
	Ævar Arnfjörð Bjarmason

Change code that dpends on "p->mode" either being a valid mode or zero
to use a p->object_type comparison to "OBJ_NONE".

The object_type() function in cache.h will not return OBJ_NONE, but in
this these API users are implicitly relying on the memzero() that
happens in setup_traverse_info().

Since OBJ_NONE is "0" we can also rely on that being zero'd out here,
along with the rest of the structure. I think this is slightly less
clever than "mode not set", and helps to get rid of more uses of
"mode".

Signed-off-by: Ævar Arnfjörð Bjarmason <avarab@gmail.com>
---
 builtin/merge-tree.c | 9 +++++----
 merge-ort.c          | 2 +-
 unpack-trees.c       | 4 ++--
 3 files changed, 8 insertions(+), 7 deletions(-)

diff --git a/builtin/merge-tree.c b/builtin/merge-tree.c
index de8520778d2..2de34c2d485 100644
--- a/builtin/merge-tree.c
+++ b/builtin/merge-tree.c
@@ -214,7 +214,7 @@ static void unresolved_directory(const struct traverse_info *info,
 	void *buf0, *buf1, *buf2;
 
 	for (p = n; p < n + 3; p++) {
-		if (p->mode && S_ISDIR(p->mode))
+		if (p->object_type == OBJ_TREE)
 			break;
 	}
 	if (n + 3 <= p)
@@ -222,7 +222,7 @@ static void unresolved_directory(const struct traverse_info *info,
 
 	newbase = traverse_path(info, p);
 
-#define ENTRY_OID(e) (((e)->mode && S_ISDIR((e)->mode)) ? &(e)->oid : NULL)
+#define ENTRY_OID(e) (((e)->object_type == OBJ_TREE) ? &(e)->oid : NULL)
 	buf0 = fill_tree_descriptor(r, t + 0, ENTRY_OID(n + 0));
 	buf1 = fill_tree_descriptor(r, t + 1, ENTRY_OID(n + 1));
 	buf2 = fill_tree_descriptor(r, t + 2, ENTRY_OID(n + 2));
@@ -242,7 +242,7 @@ static struct merge_list *link_entry(unsigned stage, const struct traverse_info
 	const char *path;
 	struct merge_list *link;
 
-	if (!n->mode)
+	if (n->object_type == OBJ_NONE)
 		return entry;
 	if (entry)
 		path = entry->path;
@@ -265,7 +265,8 @@ static void unresolved(const struct traverse_info *info, struct name_entry n[3])
 		 * Treat missing entries as directories so that we return
 		 * after unresolved_directory has handled this.
 		 */
-		if (!n[i].mode || S_ISDIR(n[i].mode))
+		if (n[i].object_type == OBJ_NONE ||
+		    n[i].object_type == OBJ_TREE)
 			dirmask |= (1 << i);
 	}
 
diff --git a/merge-ort.c b/merge-ort.c
index 4075d13aaab..4375027914c 100644
--- a/merge-ort.c
+++ b/merge-ort.c
@@ -668,7 +668,7 @@ static int collect_merge_info_callback(int n,
 	 * setup_path_info() for tracking.
 	 */
 	p = names;
-	while (!p->mode)
+	while (p->object_type == OBJ_NONE)
 		p++;
 	len = traverse_path_len(info, p->pathlen);
 
diff --git a/unpack-trees.c b/unpack-trees.c
index 802f7771d75..92105135522 100644
--- a/unpack-trees.c
+++ b/unpack-trees.c
@@ -859,7 +859,7 @@ static int traverse_trees_recursive(int n, unsigned long dirmask,
 	}
 
 	p = names;
-	while (!p->mode)
+	while (p->object_type == OBJ_NONE)
 		p++;
 
 	newinfo = *info;
@@ -1239,7 +1239,7 @@ static int unpack_callback(int n, unsigned long mask, unsigned long dirmask, str
 	const struct name_entry *p = names;
 
 	/* Find first entry with a real name (we could use "mask" too) */
-	while (!p->mode)
+	while (p->object_type == OBJ_NONE)
 		p++;
 
 	if (o->debug_unpack)
-- 
2.31.0.rc0.126.g04f22c5b82


^ permalink raw reply	[flat|nested] 262+ messages in thread

* [PATCH 13/30] tree-walk.h users: refactor chained "mode" if/else into switch
  2021-03-08  2:21   ` [PATCH v2 0/6] " Ævar Arnfjörð Bjarmason
                       ` (12 preceding siblings ...)
  2021-03-08 15:06     ` [PATCH 12/30] tree-walk.h users: migrate "p->mode &&" pattern Ævar Arnfjörð Bjarmason
@ 2021-03-08 15:06     ` Ævar Arnfjörð Bjarmason
  2021-03-09 17:11       ` Elijah Newren
  2021-03-08 15:06     ` [PATCH 14/30] tree-walk.h users: migrate miscellaneous "mode" to "object_type" Ævar Arnfjörð Bjarmason
                       ` (27 subsequent siblings)
  41 siblings, 1 reply; 262+ messages in thread
From: Ævar Arnfjörð Bjarmason @ 2021-03-08 15:06 UTC (permalink / raw)
  To: git
  Cc: Junio C Hamano, Elijah Newren, Kirill Smelkov,
	Nguyễn Thái Ngọc Duy,
	Ævar Arnfjörð Bjarmason

Refactor a couple of "switch" statements that previously relied on
"entry.mode" to switch on "entry.object_type" instead.

This is more obvious, and allows us to explicitly handle all the OBJ_*
cases, not just have a wildcard "else". That doesn't matter for the
behavior of this code, but for its readability and maintainability.

Signed-off-by: Ævar Arnfjörð Bjarmason <avarab@gmail.com>
---
 list-objects.c | 20 ++++++++++++++------
 walker.c       | 22 +++++++++++++---------
 2 files changed, 27 insertions(+), 15 deletions(-)

diff --git a/list-objects.c b/list-objects.c
index e19589baa04..37434ba89d3 100644
--- a/list-objects.c
+++ b/list-objects.c
@@ -111,6 +111,9 @@ static void process_tree_contents(struct traversal_context *ctx,
 	init_tree_desc(&desc, tree->buffer, tree->size);
 
 	while (tree_entry(&desc, &entry)) {
+		struct tree *t;
+		struct blob *b;
+
 		if (match != all_entries_interesting) {
 			match = tree_entry_interesting(ctx->revs->repo->index,
 						       &entry, base, 0,
@@ -121,8 +124,9 @@ static void process_tree_contents(struct traversal_context *ctx,
 				continue;
 		}
 
-		if (S_ISDIR(entry.mode)) {
-			struct tree *t = lookup_tree(ctx->revs->repo, &entry.oid);
+		switch (entry.object_type) {
+		case OBJ_TREE:
+			t = lookup_tree(ctx->revs->repo, &entry.oid);
 			if (!t) {
 				die(_("entry '%s' in tree %s has tree mode, "
 				      "but is not a tree"),
@@ -130,12 +134,13 @@ static void process_tree_contents(struct traversal_context *ctx,
 			}
 			t->object.flags |= NOT_USER_GIVEN;
 			process_tree(ctx, t, base, entry.path);
-		}
-		else if (S_ISGITLINK(entry.mode))
+			break;
+		case OBJ_COMMIT:
 			process_gitlink(ctx, entry.oid.hash,
 					base, entry.path);
-		else {
-			struct blob *b = lookup_blob(ctx->revs->repo, &entry.oid);
+			break;
+		case OBJ_BLOB:
+			b = lookup_blob(ctx->revs->repo, &entry.oid);
 			if (!b) {
 				die(_("entry '%s' in tree %s has blob mode, "
 				      "but is not a blob"),
@@ -143,6 +148,9 @@ static void process_tree_contents(struct traversal_context *ctx,
 			}
 			b->object.flags |= NOT_USER_GIVEN;
 			process_blob(ctx, b, base, entry.path);
+			break;
+		default:
+			BUG("unreachable");
 		}
 	}
 }
diff --git a/walker.c b/walker.c
index 4984bf8b3d6..7ba757244e6 100644
--- a/walker.c
+++ b/walker.c
@@ -45,21 +45,25 @@ static int process_tree(struct walker *walker, struct tree *tree)
 	init_tree_desc(&desc, tree->buffer, tree->size);
 	while (tree_entry(&desc, &entry)) {
 		struct object *obj = NULL;
+		struct tree *tree;
+		struct blob *blob;
 
-		/* submodule commits are not stored in the superproject */
-		if (S_ISGITLINK(entry.mode))
+		switch (entry.object_type) {
+		case OBJ_COMMIT:
+			/* submodule commits are not stored in the superproject */
 			continue;
-		if (S_ISDIR(entry.mode)) {
-			struct tree *tree = lookup_tree(the_repository,
-							&entry.oid);
+		case OBJ_TREE:
+			tree = lookup_tree(the_repository, &entry.oid);
 			if (tree)
 				obj = &tree->object;
-		}
-		else {
-			struct blob *blob = lookup_blob(the_repository,
-							&entry.oid);
+			break;
+		case OBJ_BLOB:
+			blob = lookup_blob(the_repository, &entry.oid);
 			if (blob)
 				obj = &blob->object;
+			break;
+		default:
+			BUG("unreachable");
 		}
 		if (!obj || process(walker, obj))
 			return -1;
-- 
2.31.0.rc0.126.g04f22c5b82


^ permalink raw reply	[flat|nested] 262+ messages in thread

* [PATCH 14/30] tree-walk.h users: migrate miscellaneous "mode" to "object_type"
  2021-03-08  2:21   ` [PATCH v2 0/6] " Ævar Arnfjörð Bjarmason
                       ` (13 preceding siblings ...)
  2021-03-08 15:06     ` [PATCH 13/30] tree-walk.h users: refactor chained "mode" if/else into switch Ævar Arnfjörð Bjarmason
@ 2021-03-08 15:06     ` Ævar Arnfjörð Bjarmason
  2021-03-08 15:06     ` [PATCH 15/30] merge-tree tests: test for the mode comparison in same_entry() Ævar Arnfjörð Bjarmason
                       ` (26 subsequent siblings)
  41 siblings, 0 replies; 262+ messages in thread
From: Ævar Arnfjörð Bjarmason @ 2021-03-08 15:06 UTC (permalink / raw)
  To: git
  Cc: Junio C Hamano, Elijah Newren, Kirill Smelkov,
	Nguyễn Thái Ngọc Duy,
	Ævar Arnfjörð Bjarmason

Refactor more users of the "entry.mode" field to use the new
"entry.object_type" field.

Signed-off-by: Ævar Arnfjörð Bjarmason <avarab@gmail.com>
---
 builtin/grep.c         | 6 +++---
 builtin/merge-tree.c   | 9 +++++----
 builtin/pack-objects.c | 4 ++--
 builtin/reflog.c       | 3 ++-
 cache-tree.c           | 2 +-
 delta-islands.c        | 2 +-
 notes.c                | 4 ++--
 unpack-trees.c         | 2 +-
 8 files changed, 17 insertions(+), 15 deletions(-)

diff --git a/builtin/grep.c b/builtin/grep.c
index 4e91a253ac3..5a317cdd2f4 100644
--- a/builtin/grep.c
+++ b/builtin/grep.c
@@ -587,10 +587,10 @@ static int grep_tree(struct grep_opt *opt, const struct pathspec *pathspec,
 
 		strbuf_add(base, entry.path, te_len);
 
-		if (S_ISREG(entry.mode)) {
+		if (entry.object_type == OBJ_BLOB) {
 			hit |= grep_oid(opt, &entry.oid, base->buf, tn_len,
 					 check_attr ? base->buf + tn_len : NULL);
-		} else if (S_ISDIR(entry.mode)) {
+		} else if (entry.object_type == OBJ_TREE) {
 			enum object_type type;
 			struct tree_desc sub;
 			void *data;
@@ -606,7 +606,7 @@ static int grep_tree(struct grep_opt *opt, const struct pathspec *pathspec,
 			hit |= grep_tree(opt, pathspec, &sub, base, tn_len,
 					 check_attr);
 			free(data);
-		} else if (recurse_submodules && S_ISGITLINK(entry.mode)) {
+		} else if (recurse_submodules && entry.object_type == OBJ_COMMIT) {
 			hit |= grep_submodule(opt, pathspec, &entry.oid,
 					      base->buf, base->buf + tn_len,
 					      1); /* ignored */
diff --git a/builtin/merge-tree.c b/builtin/merge-tree.c
index 2de34c2d485..12cb317c1ba 100644
--- a/builtin/merge-tree.c
+++ b/builtin/merge-tree.c
@@ -275,11 +275,11 @@ static void unresolved(const struct traverse_info *info, struct name_entry n[3])
 	if (dirmask == mask)
 		return;
 
-	if (n[2].mode && !S_ISDIR(n[2].mode))
+	if (n[2].object_type != OBJ_TREE)
 		entry = link_entry(3, info, n + 2, entry);
-	if (n[1].mode && !S_ISDIR(n[1].mode))
+	if (n[1].object_type != OBJ_TREE)
 		entry = link_entry(2, info, n + 1, entry);
-	if (n[0].mode && !S_ISDIR(n[0].mode))
+	if (n[0].object_type != OBJ_TREE)
 		entry = link_entry(1, info, n + 0, entry);
 
 	add_merge_entry(entry);
@@ -324,7 +324,8 @@ static int threeway_callback(int n, unsigned long mask, unsigned long dirmask, s
 	}
 
 	if (same_entry(entry+0, entry+1)) {
-		if (!is_null_oid(&entry[2].oid) && !S_ISDIR(entry[2].mode)) {
+		if (!is_null_oid(&entry[2].oid) &&
+		    entry[2].object_type != OBJ_TREE) {
 			/* We did not touch, they modified -- take theirs */
 			resolve(info, entry+1, entry+2);
 			return mask;
diff --git a/builtin/pack-objects.c b/builtin/pack-objects.c
index d3ba1d4a4a6..f92722c12d4 100644
--- a/builtin/pack-objects.c
+++ b/builtin/pack-objects.c
@@ -1524,7 +1524,7 @@ static void add_pbase_object(struct tree_desc *tree,
 	int cmp;
 
 	while (tree_entry(tree,&entry)) {
-		if (S_ISGITLINK(entry.mode))
+		if (entry.object_type == OBJ_COMMIT)
 			continue;
 		cmp = tree_entry_len(&entry) != cmplen ? 1 :
 		      memcmp(name, entry.path, cmplen);
@@ -1538,7 +1538,7 @@ static void add_pbase_object(struct tree_desc *tree,
 					 fullname, 1);
 			return;
 		}
-		if (S_ISDIR(entry.mode)) {
+		if (entry.object_type == OBJ_TREE) {
 			struct tree_desc sub;
 			struct pbase_tree_cache *tree;
 			const char *down = name+cmplen+1;
diff --git a/builtin/reflog.c b/builtin/reflog.c
index 09541d1c804..bcbca82aa90 100644
--- a/builtin/reflog.c
+++ b/builtin/reflog.c
@@ -95,7 +95,8 @@ static int tree_is_complete(const struct object_id *oid)
 	complete = 1;
 	while (tree_entry(&desc, &entry)) {
 		if (!has_object_file(&entry.oid) ||
-		    (S_ISDIR(entry.mode) && !tree_is_complete(&entry.oid))) {
+		    (entry.object_type == OBJ_TREE &&
+		     !tree_is_complete(&entry.oid))) {
 			tree->object.flags |= INCOMPLETE;
 			complete = 0;
 		}
diff --git a/cache-tree.c b/cache-tree.c
index 2fb483d3c08..fbe93dd2a5f 100644
--- a/cache-tree.c
+++ b/cache-tree.c
@@ -726,7 +726,7 @@ static void prime_cache_tree_rec(struct repository *r,
 	init_tree_desc(&desc, tree->buffer, tree->size);
 	cnt = 0;
 	while (tree_entry(&desc, &entry)) {
-		if (!S_ISDIR(entry.mode))
+		if (entry.object_type != OBJ_TREE)
 			cnt++;
 		else {
 			struct cache_tree_sub *sub;
diff --git a/delta-islands.c b/delta-islands.c
index aa98b2e5414..e7cf93acbe3 100644
--- a/delta-islands.c
+++ b/delta-islands.c
@@ -293,7 +293,7 @@ void resolve_tree_islands(struct repository *r,
 		while (tree_entry(&desc, &entry)) {
 			struct object *obj;
 
-			if (S_ISGITLINK(entry.mode))
+			if (entry.object_type == OBJ_COMMIT)
 				continue;
 
 			obj = lookup_object(r, &entry.oid);
diff --git a/notes.c b/notes.c
index 0a5b4fa1dbb..d631dc5623e 100644
--- a/notes.c
+++ b/notes.c
@@ -418,7 +418,7 @@ static void load_subtree(struct notes_tree *t, struct leaf_node *subtree,
 		if (path_len == 2 * (hashsz - prefix_len)) {
 			/* This is potentially the remainder of the SHA-1 */
 
-			if (!S_ISREG(entry.mode))
+			if (entry.object_type != OBJ_BLOB)
 				/* notes must be blobs */
 				goto handle_non_note;
 
@@ -431,7 +431,7 @@ static void load_subtree(struct notes_tree *t, struct leaf_node *subtree,
 			/* This is potentially an internal node */
 			size_t len = prefix_len;
 
-			if (!S_ISDIR(entry.mode))
+			if (entry.object_type != OBJ_TREE)
 				/* internal nodes must be trees */
 				goto handle_non_note;
 
diff --git a/unpack-trees.c b/unpack-trees.c
index 92105135522..e24302f45ba 100644
--- a/unpack-trees.c
+++ b/unpack-trees.c
@@ -1297,7 +1297,7 @@ static int unpack_callback(int n, unsigned long mask, unsigned long dirmask, str
 	if (dirmask) {
 		/* special case: "diff-index --cached" looking at a tree */
 		if (o->diff_index_cached &&
-		    n == 1 && dirmask == 1 && S_ISDIR(names->mode)) {
+		    n == 1 && dirmask == 1 && names->object_type == OBJ_TREE) {
 			int matches;
 			matches = cache_tree_matches_traversal(o->src_index->cache_tree,
 							       names, info);
-- 
2.31.0.rc0.126.g04f22c5b82


^ permalink raw reply	[flat|nested] 262+ messages in thread

* [PATCH 15/30] merge-tree tests: test for the mode comparison in same_entry()
  2021-03-08  2:21   ` [PATCH v2 0/6] " Ævar Arnfjörð Bjarmason
                       ` (14 preceding siblings ...)
  2021-03-08 15:06     ` [PATCH 14/30] tree-walk.h users: migrate miscellaneous "mode" to "object_type" Ævar Arnfjörð Bjarmason
@ 2021-03-08 15:06     ` Ævar Arnfjörð Bjarmason
  2021-03-09 17:19       ` Elijah Newren
  2021-03-08 15:06     ` [PATCH 16/30] merge-ort: correct reference to test in 62fdec17a11 Ævar Arnfjörð Bjarmason
                       ` (25 subsequent siblings)
  41 siblings, 1 reply; 262+ messages in thread
From: Ævar Arnfjörð Bjarmason @ 2021-03-08 15:06 UTC (permalink / raw)
  To: git
  Cc: Junio C Hamano, Elijah Newren, Kirill Smelkov,
	Nguyễn Thái Ngọc Duy,
	Ævar Arnfjörð Bjarmason

Add a test to stress the "a->mode == b->mode" comparison in
merge-tree.c's same_entry().

That code was initially added by Linus in 33deb63a36f (Add
"merge-tree" helper program. Maybe it's retarded, maybe it's helpful.,
2005-04-14), and then again in its current form in
492e0759bfe (Handling large files with GIT, 2006-02-14).

However, nothing was testing that we handled this case
correctly. Simply removing the mode comparison left all tests passing,
but as seen here it's important that we don't think a path with the
same content but different modes is the same_entry().

The rest of this series will touch code that's relevant to this, but
won't change its behavior. This test is just something I came up with
in testing whether the mode test in same_entry() was needed at all.

Signed-off-by: Ævar Arnfjörð Bjarmason <avarab@gmail.com>
---
 t/t4300-merge-tree.sh | 44 +++++++++++++++++++++++++++++++++++++++++++
 1 file changed, 44 insertions(+)

diff --git a/t/t4300-merge-tree.sh b/t/t4300-merge-tree.sh
index e59601e5fe9..f783d784d02 100755
--- a/t/t4300-merge-tree.sh
+++ b/t/t4300-merge-tree.sh
@@ -40,6 +40,25 @@ test_expect_success 'file add A, B (same)' '
 	test_must_be_empty actual
 '
 
+test_expect_success 'file add A, B (different mode)' '
+	git reset --hard initial &&
+	test_commit "add-a-b-same-diff-mode-A" "ONE" "AAA" &&
+	git reset --hard initial &&
+	echo AAA >ONE &&
+	test_chmod +x ONE &&
+	test_tick &&
+	git commit -m"add-a-b-same-diff-mode-B" &&
+	git tag "add-a-b-same-diff-mode-B" HEAD &&
+	git merge-tree initial add-a-b-same-diff-mode-A add-a-b-same-diff-mode-B >actual &&
+	cat >expected <<EXPECTED &&
+added in both
+  our    100644 $(git rev-parse add-a-b-same-diff-mode-A:ONE) ONE
+  their  100755 $(git rev-parse add-a-b-same-diff-mode-B:ONE) ONE
+EXPECTED
+
+	test_cmp expected actual
+'
+
 test_expect_success 'file add A, B (different)' '
 	git reset --hard initial &&
 	test_commit "add-a-b-diff-A" "ONE" "AAA" &&
@@ -61,6 +80,31 @@ EXPECTED
 	test_cmp expected actual
 '
 
+test_expect_success 'file add A, B (different and different mode)' '
+	git reset --hard initial &&
+	test_commit "add-a-b-diff-diff-mode-A" "ONE" "AAA" &&
+	git reset --hard initial &&
+	echo BBB >ONE &&
+	test_chmod +x ONE &&
+	test_tick &&
+	git commit -m"add-a-b-diff-diff-mode-B" &&
+	git tag "add-a-b-diff-diff-mode-B" &&
+	git merge-tree initial add-a-b-diff-diff-mode-A add-a-b-diff-diff-mode-B >actual &&
+	cat >expected <<EXPECTED &&
+added in both
+  our    100644 $(git rev-parse add-a-b-diff-diff-mode-A:ONE) ONE
+  their  100755 $(git rev-parse add-a-b-diff-diff-mode-B:ONE) ONE
+@@ -1 +1,5 @@
++<<<<<<< .our
+ AAA
++=======
++BBB
++>>>>>>> .their
+EXPECTED
+
+	test_cmp expected actual
+'
+
 test_expect_success 'file change A, !B' '
 	git reset --hard initial &&
 	test_commit "change-a-not-b" "initial-file" "BBB" &&
-- 
2.31.0.rc0.126.g04f22c5b82


^ permalink raw reply	[flat|nested] 262+ messages in thread

* [PATCH 16/30] merge-ort: correct reference to test in 62fdec17a11
  2021-03-08  2:21   ` [PATCH v2 0/6] " Ævar Arnfjörð Bjarmason
                       ` (15 preceding siblings ...)
  2021-03-08 15:06     ` [PATCH 15/30] merge-tree tests: test for the mode comparison in same_entry() Ævar Arnfjörð Bjarmason
@ 2021-03-08 15:06     ` Ævar Arnfjörð Bjarmason
  2021-03-09 17:22       ` Elijah Newren
  2021-03-08 15:06     ` [PATCH 17/30] fsck.c: switch on "object_type" in fsck_walk_tree() Ævar Arnfjörð Bjarmason
                       ` (24 subsequent siblings)
  41 siblings, 1 reply; 262+ messages in thread
From: Ævar Arnfjörð Bjarmason @ 2021-03-08 15:06 UTC (permalink / raw)
  To: git
  Cc: Junio C Hamano, Elijah Newren, Kirill Smelkov,
	Nguyễn Thái Ngọc Duy,
	Ævar Arnfjörð Bjarmason

Fix a comment added in 62fdec17a11 (merge-ort: flesh out
implementation of handle_content_merge(), 2021-01-01).

The test being referred to here was moved from t6036 in
919df319555 (Collect merge-related tests to t64xx, 2020-08-10).

It has also had the plural of "mode" in the name ever since being
introduced in 5d1daf30cce (t6036: add a failed conflict detection
case: regular files, different modes, 2018-06-30).

Signed-off-by: Ævar Arnfjörð Bjarmason <avarab@gmail.com>
---
 merge-ort.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/merge-ort.c b/merge-ort.c
index 4375027914c..e54be179bd5 100644
--- a/merge-ort.c
+++ b/merge-ort.c
@@ -1079,7 +1079,7 @@ static int handle_content_merge(struct merge_options *opt,
 		/*
 		 * FIXME: If opt->priv->call_depth && !clean, then we really
 		 * should not make result->mode match either a->mode or
-		 * b->mode; that causes t6036 "check conflicting mode for
+		 * b->mode; that causes t6416 "check conflicting modes for
 		 * regular file" to fail.  It would be best to use some other
 		 * mode, but we'll confuse all kinds of stuff if we use one
 		 * where S_ISREG(result->mode) isn't true, and if we use
-- 
2.31.0.rc0.126.g04f22c5b82


^ permalink raw reply	[flat|nested] 262+ messages in thread

* [PATCH 17/30] fsck.c: switch on "object_type" in fsck_walk_tree()
  2021-03-08  2:21   ` [PATCH v2 0/6] " Ævar Arnfjörð Bjarmason
                       ` (16 preceding siblings ...)
  2021-03-08 15:06     ` [PATCH 16/30] merge-ort: correct reference to test in 62fdec17a11 Ævar Arnfjörð Bjarmason
@ 2021-03-08 15:06     ` Ævar Arnfjörð Bjarmason
  2021-03-08 15:06     ` [PATCH 18/30] tree-walk.h users: use temporary variable(s) for "mode" Ævar Arnfjörð Bjarmason
                       ` (23 subsequent siblings)
  41 siblings, 0 replies; 262+ messages in thread
From: Ævar Arnfjörð Bjarmason @ 2021-03-08 15:06 UTC (permalink / raw)
  To: git
  Cc: Junio C Hamano, Elijah Newren, Kirill Smelkov,
	Nguyễn Thái Ngọc Duy,
	Ævar Arnfjörð Bjarmason

Since 7146e66f086 (tree-walk: finally switch over tree descriptors to
contain a pre-parsed entry, 2014-02-06) the "mode" is validated such
that we'll never reach the "else" clause here.

Good for us that fsck_tree() has its own FSCK_MSG_BAD_FILEMODE check
which we can use, added way back in 64071805eda (git-fsck-cache: be
stricter about "tree" objects, 2005-07-27).

Except it really doesn't due to a regression in 7146e66f086. A
follow-up commit will address that, but for now we can simply rewrite
this code like the rest of the s/entry.mode/entry.object_type/g
changes I'm making.

Signed-off-by: Ævar Arnfjörð Bjarmason <avarab@gmail.com>
---
 fsck.c | 21 +++++++++------------
 1 file changed, 9 insertions(+), 12 deletions(-)

diff --git a/fsck.c b/fsck.c
index e3030f3b358..7c74c49d329 100644
--- a/fsck.c
+++ b/fsck.c
@@ -396,28 +396,25 @@ static int fsck_walk_tree(struct tree *tree, void *data, struct fsck_options *op
 		struct object *obj;
 		int result;
 
-		if (S_ISGITLINK(entry.mode))
+		switch (entry.object_type) {
+		case OBJ_COMMIT:
 			continue;
-
-		if (S_ISDIR(entry.mode)) {
+		case OBJ_TREE:
 			obj = (struct object *)lookup_tree(the_repository, &entry.oid);
 			if (name && obj)
 				fsck_put_object_name(options, &entry.oid, "%s%s/",
 						     name, entry.path);
-			result = options->walk(obj, OBJ_TREE, data, options);
-		}
-		else if (S_ISREG(entry.mode) || S_ISLNK(entry.mode)) {
+			break;
+		case OBJ_BLOB:
 			obj = (struct object *)lookup_blob(the_repository, &entry.oid);
 			if (name && obj)
 				fsck_put_object_name(options, &entry.oid, "%s%s",
 						     name, entry.path);
-			result = options->walk(obj, OBJ_BLOB, data, options);
-		}
-		else {
-			result = error("in tree %s: entry %s has bad mode %.6o",
-				       fsck_describe_object(options, &tree->object.oid),
-				       entry.path, entry.mode);
+			break;
+		default:
+			BUG("unreachable");
 		}
+		result = options->walk(obj, entry.object_type, data, options);
 		if (result < 0)
 			return result;
 		if (!res)
-- 
2.31.0.rc0.126.g04f22c5b82


^ permalink raw reply	[flat|nested] 262+ messages in thread

* [PATCH 18/30] tree-walk.h users: use temporary variable(s) for "mode"
  2021-03-08  2:21   ` [PATCH v2 0/6] " Ævar Arnfjörð Bjarmason
                       ` (17 preceding siblings ...)
  2021-03-08 15:06     ` [PATCH 17/30] fsck.c: switch on "object_type" in fsck_walk_tree() Ævar Arnfjörð Bjarmason
@ 2021-03-08 15:06     ` Ævar Arnfjörð Bjarmason
  2021-03-08 15:06     ` [PATCH 19/30] tree-walk.h API: formatting changes for subsequent commit Ævar Arnfjörð Bjarmason
                       ` (22 subsequent siblings)
  41 siblings, 0 replies; 262+ messages in thread
From: Ævar Arnfjörð Bjarmason @ 2021-03-08 15:06 UTC (permalink / raw)
  To: git
  Cc: Junio C Hamano, Elijah Newren, Kirill Smelkov,
	Nguyễn Thái Ngọc Duy,
	Ævar Arnfjörð Bjarmason

In preparation for an eventual rename of the "mode" field, add
temporary variable(s) in those places where it's used more than once.

This will make a subsequent commits easier to read., since we're only
going to need to modify the line on which the assignment happens.

Signed-off-by: Ævar Arnfjörð Bjarmason <avarab@gmail.com>
---
 builtin/merge-tree.c | 12 +++++++++---
 match-trees.c        | 13 +++++++------
 merge-ort.c          |  5 +++--
 notes.c              |  3 ++-
 tree-diff.c          | 13 ++++++++-----
 unpack-trees.c       |  3 ++-
 6 files changed, 31 insertions(+), 18 deletions(-)

diff --git a/builtin/merge-tree.c b/builtin/merge-tree.c
index 12cb317c1ba..eec5b906561 100644
--- a/builtin/merge-tree.c
+++ b/builtin/merge-tree.c
@@ -190,14 +190,17 @@ static void resolve(const struct traverse_info *info, struct name_entry *ours, s
 {
 	struct merge_list *orig, *final;
 	const char *path;
+	unsigned int orig_mode, final_mode;
 
 	/* If it's already ours, don't bother showing it */
 	if (!ours)
 		return;
 
 	path = traverse_path(info, result);
-	orig = create_entry(2, ours->mode, &ours->oid, path);
-	final = create_entry(0, result->mode, &result->oid, path);
+	orig_mode = ours->mode;
+	orig = create_entry(2, orig_mode, &ours->oid, path);
+	final_mode = result->mode;
+	final = create_entry(0, final_mode, &result->oid, path);
 
 	final->link = orig;
 
@@ -241,6 +244,7 @@ static struct merge_list *link_entry(unsigned stage, const struct traverse_info
 {
 	const char *path;
 	struct merge_list *link;
+	unsigned int link_mode;
 
 	if (n->object_type == OBJ_NONE)
 		return entry;
@@ -248,7 +252,9 @@ static struct merge_list *link_entry(unsigned stage, const struct traverse_info
 		path = entry->path;
 	else
 		path = traverse_path(info, n);
-	link = create_entry(stage, n->mode, &n->oid, path);
+	link_mode = n->mode;
+	link = create_entry(stage, link_mode, &n->oid, path);
+
 	link->link = entry;
 	return link;
 }
diff --git a/match-trees.c b/match-trees.c
index 4d124a0fd1b..07159172b63 100644
--- a/match-trees.c
+++ b/match-trees.c
@@ -86,6 +86,8 @@ static int score_trees(const struct object_id *hash1, const struct object_id *ha
 
 	for (;;) {
 		int cmp;
+		unsigned int one_mode = one.entry.mode;
+		unsigned int two_mode = two.entry.mode;
 
 		if (one.size && two.size)
 			cmp = base_name_entries_compare(&one.entry, &two.entry);
@@ -100,22 +102,21 @@ static int score_trees(const struct object_id *hash1, const struct object_id *ha
 
 		if (cmp < 0) {
 			/* path1 does not appear in two */
-			score += score_missing(one.entry.mode);
+			score += score_missing(one_mode);
 			update_tree_entry(&one);
 		} else if (cmp > 0) {
 			/* path2 does not appear in one */
-			score += score_missing(two.entry.mode);
+			score += score_missing(two_mode);
 			update_tree_entry(&two);
 		} else {
+
 			/* path appears in both */
 			if (!oideq(&one.entry.oid, &two.entry.oid)) {
 				/* they are different */
-				score += score_differs(one.entry.mode,
-						       two.entry.mode);
+				score += score_differs(one_mode, two_mode);
 			} else {
 				/* same subtree or blob */
-				score += score_matches(one.entry.mode,
-						       two.entry.mode);
+				score += score_matches(one_mode, two_mode);
 			}
 			update_tree_entry(&one);
 			update_tree_entry(&two);
diff --git a/merge-ort.c b/merge-ort.c
index e54be179bd5..cad10436504 100644
--- a/merge-ort.c
+++ b/merge-ort.c
@@ -544,11 +544,12 @@ static void add_pair(struct merge_options *opt,
 	struct diff_filespec *one, *two;
 	struct rename_info *renames = &opt->priv->renames;
 	int names_idx = is_add ? side : 0;
+	const struct object_id *oid = &names[names_idx].oid;
+	unsigned int mode = names[names_idx].mode;
 
 	one = alloc_filespec(pathname);
 	two = alloc_filespec(pathname);
-	fill_filespec(is_add ? two : one,
-		      &names[names_idx].oid, 1, names[names_idx].mode);
+	fill_filespec(is_add ? two : one, oid, 1, mode);
 	diff_queue(&renames->pairs[side], one, two);
 }
 
diff --git a/notes.c b/notes.c
index d631dc5623e..688d03ee9cd 100644
--- a/notes.c
+++ b/notes.c
@@ -478,6 +478,7 @@ static void load_subtree(struct notes_tree *t, struct leaf_node *subtree,
 			struct strbuf non_note_path = STRBUF_INIT;
 			const char *q = oid_to_hex(&subtree->key_oid);
 			size_t i;
+			unsigned int mode = entry.mode;
 			for (i = 0; i < prefix_len; i++) {
 				strbuf_addch(&non_note_path, *q++);
 				strbuf_addch(&non_note_path, *q++);
@@ -485,7 +486,7 @@ static void load_subtree(struct notes_tree *t, struct leaf_node *subtree,
 			}
 			strbuf_add(&non_note_path, entry.path, path_len);
 			add_non_note(t, strbuf_detach(&non_note_path, NULL),
-				     entry.mode, entry.oid.hash);
+				     mode, entry.oid.hash);
 		}
 	}
 	free(buf);
diff --git a/tree-diff.c b/tree-diff.c
index f133834597c..f145ff84c68 100644
--- a/tree-diff.c
+++ b/tree-diff.c
@@ -466,17 +466,19 @@ static struct combine_diff_path *ll_diff_tree_paths(
 		tp[0].entry.mode &= ~S_IFXMIN_NEQ;
 
 		for (i = 1; i < nparent; ++i) {
+			unsigned int mode = tp[i].entry.mode;
 			cmp = tree_entry_pathcmp(&tp[i], &tp[imin]);
 			if (cmp < 0) {
 				imin = i;
-				tp[i].entry.mode &= ~S_IFXMIN_NEQ;
+				mode &= ~S_IFXMIN_NEQ;
 			}
 			else if (cmp == 0) {
-				tp[i].entry.mode &= ~S_IFXMIN_NEQ;
+				mode &= ~S_IFXMIN_NEQ;
 			}
 			else {
-				tp[i].entry.mode |= S_IFXMIN_NEQ;
+				mode |= S_IFXMIN_NEQ;
 			}
+			tp[i].entry.mode = mode;
 		}
 
 		/* fixup markings for entries before imin */
@@ -493,13 +495,14 @@ static struct combine_diff_path *ll_diff_tree_paths(
 			/* are either pi > p[imin] or diff(t,pi) != ø ? */
 			if (!opt->flags.find_copies_harder) {
 				for (i = 0; i < nparent; ++i) {
+					unsigned int mode = tp[i].entry.mode;
 					/* p[i] > p[imin] */
-					if (tp[i].entry.mode & S_IFXMIN_NEQ)
+					if (mode & S_IFXMIN_NEQ)
 						continue;
 
 					/* diff(t,pi) != ø */
 					if (!oideq(&t.entry.oid, &tp[i].entry.oid) ||
-					    (t.entry.mode != tp[i].entry.mode))
+					    (t.entry.mode != mode))
 						continue;
 
 					goto skip_emit_t_tp;
diff --git a/unpack-trees.c b/unpack-trees.c
index e24302f45ba..9471c19de72 100644
--- a/unpack-trees.c
+++ b/unpack-trees.c
@@ -1020,8 +1020,9 @@ static struct cache_entry *create_ce_entry(const struct traverse_info *info,
 		is_transient ?
 		make_empty_transient_cache_entry(len) :
 		make_empty_cache_entry(istate, len);
+	unsigned int mode = n->mode;
 
-	ce->ce_mode = create_ce_mode(n->mode);
+	ce->ce_mode = create_ce_mode(mode);
 	ce->ce_flags = create_ce_flags(stage);
 	ce->ce_namelen = len;
 	oidcpy(&ce->oid, &n->oid);
-- 
2.31.0.rc0.126.g04f22c5b82


^ permalink raw reply	[flat|nested] 262+ messages in thread

* [PATCH 19/30] tree-walk.h API: formatting changes for subsequent commit
  2021-03-08  2:21   ` [PATCH v2 0/6] " Ævar Arnfjörð Bjarmason
                       ` (18 preceding siblings ...)
  2021-03-08 15:06     ` [PATCH 18/30] tree-walk.h users: use temporary variable(s) for "mode" Ævar Arnfjörð Bjarmason
@ 2021-03-08 15:06     ` Ævar Arnfjörð Bjarmason
  2021-03-08 15:06     ` [PATCH 20/30] tree-walk.h API: rename get_tree_entry() to get_tree_entry_mode() Ævar Arnfjörð Bjarmason
                       ` (21 subsequent siblings)
  41 siblings, 0 replies; 262+ messages in thread
From: Ævar Arnfjörð Bjarmason @ 2021-03-08 15:06 UTC (permalink / raw)
  To: git
  Cc: Junio C Hamano, Elijah Newren, Kirill Smelkov,
	Nguyễn Thái Ngọc Duy,
	Ævar Arnfjörð Bjarmason

Do formatting (mainly whitespace) changes of code around the
get_tree_entry() function to make a subsequent change where we'll add
a sister function easier to read.

Signed-off-by: Ævar Arnfjörð Bjarmason <avarab@gmail.com>
---
 blame.c     |  5 +++--
 tree-walk.c |  9 ++++++---
 tree-walk.h | 12 ++++++++----
 3 files changed, 17 insertions(+), 9 deletions(-)

diff --git a/blame.c b/blame.c
index a5044fcfaa6..83babc41d08 100644
--- a/blame.c
+++ b/blame.c
@@ -102,9 +102,10 @@ static void verify_working_tree_path(struct repository *r,
 		const struct object_id *commit_oid = &parents->item->object.oid;
 		struct object_id blob_oid;
 		unsigned short mode;
+		int ret = get_tree_entry(r, commit_oid, path, &blob_oid,
+					 &mode);
 
-		if (!get_tree_entry(r, commit_oid, path, &blob_oid, &mode) &&
-		    oid_object_info(r, &blob_oid, NULL) == OBJ_BLOB)
+		if (!ret && oid_object_info(r, &blob_oid, NULL) == OBJ_BLOB)
 			return;
 	}
 
diff --git a/tree-walk.c b/tree-walk.c
index 6e9161901d8..e88187e3714 100644
--- a/tree-walk.c
+++ b/tree-walk.c
@@ -591,7 +591,8 @@ static int find_tree_entry(struct repository *r, struct tree_desc *t,
 			oidcpy(result, &oid);
 			return 0;
 		}
-		return get_tree_entry(r, &oid, name + entrylen, result, mode);
+		return get_tree_entry(r, &oid, name + entrylen, result,
+				      mode);
 	}
 	return -1;
 }
@@ -622,7 +623,8 @@ int get_tree_entry(struct repository *r,
 	} else {
 		struct tree_desc t;
 		init_tree_desc(&t, tree, size);
-		retval = find_tree_entry(r, &t, name, oid, mode);
+		retval = find_tree_entry(r, &t, name, oid,
+					 mode);
 	}
 	free(tree);
 	return retval;
@@ -748,7 +750,8 @@ enum get_oid_result get_tree_entry_follow_symlinks(struct repository *r,
 
 		/* Look up the first (or only) path component in the tree. */
 		find_result = find_tree_entry(r, &t, namebuf.buf,
-					      &current_tree_oid, mode);
+					      &current_tree_oid,
+					      mode);
 		if (find_result) {
 			goto done;
 		}
diff --git a/tree-walk.h b/tree-walk.h
index 9f3825d2773..478a659ee2b 100644
--- a/tree-walk.h
+++ b/tree-walk.h
@@ -169,10 +169,14 @@ struct traverse_info {
 
 /**
  * Find an entry in a tree given a pathname and the sha1 of a tree to
- * search. Returns 0 if the entry is found and -1 otherwise. The third
- * and fourth parameters are set to the entry's sha1 and mode respectively.
- */
-int get_tree_entry(struct repository *, const struct object_id *, const char *, struct object_id *, unsigned short *);
+ * search. Returns 0 if the entry is found and -1 otherwise.
+ *
+ * The third and fourth parameters are set to the entry's sha1 and
+ * mode respectively.
+ */
+int get_tree_entry(struct repository *, const struct object_id *, const char *,
+		   struct object_id *,
+		   unsigned short *);
 
 /**
  * Generate the full pathname of a tree entry based from the root of the
-- 
2.31.0.rc0.126.g04f22c5b82


^ permalink raw reply	[flat|nested] 262+ messages in thread

* [PATCH 20/30] tree-walk.h API: rename get_tree_entry() to get_tree_entry_mode()
  2021-03-08  2:21   ` [PATCH v2 0/6] " Ævar Arnfjörð Bjarmason
                       ` (19 preceding siblings ...)
  2021-03-08 15:06     ` [PATCH 19/30] tree-walk.h API: formatting changes for subsequent commit Ævar Arnfjörð Bjarmason
@ 2021-03-08 15:06     ` Ævar Arnfjörð Bjarmason
  2021-03-08 15:06     ` [PATCH 21/30] tree-walk.h API users: use "tmp" for mode in shift_tree_by() Ævar Arnfjörð Bjarmason
                       ` (20 subsequent siblings)
  41 siblings, 0 replies; 262+ messages in thread
From: Ævar Arnfjörð Bjarmason @ 2021-03-08 15:06 UTC (permalink / raw)
  To: git
  Cc: Junio C Hamano, Elijah Newren, Kirill Smelkov,
	Nguyễn Thái Ngọc Duy,
	Ævar Arnfjörð Bjarmason

Rename the get_tree_entry() function to get_tree_entry_mode(). This
change is only a search-replacement of the name and indentation of the
argument lists.

A subsequent commits will add get_tree_entry_type() and
get_tree_entry_all() functions. Those changes will be much easier to
read if we do this rename first.

Signed-off-by: Ævar Arnfjörð Bjarmason <avarab@gmail.com>
---
 archive.c              |  8 ++++----
 blame.c                |  6 +++---
 builtin/rm.c           |  2 +-
 builtin/update-index.c |  2 +-
 line-log.c             |  2 +-
 match-trees.c          |  6 +++---
 merge-recursive.c      | 18 +++++++++---------
 notes.c                |  2 +-
 object-name.c          |  6 +++---
 tree-walk.c            | 14 +++++++-------
 tree-walk.h            |  6 +++---
 11 files changed, 36 insertions(+), 36 deletions(-)

diff --git a/archive.c b/archive.c
index 64abe736f93..95fa759e1fb 100644
--- a/archive.c
+++ b/archive.c
@@ -482,10 +482,10 @@ static void parse_treeish_arg(const char **argv,
 		unsigned short mode;
 		int err;
 
-		err = get_tree_entry(ar_args->repo,
-				     &tree->object.oid,
-				     prefix, &tree_oid,
-				     &mode);
+		err = get_tree_entry_mode(ar_args->repo,
+					  &tree->object.oid,
+					  prefix, &tree_oid,
+					  &mode);
 		if (err || !S_ISDIR(mode))
 			die(_("current working directory is untracked"));
 
diff --git a/blame.c b/blame.c
index 83babc41d08..9e0543e13d4 100644
--- a/blame.c
+++ b/blame.c
@@ -102,8 +102,8 @@ static void verify_working_tree_path(struct repository *r,
 		const struct object_id *commit_oid = &parents->item->object.oid;
 		struct object_id blob_oid;
 		unsigned short mode;
-		int ret = get_tree_entry(r, commit_oid, path, &blob_oid,
-					 &mode);
+		int ret = get_tree_entry_mode(r, commit_oid, path, &blob_oid,
+					      &mode);
 
 		if (!ret && oid_object_info(r, &blob_oid, NULL) == OBJ_BLOB)
 			return;
@@ -1239,7 +1239,7 @@ static int fill_blob_sha1_and_mode(struct repository *r,
 {
 	if (!is_null_oid(&origin->blob_oid))
 		return 0;
-	if (get_tree_entry(r, &origin->commit->object.oid, origin->path, &origin->blob_oid, &origin->mode))
+	if (get_tree_entry_mode(r, &origin->commit->object.oid, origin->path, &origin->blob_oid, &origin->mode))
 		goto error_out;
 	if (oid_object_info(r, &origin->blob_oid, NULL) != OBJ_BLOB)
 		goto error_out;
diff --git a/builtin/rm.c b/builtin/rm.c
index 4858631e0f0..4617388b29a 100644
--- a/builtin/rm.c
+++ b/builtin/rm.c
@@ -179,7 +179,7 @@ static int check_local_mod(struct object_id *head, int index_only)
 		 * way as changed from the HEAD.
 		 */
 		if (no_head
-		     || get_tree_entry(the_repository, head, name, &oid, &mode)
+		     || get_tree_entry_mode(the_repository, head, name, &oid, &mode)
 		     || ce->ce_mode != create_ce_mode(mode)
 		     || !oideq(&ce->oid, &oid))
 			staged_changes = 1;
diff --git a/builtin/update-index.c b/builtin/update-index.c
index 79087bccea4..070510d6a88 100644
--- a/builtin/update-index.c
+++ b/builtin/update-index.c
@@ -603,7 +603,7 @@ static struct cache_entry *read_one_ent(const char *which,
 	struct object_id oid;
 	struct cache_entry *ce;
 
-	if (get_tree_entry(the_repository, ent, path, &oid, &mode)) {
+	if (get_tree_entry_mode(the_repository, ent, path, &oid, &mode)) {
 		if (which)
 			error("%s: not in %s branch.", path, which);
 		return NULL;
diff --git a/line-log.c b/line-log.c
index 75c8b1acfff..4790dda4607 100644
--- a/line-log.c
+++ b/line-log.c
@@ -503,7 +503,7 @@ static void fill_blob_sha1(struct repository *r, struct commit *commit,
 	unsigned short mode;
 	struct object_id oid;
 
-	if (get_tree_entry(r, &commit->object.oid, spec->path, &oid, &mode))
+	if (get_tree_entry_mode(r, &commit->object.oid, spec->path, &oid, &mode))
 		die("There is no path %s in the commit", spec->path);
 	fill_filespec(spec, &oid, 1, mode);
 
diff --git a/match-trees.c b/match-trees.c
index 07159172b63..ba4aabf39d1 100644
--- a/match-trees.c
+++ b/match-trees.c
@@ -293,7 +293,7 @@ void shift_tree(struct repository *r,
 		if (!*del_prefix)
 			return;
 
-		if (get_tree_entry(r, hash2, del_prefix, shifted, &mode))
+		if (get_tree_entry_mode(r, hash2, del_prefix, shifted, &mode))
 			die("cannot find path %s in tree %s",
 			    del_prefix, oid_to_hex(hash2));
 		return;
@@ -321,12 +321,12 @@ void shift_tree_by(struct repository *r,
 	unsigned candidate = 0;
 
 	/* Can hash2 be a tree at shift_prefix in tree hash1? */
-	if (!get_tree_entry(r, hash1, shift_prefix, &sub1, &mode1) &&
+	if (!get_tree_entry_mode(r, hash1, shift_prefix, &sub1, &mode1) &&
 	    S_ISDIR(mode1))
 		candidate |= 1;
 
 	/* Can hash1 be a tree at shift_prefix in tree hash2? */
-	if (!get_tree_entry(r, hash2, shift_prefix, &sub2, &mode2) &&
+	if (!get_tree_entry_mode(r, hash2, shift_prefix, &sub2, &mode2) &&
 	    S_ISDIR(mode2))
 		candidate |= 2;
 
diff --git a/merge-recursive.c b/merge-recursive.c
index 31c080538ef..0e891360e7e 100644
--- a/merge-recursive.c
+++ b/merge-recursive.c
@@ -487,7 +487,7 @@ static int get_tree_entry_if_blob(struct repository *r,
 {
 	int ret;
 
-	ret = get_tree_entry(r, tree, path, &dfs->oid, &dfs->mode);
+	ret = get_tree_entry_mode(r, tree, path, &dfs->oid, &dfs->mode);
 	if (S_ISDIR(dfs->mode)) {
 		oidcpy(&dfs->oid, &null_oid);
 		dfs->mode = 0;
@@ -1886,9 +1886,9 @@ static int tree_has_path(struct repository *r, struct tree *tree,
 	struct object_id hashy;
 	unsigned short mode_o;
 
-	return !get_tree_entry(r,
-			       &tree->object.oid, path,
-			       &hashy, &mode_o);
+	return !get_tree_entry_mode(r,
+				    &tree->object.oid, path,
+				    &hashy, &mode_o);
 }
 
 /*
@@ -2541,11 +2541,11 @@ static void apply_directory_rename_modifications(struct merge_options *opt,
 	 * the various handle_rename_*() functions update the index
 	 * explicitly rather than relying on unpack_trees() to have done it.
 	 */
-	get_tree_entry(opt->repo,
-		       &tree->object.oid,
-		       pair->two->path,
-		       &re->dst_entry->stages[stage].oid,
-		       &re->dst_entry->stages[stage].mode);
+	get_tree_entry_mode(opt->repo,
+			    &tree->object.oid,
+			    pair->two->path,
+			    &re->dst_entry->stages[stage].oid,
+			    &re->dst_entry->stages[stage].mode);
 
 	/*
 	 * Record the original change status (or 'type' of change).  If it
diff --git a/notes.c b/notes.c
index 688d03ee9cd..ef138606146 100644
--- a/notes.c
+++ b/notes.c
@@ -1021,7 +1021,7 @@ void init_notes(struct notes_tree *t, const char *notes_ref,
 		return;
 	if (flags & NOTES_INIT_WRITABLE && read_ref(notes_ref, &object_oid))
 		die("Cannot use notes ref %s", notes_ref);
-	if (get_tree_entry(the_repository, &object_oid, "", &oid, &mode))
+	if (get_tree_entry_mode(the_repository, &object_oid, "", &oid, &mode))
 		die("Failed to read notes tree referenced by %s (%s)",
 		    notes_ref, oid_to_hex(&object_oid));
 
diff --git a/object-name.c b/object-name.c
index 64202de60b1..7e3b2d6d739 100644
--- a/object-name.c
+++ b/object-name.c
@@ -1704,7 +1704,7 @@ static void diagnose_invalid_oid_path(struct repository *r,
 	if (is_missing_file_error(errno)) {
 		char *fullname = xstrfmt("%s%s", prefix, filename);
 
-		if (!get_tree_entry(r, tree_oid, fullname, &oid, &mode)) {
+		if (!get_tree_entry_mode(r, tree_oid, fullname, &oid, &mode)) {
 			die(_("path '%s' exists, but not '%s'\n"
 			    "hint: Did you mean '%.*s:%s' aka '%.*s:./%s'?"),
 			    fullname,
@@ -1903,8 +1903,8 @@ static enum get_oid_result get_oid_with_context_1(struct repository *repo,
 					filename, oid, &oc->symlink_path,
 					&oc->mode);
 			} else {
-				ret = get_tree_entry(repo, &tree_oid, filename, oid,
-						     &oc->mode);
+				ret = get_tree_entry_mode(repo, &tree_oid, filename, oid,
+							  &oc->mode);
 				if (ret && only_to_die) {
 					diagnose_invalid_oid_path(repo, prefix,
 								   filename,
diff --git a/tree-walk.c b/tree-walk.c
index e88187e3714..7819ff3e0ec 100644
--- a/tree-walk.c
+++ b/tree-walk.c
@@ -591,17 +591,17 @@ static int find_tree_entry(struct repository *r, struct tree_desc *t,
 			oidcpy(result, &oid);
 			return 0;
 		}
-		return get_tree_entry(r, &oid, name + entrylen, result,
-				      mode);
+		return get_tree_entry_mode(r, &oid, name + entrylen, result,
+					   mode);
 	}
 	return -1;
 }
 
-int get_tree_entry(struct repository *r,
-		   const struct object_id *tree_oid,
-		   const char *name,
-		   struct object_id *oid,
-		   unsigned short *mode)
+int get_tree_entry_mode(struct repository *r,
+			const struct object_id *tree_oid,
+			const char *name,
+			struct object_id *oid,
+			unsigned short *mode)
 {
 	int retval;
 	void *tree;
diff --git a/tree-walk.h b/tree-walk.h
index 478a659ee2b..eb9b9de6ccc 100644
--- a/tree-walk.h
+++ b/tree-walk.h
@@ -174,9 +174,9 @@ struct traverse_info {
  * The third and fourth parameters are set to the entry's sha1 and
  * mode respectively.
  */
-int get_tree_entry(struct repository *, const struct object_id *, const char *,
-		   struct object_id *,
-		   unsigned short *);
+int get_tree_entry_mode(struct repository *, const struct object_id *, const char *,
+			struct object_id *,
+			unsigned short *);
 
 /**
  * Generate the full pathname of a tree entry based from the root of the
-- 
2.31.0.rc0.126.g04f22c5b82


^ permalink raw reply	[flat|nested] 262+ messages in thread

* [PATCH 21/30] tree-walk.h API users: use "tmp" for mode in shift_tree_by()
  2021-03-08  2:21   ` [PATCH v2 0/6] " Ævar Arnfjörð Bjarmason
                       ` (20 preceding siblings ...)
  2021-03-08 15:06     ` [PATCH 20/30] tree-walk.h API: rename get_tree_entry() to get_tree_entry_mode() Ævar Arnfjörð Bjarmason
@ 2021-03-08 15:06     ` Ævar Arnfjörð Bjarmason
  2021-03-09 17:47       ` Elijah Newren
  2021-03-08 15:06     ` [PATCH 22/30] tree-walk.h API: Add get_tree_entry_type() Ævar Arnfjörð Bjarmason
                       ` (19 subsequent siblings)
  41 siblings, 1 reply; 262+ messages in thread
From: Ævar Arnfjörð Bjarmason @ 2021-03-08 15:06 UTC (permalink / raw)
  To: git
  Cc: Junio C Hamano, Elijah Newren, Kirill Smelkov,
	Nguyễn Thái Ngọc Duy,
	Ævar Arnfjörð Bjarmason

Refactor code added in 85e51b783c3 (Make "subtree" part more
orthogonal to the rest of merge-recursive., 2008-06-30) to make it
obvious that we don't care about the "mode" here outside of the if
statement it appears in.

That's opposed to the sub1 & sub2 variables, where we use the two
object ids later in this function.

Signed-off-by: Ævar Arnfjörð Bjarmason <avarab@gmail.com>
---
 match-trees.c | 10 +++++-----
 1 file changed, 5 insertions(+), 5 deletions(-)

diff --git a/match-trees.c b/match-trees.c
index ba4aabf39d1..4f02768c01e 100644
--- a/match-trees.c
+++ b/match-trees.c
@@ -317,17 +317,17 @@ void shift_tree_by(struct repository *r,
 		   const char *shift_prefix)
 {
 	struct object_id sub1, sub2;
-	unsigned short mode1, mode2;
+	unsigned short tmp;
 	unsigned candidate = 0;
 
 	/* Can hash2 be a tree at shift_prefix in tree hash1? */
-	if (!get_tree_entry_mode(r, hash1, shift_prefix, &sub1, &mode1) &&
-	    S_ISDIR(mode1))
+	if (!get_tree_entry_mode(r, hash1, shift_prefix, &sub1, &tmp) &&
+	    S_ISDIR(tmp))
 		candidate |= 1;
 
 	/* Can hash1 be a tree at shift_prefix in tree hash2? */
-	if (!get_tree_entry_mode(r, hash2, shift_prefix, &sub2, &mode2) &&
-	    S_ISDIR(mode2))
+	if (!get_tree_entry_mode(r, hash2, shift_prefix, &sub2, &tmp) &&
+	    S_ISDIR(tmp))
 		candidate |= 2;
 
 	if (candidate == 3) {
-- 
2.31.0.rc0.126.g04f22c5b82


^ permalink raw reply	[flat|nested] 262+ messages in thread

* [PATCH 22/30] tree-walk.h API: Add get_tree_entry_type()
  2021-03-08  2:21   ` [PATCH v2 0/6] " Ævar Arnfjörð Bjarmason
                       ` (21 preceding siblings ...)
  2021-03-08 15:06     ` [PATCH 21/30] tree-walk.h API users: use "tmp" for mode in shift_tree_by() Ævar Arnfjörð Bjarmason
@ 2021-03-08 15:06     ` Ævar Arnfjörð Bjarmason
  2021-03-09 17:56       ` Elijah Newren
  2021-03-08 15:06     ` [PATCH 23/30] tree-walk.h API: add a get_tree_entry_path() function Ævar Arnfjörð Bjarmason
                       ` (18 subsequent siblings)
  41 siblings, 1 reply; 262+ messages in thread
From: Ævar Arnfjörð Bjarmason @ 2021-03-08 15:06 UTC (permalink / raw)
  To: git
  Cc: Junio C Hamano, Elijah Newren, Kirill Smelkov,
	Nguyễn Thái Ngọc Duy,
	Ævar Arnfjörð Bjarmason

Add a get_tree_entry_type() helper function to compliment the existing
get_tree_entry(). Move those users of get_tree_entry_type() who didn't
care about the mode specifically, but just want to know whether the
tree entry is one of OBJ_{BLOB,COMMIT,TREE} over to it.

Signed-off-by: Ævar Arnfjörð Bjarmason <avarab@gmail.com>
---
 archive.c     |  8 ++++----
 blame.c       |  8 ++++----
 match-trees.c | 10 +++++-----
 tree-walk.c   | 47 ++++++++++++++++++++++++++++++++++++-----------
 tree-walk.h   | 15 +++++++++++++--
 5 files changed, 62 insertions(+), 26 deletions(-)

diff --git a/archive.c b/archive.c
index 95fa759e1fb..bc8f1c7546f 100644
--- a/archive.c
+++ b/archive.c
@@ -479,14 +479,14 @@ static void parse_treeish_arg(const char **argv,
 
 	if (prefix) {
 		struct object_id tree_oid;
-		unsigned short mode;
+		enum object_type object_type;
 		int err;
 
-		err = get_tree_entry_mode(ar_args->repo,
+		err = get_tree_entry_type(ar_args->repo,
 					  &tree->object.oid,
 					  prefix, &tree_oid,
-					  &mode);
-		if (err || !S_ISDIR(mode))
+					  &object_type);
+		if (err || object_type != OBJ_TREE)
 			die(_("current working directory is untracked"));
 
 		tree = parse_tree_indirect(&tree_oid);
diff --git a/blame.c b/blame.c
index 9e0543e13d4..4944582dc3c 100644
--- a/blame.c
+++ b/blame.c
@@ -101,11 +101,11 @@ static void verify_working_tree_path(struct repository *r,
 	for (parents = work_tree->parents; parents; parents = parents->next) {
 		const struct object_id *commit_oid = &parents->item->object.oid;
 		struct object_id blob_oid;
-		unsigned short mode;
-		int ret = get_tree_entry_mode(r, commit_oid, path, &blob_oid,
-					      &mode);
+		enum object_type object_type;
+		int ret = get_tree_entry_type(r, commit_oid, path, &blob_oid,
+					      &object_type);
 
-		if (!ret && oid_object_info(r, &blob_oid, NULL) == OBJ_BLOB)
+		if (!ret && object_type == OBJ_BLOB)
 			return;
 	}
 
diff --git a/match-trees.c b/match-trees.c
index 4f02768c01e..ce3f811ec04 100644
--- a/match-trees.c
+++ b/match-trees.c
@@ -317,17 +317,17 @@ void shift_tree_by(struct repository *r,
 		   const char *shift_prefix)
 {
 	struct object_id sub1, sub2;
-	unsigned short tmp;
+	enum object_type tmp;
 	unsigned candidate = 0;
 
 	/* Can hash2 be a tree at shift_prefix in tree hash1? */
-	if (!get_tree_entry_mode(r, hash1, shift_prefix, &sub1, &tmp) &&
-	    S_ISDIR(tmp))
+	if (!get_tree_entry_type(r, hash1, shift_prefix, &sub1, &tmp) &&
+	    tmp == OBJ_TREE)
 		candidate |= 1;
 
 	/* Can hash1 be a tree at shift_prefix in tree hash2? */
-	if (!get_tree_entry_mode(r, hash2, shift_prefix, &sub2, &tmp) &&
-	    S_ISDIR(tmp))
+	if (!get_tree_entry_type(r, hash2, shift_prefix, &sub2, &tmp) &&
+	    tmp == OBJ_TREE)
 		candidate |= 2;
 
 	if (candidate == 3) {
diff --git a/tree-walk.c b/tree-walk.c
index 7819ff3e0ec..0ad3d80593e 100644
--- a/tree-walk.c
+++ b/tree-walk.c
@@ -561,7 +561,8 @@ struct dir_state {
 
 static int find_tree_entry(struct repository *r, struct tree_desc *t,
 			   const char *name, struct object_id *result,
-			   unsigned short *mode)
+			   unsigned short *mode,
+			   enum object_type *object_type)
 {
 	int namelen = strlen(name);
 	while (t->size) {
@@ -585,23 +586,24 @@ static int find_tree_entry(struct repository *r, struct tree_desc *t,
 		}
 		if (name[entrylen] != '/')
 			continue;
-		if (!S_ISDIR(*mode))
+		if (*object_type != OBJ_TREE)
 			break;
 		if (++entrylen == namelen) {
 			oidcpy(result, &oid);
 			return 0;
 		}
-		return get_tree_entry_mode(r, &oid, name + entrylen, result,
-					   mode);
+		return get_tree_entry_all(r, &oid, name + entrylen, result,
+					  mode, object_type);
 	}
 	return -1;
 }
 
-int get_tree_entry_mode(struct repository *r,
-			const struct object_id *tree_oid,
-			const char *name,
-			struct object_id *oid,
-			unsigned short *mode)
+int get_tree_entry_all(struct repository *r,
+		       const struct object_id *tree_oid,
+		       const char *name,
+		       struct object_id *oid,
+		       unsigned short *mode,
+		       enum object_type *object_type)
 {
 	int retval;
 	void *tree;
@@ -624,12 +626,34 @@ int get_tree_entry_mode(struct repository *r,
 		struct tree_desc t;
 		init_tree_desc(&t, tree, size);
 		retval = find_tree_entry(r, &t, name, oid,
-					 mode);
+					 mode, object_type);
 	}
 	free(tree);
 	return retval;
 }
 
+int get_tree_entry_mode(struct repository *r,
+			const struct object_id *tree_oid,
+			const char *name,
+			struct object_id *oid,
+			unsigned short *mode)
+{
+	enum object_type object_type;
+	return get_tree_entry_all(r, tree_oid, name, oid,
+				  mode, &object_type);
+}
+
+int get_tree_entry_type(struct repository *r,
+			const struct object_id *tree_oid,
+			const char *name,
+			struct object_id *oid,
+			enum object_type *object_type)
+{
+	unsigned short mode;
+	return get_tree_entry_all(r, tree_oid, name, oid,
+				  &mode, object_type);
+}
+
 /*
  * This is Linux's built-in max for the number of symlinks to follow.
  * That limit, of course, does not affect git, but it's a reasonable
@@ -674,6 +698,7 @@ enum get_oid_result get_tree_entry_follow_symlinks(struct repository *r,
 		int find_result;
 		char *first_slash;
 		char *remainder = NULL;
+		enum object_type object_type;
 
 		if (!t.buffer) {
 			void *tree;
@@ -751,7 +776,7 @@ enum get_oid_result get_tree_entry_follow_symlinks(struct repository *r,
 		/* Look up the first (or only) path component in the tree. */
 		find_result = find_tree_entry(r, &t, namebuf.buf,
 					      &current_tree_oid,
-					      mode);
+					      mode, &object_type);
 		if (find_result) {
 			goto done;
 		}
diff --git a/tree-walk.h b/tree-walk.h
index eb9b9de6ccc..5db38fcb575 100644
--- a/tree-walk.h
+++ b/tree-walk.h
@@ -171,12 +171,23 @@ struct traverse_info {
  * Find an entry in a tree given a pathname and the sha1 of a tree to
  * search. Returns 0 if the entry is found and -1 otherwise.
  *
- * The third and fourth parameters are set to the entry's sha1 and
- * mode respectively.
+ * There are variants of this function depending on what fields in the
+ * "struct name_entry" you'd like. You always need to pointer to an
+ * appropriate variable to fill in (NULL won't do!):
+ *
+ * get_tree_entry_mode(): unsigned int mode
+ * get_tree_entry_type(): enum object_type
+ * get_tree_entry_all(): unsigned int mode, enum object_type
  */
 int get_tree_entry_mode(struct repository *, const struct object_id *, const char *,
 			struct object_id *,
 			unsigned short *);
+int get_tree_entry_type(struct repository *, const struct object_id *, const char *,
+			struct object_id *,
+			enum object_type *);
+int get_tree_entry_all(struct repository *, const struct object_id *, const char *,
+		       struct object_id *,
+		       unsigned short *, enum object_type *);
 
 /**
  * Generate the full pathname of a tree entry based from the root of the
-- 
2.31.0.rc0.126.g04f22c5b82


^ permalink raw reply	[flat|nested] 262+ messages in thread

* [PATCH 23/30] tree-walk.h API: add a get_tree_entry_path() function
  2021-03-08  2:21   ` [PATCH v2 0/6] " Ævar Arnfjörð Bjarmason
                       ` (22 preceding siblings ...)
  2021-03-08 15:06     ` [PATCH 22/30] tree-walk.h API: Add get_tree_entry_type() Ævar Arnfjörð Bjarmason
@ 2021-03-08 15:06     ` Ævar Arnfjörð Bjarmason
  2021-03-09 18:17       ` Elijah Newren
  2021-03-08 15:06     ` [PATCH 24/30] tree-walk.h API: document and format tree_entry_extract() Ævar Arnfjörð Bjarmason
                       ` (17 subsequent siblings)
  41 siblings, 1 reply; 262+ messages in thread
From: Ævar Arnfjörð Bjarmason @ 2021-03-08 15:06 UTC (permalink / raw)
  To: git
  Cc: Junio C Hamano, Elijah Newren, Kirill Smelkov,
	Nguyễn Thái Ngọc Duy,
	Ævar Arnfjörð Bjarmason

Add a get_tree_entry_path() variant in addition to
get_tree_entry_path_{mode,type,all}(). This is for those callers that
need neither the mode nor "enum object_type" parameters filled for
them.

There's callers here which doesn't need the "struct object_id" filled
either, and provides a throwaway variable for us.

See the following commits for the introduction of such code that's
being modified here:

 - shift_tree(): 68faf68938e (A new merge stragety 'subtree'.,
    2007-02-15) for the shift_tree()

 - tree_has_path(): 96e7ffbdc31 (merge-recursive: check for directory
   level conflicts, 2018-04-19)

 - init_notes(): fd53c9eb445 (Speed up git notes lookup, 2009-10-09)

 - diagnose_invalid_oid_path(): 009fee4774d (Detailed diagnosis when
   parsing an object name fails., 2009-12-07)

Those could potentially be refactored too, but I've got to stop at
some point, and right now I'm focusing downstream code that depends on
"mode" (or "enum object_type").

Signed-off-by: Ævar Arnfjörð Bjarmason <avarab@gmail.com>
---
 match-trees.c     |  4 +---
 merge-recursive.c |  6 ++----
 notes.c           |  3 +--
 object-name.c     |  3 +--
 tree-walk.c       | 11 +++++++++++
 tree-walk.h       |  3 +++
 6 files changed, 19 insertions(+), 11 deletions(-)

diff --git a/match-trees.c b/match-trees.c
index ce3f811ec04..60a17b92d70 100644
--- a/match-trees.c
+++ b/match-trees.c
@@ -288,12 +288,10 @@ void shift_tree(struct repository *r,
 
 	if (add_score < del_score) {
 		/* We need to pick a subtree of two */
-		unsigned short mode;
-
 		if (!*del_prefix)
 			return;
 
-		if (get_tree_entry_mode(r, hash2, del_prefix, shifted, &mode))
+		if (get_tree_entry_path(r, hash2, del_prefix, shifted))
 			die("cannot find path %s in tree %s",
 			    del_prefix, oid_to_hex(hash2));
 		return;
diff --git a/merge-recursive.c b/merge-recursive.c
index 0e891360e7e..b26d9d418f9 100644
--- a/merge-recursive.c
+++ b/merge-recursive.c
@@ -1884,11 +1884,9 @@ static int tree_has_path(struct repository *r, struct tree *tree,
 			 const char *path)
 {
 	struct object_id hashy;
-	unsigned short mode_o;
-
-	return !get_tree_entry_mode(r,
+	return !get_tree_entry_path(r,
 				    &tree->object.oid, path,
-				    &hashy, &mode_o);
+				    &hashy);
 }
 
 /*
diff --git a/notes.c b/notes.c
index ef138606146..aa46cb2b09e 100644
--- a/notes.c
+++ b/notes.c
@@ -994,7 +994,6 @@ void init_notes(struct notes_tree *t, const char *notes_ref,
 		combine_notes_fn combine_notes, int flags)
 {
 	struct object_id oid, object_oid;
-	unsigned short mode;
 	struct leaf_node root_tree;
 
 	if (!t)
@@ -1021,7 +1020,7 @@ void init_notes(struct notes_tree *t, const char *notes_ref,
 		return;
 	if (flags & NOTES_INIT_WRITABLE && read_ref(notes_ref, &object_oid))
 		die("Cannot use notes ref %s", notes_ref);
-	if (get_tree_entry_mode(the_repository, &object_oid, "", &oid, &mode))
+	if (get_tree_entry_path(the_repository, &object_oid, "", &oid))
 		die("Failed to read notes tree referenced by %s (%s)",
 		    notes_ref, oid_to_hex(&object_oid));
 
diff --git a/object-name.c b/object-name.c
index 7e3b2d6d739..9ff5f83c1ff 100644
--- a/object-name.c
+++ b/object-name.c
@@ -1693,7 +1693,6 @@ static void diagnose_invalid_oid_path(struct repository *r,
 				      int object_name_len)
 {
 	struct object_id oid;
-	unsigned short mode;
 
 	if (!prefix)
 		prefix = "";
@@ -1704,7 +1703,7 @@ static void diagnose_invalid_oid_path(struct repository *r,
 	if (is_missing_file_error(errno)) {
 		char *fullname = xstrfmt("%s%s", prefix, filename);
 
-		if (!get_tree_entry_mode(r, tree_oid, fullname, &oid, &mode)) {
+		if (!get_tree_entry_path(r, tree_oid, fullname, &oid)) {
 			die(_("path '%s' exists, but not '%s'\n"
 			    "hint: Did you mean '%.*s:%s' aka '%.*s:./%s'?"),
 			    fullname,
diff --git a/tree-walk.c b/tree-walk.c
index 0ad3d80593e..83737634770 100644
--- a/tree-walk.c
+++ b/tree-walk.c
@@ -632,6 +632,17 @@ int get_tree_entry_all(struct repository *r,
 	return retval;
 }
 
+int get_tree_entry_path(struct repository *r,
+			const struct object_id *tree_oid,
+			const char *name,
+			struct object_id *oid)
+{
+	unsigned short mode;
+	enum object_type object_type;
+	return get_tree_entry_all(r, tree_oid, name, oid,
+				  &mode, &object_type);
+}
+
 int get_tree_entry_mode(struct repository *r,
 			const struct object_id *tree_oid,
 			const char *name,
diff --git a/tree-walk.h b/tree-walk.h
index 5db38fcb575..1bfa839b275 100644
--- a/tree-walk.h
+++ b/tree-walk.h
@@ -175,10 +175,13 @@ struct traverse_info {
  * "struct name_entry" you'd like. You always need to pointer to an
  * appropriate variable to fill in (NULL won't do!):
  *
+ * get_tree_entry_path(): <no extra argument, just get the common 'path'>
  * get_tree_entry_mode(): unsigned int mode
  * get_tree_entry_type(): enum object_type
  * get_tree_entry_all(): unsigned int mode, enum object_type
  */
+int get_tree_entry_path(struct repository *, const struct object_id *, const char *,
+			struct object_id *);
 int get_tree_entry_mode(struct repository *, const struct object_id *, const char *,
 			struct object_id *,
 			unsigned short *);
-- 
2.31.0.rc0.126.g04f22c5b82


^ permalink raw reply	[flat|nested] 262+ messages in thread

* [PATCH 24/30] tree-walk.h API: document and format tree_entry_extract()
  2021-03-08  2:21   ` [PATCH v2 0/6] " Ævar Arnfjörð Bjarmason
                       ` (23 preceding siblings ...)
  2021-03-08 15:06     ` [PATCH 23/30] tree-walk.h API: add a get_tree_entry_path() function Ævar Arnfjörð Bjarmason
@ 2021-03-08 15:06     ` Ævar Arnfjörð Bjarmason
  2021-03-09 18:28       ` Elijah Newren
  2021-03-08 15:06     ` [PATCH 25/30] tree-entry.h API: rename tree_entry_extract() to tree_entry_extract_mode() Ævar Arnfjörð Bjarmason
                       ` (16 subsequent siblings)
  41 siblings, 1 reply; 262+ messages in thread
From: Ævar Arnfjörð Bjarmason @ 2021-03-08 15:06 UTC (permalink / raw)
  To: git
  Cc: Junio C Hamano, Elijah Newren, Kirill Smelkov,
	Nguyễn Thái Ngọc Duy,
	Ævar Arnfjörð Bjarmason

Document and format the argument list of the tree_entry_extract()
function in preparation for adding a sister function.

Signed-off-by: Ævar Arnfjörð Bjarmason <avarab@gmail.com>
---
 tree-walk.h | 14 ++++++++++----
 1 file changed, 10 insertions(+), 4 deletions(-)

diff --git a/tree-walk.h b/tree-walk.h
index 1bfa839b275..61fdcb166d2 100644
--- a/tree-walk.h
+++ b/tree-walk.h
@@ -40,11 +40,17 @@ struct tree_desc {
 
 /**
  * Decode the entry currently being visited (the one pointed to by
- * `tree_desc's` `entry` member) and return the sha1 of the entry. The
- * `pathp` and `modep` arguments are set to the entry's pathname and mode
- * respectively.
+ * `tree_desc's` `entry` member) and return the OID of the entry.
+
+ * There are variants of this function depending on what fields in the
+ * "struct name_entry" you'd like. You always need to pointer to an
+ * appropriate variable to fill in (NULL won't do!):
+ *
+ * tree_entry_extract_mode(): const char *path, unsigned int mode
  */
-static inline const struct object_id *tree_entry_extract(struct tree_desc *desc, const char **pathp, unsigned short *modep)
+static inline const struct object_id *tree_entry_extract(struct tree_desc *desc,
+							 const char **pathp,
+							 unsigned short *modep)
 {
 	*pathp = desc->entry.path;
 	*modep = desc->entry.mode;
-- 
2.31.0.rc0.126.g04f22c5b82


^ permalink raw reply	[flat|nested] 262+ messages in thread

* [PATCH 25/30] tree-entry.h API: rename tree_entry_extract() to tree_entry_extract_mode()
  2021-03-08  2:21   ` [PATCH v2 0/6] " Ævar Arnfjörð Bjarmason
                       ` (24 preceding siblings ...)
  2021-03-08 15:06     ` [PATCH 24/30] tree-walk.h API: document and format tree_entry_extract() Ævar Arnfjörð Bjarmason
@ 2021-03-08 15:06     ` Ævar Arnfjörð Bjarmason
  2021-03-08 15:06     ` [PATCH 26/30] tree-walk.h API: add a tree_entry_extract_all() function Ævar Arnfjörð Bjarmason
                       ` (15 subsequent siblings)
  41 siblings, 0 replies; 262+ messages in thread
From: Ævar Arnfjörð Bjarmason @ 2021-03-08 15:06 UTC (permalink / raw)
  To: git
  Cc: Junio C Hamano, Elijah Newren, Kirill Smelkov,
	Nguyễn Thái Ngọc Duy,
	Ævar Arnfjörð Bjarmason

As with the recent split of the get_tree_entry() function, rename the
tree_entry_extract() function to *_mode() in preparation for adding
other variants of it.

Signed-off-by: Ævar Arnfjörð Bjarmason <avarab@gmail.com>
---
 fsck.c        | 2 +-
 match-trees.c | 4 ++--
 tree-diff.c   | 4 ++--
 tree-walk.c   | 2 +-
 tree-walk.h   | 6 +++---
 5 files changed, 9 insertions(+), 9 deletions(-)

diff --git a/fsck.c b/fsck.c
index 7c74c49d329..11678ba5826 100644
--- a/fsck.c
+++ b/fsck.c
@@ -670,7 +670,7 @@ static int fsck_tree(const struct object_id *oid,
 		const char *name, *backslash;
 		const struct object_id *oid;
 
-		oid = tree_entry_extract(&desc, &name, &mode);
+		oid = tree_entry_extract_mode(&desc, &name, &mode);
 
 		has_null_sha1 |= is_null_oid(oid);
 		has_full_path |= !!strchr(name, '/');
diff --git a/match-trees.c b/match-trees.c
index 60a17b92d70..3d2c74a44ac 100644
--- a/match-trees.c
+++ b/match-trees.c
@@ -146,7 +146,7 @@ static void match_trees(const struct object_id *hash1,
 		unsigned short mode;
 		int score;
 
-		elem = tree_entry_extract(&one, &path, &mode);
+		elem = tree_entry_extract_mode(&one, &path, &mode);
 		if (!S_ISDIR(mode))
 			goto next;
 		score = score_trees(elem, hash2);
@@ -202,7 +202,7 @@ static int splice_tree(const struct object_id *oid1, const char *prefix,
 		unsigned short mode;
 		int len = tree_entry_len(&desc.entry);
 
-		tree_entry_extract(&desc, &name, &mode);
+		tree_entry_extract_mode(&desc, &name, &mode);
 		if (len == toplen &&
 		    !memcmp(name, prefix, toplen)) {
 			if (!S_ISDIR(mode))
diff --git a/tree-diff.c b/tree-diff.c
index f145ff84c68..b37348b7908 100644
--- a/tree-diff.c
+++ b/tree-diff.c
@@ -196,7 +196,7 @@ static struct combine_diff_path *emit_path(struct combine_diff_path *p,
 
 	if (t) {
 		/* path present in resulting tree */
-		oid = tree_entry_extract(t, &path, &mode);
+		oid = tree_entry_extract_mode(t, &path, &mode);
 		pathlen = tree_entry_len(&t->entry);
 		isdir = S_ISDIR(mode);
 	} else {
@@ -207,7 +207,7 @@ static struct combine_diff_path *emit_path(struct combine_diff_path *p,
 		 * 1) all modes for tp[i]=tp[imin] should be the same wrt
 		 *    S_ISDIR, thanks to base_name_compare().
 		 */
-		tree_entry_extract(&tp[imin], &path, &mode);
+		tree_entry_extract_mode(&tp[imin], &path, &mode);
 		pathlen = tree_entry_len(&tp[imin].entry);
 
 		isdir = S_ISDIR(mode);
diff --git a/tree-walk.c b/tree-walk.c
index 83737634770..e613f273767 100644
--- a/tree-walk.c
+++ b/tree-walk.c
@@ -570,7 +570,7 @@ static int find_tree_entry(struct repository *r, struct tree_desc *t,
 		struct object_id oid;
 		int entrylen, cmp;
 
-		oidcpy(&oid, tree_entry_extract(t, &entry, mode));
+		oidcpy(&oid, tree_entry_extract_mode(t, &entry, mode));
 		entrylen = tree_entry_len(&t->entry);
 		update_tree_entry(t);
 		if (entrylen > namelen)
diff --git a/tree-walk.h b/tree-walk.h
index 61fdcb166d2..892e77eda23 100644
--- a/tree-walk.h
+++ b/tree-walk.h
@@ -48,9 +48,9 @@ struct tree_desc {
  *
  * tree_entry_extract_mode(): const char *path, unsigned int mode
  */
-static inline const struct object_id *tree_entry_extract(struct tree_desc *desc,
-							 const char **pathp,
-							 unsigned short *modep)
+static inline const struct object_id *tree_entry_extract_mode(struct tree_desc *desc,
+							      const char **pathp,
+							      unsigned short *modep)
 {
 	*pathp = desc->entry.path;
 	*modep = desc->entry.mode;
-- 
2.31.0.rc0.126.g04f22c5b82


^ permalink raw reply	[flat|nested] 262+ messages in thread

* [PATCH 26/30] tree-walk.h API: add a tree_entry_extract_all() function
  2021-03-08  2:21   ` [PATCH v2 0/6] " Ævar Arnfjörð Bjarmason
                       ` (25 preceding siblings ...)
  2021-03-08 15:06     ` [PATCH 25/30] tree-entry.h API: rename tree_entry_extract() to tree_entry_extract_mode() Ævar Arnfjörð Bjarmason
@ 2021-03-08 15:06     ` Ævar Arnfjörð Bjarmason
  2021-03-09 18:30       ` Elijah Newren
  2021-03-08 15:06     ` [PATCH 27/30] tree-walk.h API: add a tree_entry_extract_type() function Ævar Arnfjörð Bjarmason
                       ` (14 subsequent siblings)
  41 siblings, 1 reply; 262+ messages in thread
From: Ævar Arnfjörð Bjarmason @ 2021-03-08 15:06 UTC (permalink / raw)
  To: git
  Cc: Junio C Hamano, Elijah Newren, Kirill Smelkov,
	Nguyễn Thái Ngọc Duy,
	Ævar Arnfjörð Bjarmason

Add a tree_entry_extract_all() sibling function to the existing
tree_entry_extract_mode().

Having the OBJ_{BLOB,TREE,COMMIT} when you have the "mode" is strictly
speaking redundant, but hopefully makes it easier to read the
code. We'll now see which parts of the code are checking the types,
v.s. those that care about the mode specifically.

Only the first use of tree_entry_extract_mode() in emit_path() is
converted here, the other branch will use a new
get_tree_entry_mode_type() introduced in a subsequent commit.

Signed-off-by: Ævar Arnfjörð Bjarmason <avarab@gmail.com>
---
 builtin/update-index.c |  6 ++++--
 tree-diff.c            |  5 +++--
 tree-walk.c            |  3 ++-
 tree-walk.h            | 12 ++++++++++++
 4 files changed, 21 insertions(+), 5 deletions(-)

diff --git a/builtin/update-index.c b/builtin/update-index.c
index 070510d6a88..b489a876392 100644
--- a/builtin/update-index.c
+++ b/builtin/update-index.c
@@ -599,16 +599,18 @@ static struct cache_entry *read_one_ent(const char *which,
 					struct object_id *ent, const char *path,
 					int namelen, int stage)
 {
+	enum object_type object_type;
 	unsigned short mode;
 	struct object_id oid;
 	struct cache_entry *ce;
 
-	if (get_tree_entry_mode(the_repository, ent, path, &oid, &mode)) {
+	if (get_tree_entry_all(the_repository, ent, path, &oid,
+			       &mode, &object_type)) {
 		if (which)
 			error("%s: not in %s branch.", path, which);
 		return NULL;
 	}
-	if (mode == S_IFDIR) {
+	if (object_type == OBJ_TREE) {
 		if (which)
 			error("%s: not a blob in %s branch.", path, which);
 		return NULL;
diff --git a/tree-diff.c b/tree-diff.c
index b37348b7908..b25095c1164 100644
--- a/tree-diff.c
+++ b/tree-diff.c
@@ -195,10 +195,11 @@ static struct combine_diff_path *emit_path(struct combine_diff_path *p,
 	assert(t || tp);
 
 	if (t) {
+		enum object_type object_type;
 		/* path present in resulting tree */
-		oid = tree_entry_extract_mode(t, &path, &mode);
+		oid = tree_entry_extract_all(t, &path, &mode, &object_type);
 		pathlen = tree_entry_len(&t->entry);
-		isdir = S_ISDIR(mode);
+		isdir = object_type == OBJ_TREE;
 	} else {
 		/*
 		 * a path was removed - take path from imin parent. Also take
diff --git a/tree-walk.c b/tree-walk.c
index e613f273767..12e0ed4e250 100644
--- a/tree-walk.c
+++ b/tree-walk.c
@@ -570,7 +570,8 @@ static int find_tree_entry(struct repository *r, struct tree_desc *t,
 		struct object_id oid;
 		int entrylen, cmp;
 
-		oidcpy(&oid, tree_entry_extract_mode(t, &entry, mode));
+		oidcpy(&oid, tree_entry_extract_all(t, &entry, mode, object_type));
+
 		entrylen = tree_entry_len(&t->entry);
 		update_tree_entry(t);
 		if (entrylen > namelen)
diff --git a/tree-walk.h b/tree-walk.h
index 892e77eda23..06ad40ab2f1 100644
--- a/tree-walk.h
+++ b/tree-walk.h
@@ -47,6 +47,7 @@ struct tree_desc {
  * appropriate variable to fill in (NULL won't do!):
  *
  * tree_entry_extract_mode(): const char *path, unsigned int mode
+ * tree_entry_extract_all(): const char *path, unsigned int mode, enum object_type
  */
 static inline const struct object_id *tree_entry_extract_mode(struct tree_desc *desc,
 							      const char **pathp,
@@ -57,6 +58,17 @@ static inline const struct object_id *tree_entry_extract_mode(struct tree_desc *
 	return &desc->entry.oid;
 }
 
+static inline const struct object_id *tree_entry_extract_all(struct tree_desc *desc,
+							     const char **pathp,
+							     unsigned short *modep,
+							     enum object_type *object_typep)
+{
+	*pathp = desc->entry.path;
+	*modep = desc->entry.mode;
+	*object_typep = desc->entry.object_type;
+	return &desc->entry.oid;
+}
+
 /**
  * Calculate the length of a tree entry's pathname. This utilizes the
  * memory structure of a tree entry to avoid the overhead of using a
-- 
2.31.0.rc0.126.g04f22c5b82


^ permalink raw reply	[flat|nested] 262+ messages in thread

* [PATCH 27/30] tree-walk.h API: add a tree_entry_extract_type() function
  2021-03-08  2:21   ` [PATCH v2 0/6] " Ævar Arnfjörð Bjarmason
                       ` (26 preceding siblings ...)
  2021-03-08 15:06     ` [PATCH 26/30] tree-walk.h API: add a tree_entry_extract_all() function Ævar Arnfjörð Bjarmason
@ 2021-03-08 15:06     ` Ævar Arnfjörð Bjarmason
  2021-03-08 15:06     ` [PATCH 28/30] tree-walk.h API users: rename "struct name_entry"'s "mode" to "raw_mode" Ævar Arnfjörð Bjarmason
                       ` (13 subsequent siblings)
  41 siblings, 0 replies; 262+ messages in thread
From: Ævar Arnfjörð Bjarmason @ 2021-03-08 15:06 UTC (permalink / raw)
  To: git
  Cc: Junio C Hamano, Elijah Newren, Kirill Smelkov,
	Nguyễn Thái Ngọc Duy,
	Ævar Arnfjörð Bjarmason

Add and use a tree_entry_extract_type() function. There were callers
of tree_entry_extract() which didn't care about the mode, but just the
type in the tree entry.

In emit_path() the "mode" variable was not used after the "isdir"
assignment, as can be seen in the diff with it being set to 0.

Signed-off-by: Ævar Arnfjörð Bjarmason <avarab@gmail.com>
---
 match-trees.c | 12 ++++++------
 tree-diff.c   |  5 +++--
 tree-walk.h   | 11 +++++++++++
 3 files changed, 20 insertions(+), 8 deletions(-)

diff --git a/match-trees.c b/match-trees.c
index 3d2c74a44ac..0636f6e58e9 100644
--- a/match-trees.c
+++ b/match-trees.c
@@ -143,11 +143,11 @@ static void match_trees(const struct object_id *hash1,
 	while (one.size) {
 		const char *path;
 		const struct object_id *elem;
-		unsigned short mode;
+		enum object_type object_type;
 		int score;
 
-		elem = tree_entry_extract_mode(&one, &path, &mode);
-		if (!S_ISDIR(mode))
+		elem = tree_entry_extract_type(&one, &path, &object_type);
+		if (object_type != OBJ_TREE)
 			goto next;
 		score = score_trees(elem, hash2);
 		if (*best_score < score) {
@@ -198,14 +198,14 @@ static int splice_tree(const struct object_id *oid1, const char *prefix,
 
 	rewrite_here = NULL;
 	while (desc.size) {
+		enum object_type object_type;
 		const char *name;
-		unsigned short mode;
 		int len = tree_entry_len(&desc.entry);
 
-		tree_entry_extract_mode(&desc, &name, &mode);
+		tree_entry_extract_type(&desc, &name, &object_type);
 		if (len == toplen &&
 		    !memcmp(name, prefix, toplen)) {
-			if (!S_ISDIR(mode))
+			if (object_type != OBJ_TREE)
 				die("entry %s in tree %s is not a tree", name,
 				    oid_to_hex(oid1));
 
diff --git a/tree-diff.c b/tree-diff.c
index b25095c1164..10c92d39c42 100644
--- a/tree-diff.c
+++ b/tree-diff.c
@@ -208,10 +208,11 @@ static struct combine_diff_path *emit_path(struct combine_diff_path *p,
 		 * 1) all modes for tp[i]=tp[imin] should be the same wrt
 		 *    S_ISDIR, thanks to base_name_compare().
 		 */
-		tree_entry_extract_mode(&tp[imin], &path, &mode);
+		enum object_type object_type;
+		tree_entry_extract_type(&tp[imin], &path, &object_type);
 		pathlen = tree_entry_len(&tp[imin].entry);
 
-		isdir = S_ISDIR(mode);
+		isdir = object_type == OBJ_TREE;
 		oid = NULL;
 		mode = 0;
 	}
diff --git a/tree-walk.h b/tree-walk.h
index 06ad40ab2f1..1f69e57db4c 100644
--- a/tree-walk.h
+++ b/tree-walk.h
@@ -47,6 +47,7 @@ struct tree_desc {
  * appropriate variable to fill in (NULL won't do!):
  *
  * tree_entry_extract_mode(): const char *path, unsigned int mode
+ * tree_entry_extract_type(): const char *path, enum object_type
  * tree_entry_extract_all(): const char *path, unsigned int mode, enum object_type
  */
 static inline const struct object_id *tree_entry_extract_mode(struct tree_desc *desc,
@@ -58,6 +59,16 @@ static inline const struct object_id *tree_entry_extract_mode(struct tree_desc *
 	return &desc->entry.oid;
 }
 
+static inline const struct object_id *tree_entry_extract_type(struct tree_desc *desc,
+							      const char **pathp,
+							      enum object_type *object_typep)
+{
+	*pathp = desc->entry.path;
+	*object_typep = desc->entry.object_type;
+	return &desc->entry.oid;
+}
+
+
 static inline const struct object_id *tree_entry_extract_all(struct tree_desc *desc,
 							     const char **pathp,
 							     unsigned short *modep,
-- 
2.31.0.rc0.126.g04f22c5b82


^ permalink raw reply	[flat|nested] 262+ messages in thread

* [PATCH 28/30] tree-walk.h API users: rename "struct name_entry"'s "mode" to "raw_mode"
  2021-03-08  2:21   ` [PATCH v2 0/6] " Ævar Arnfjörð Bjarmason
                       ` (27 preceding siblings ...)
  2021-03-08 15:06     ` [PATCH 27/30] tree-walk.h API: add a tree_entry_extract_type() function Ævar Arnfjörð Bjarmason
@ 2021-03-08 15:06     ` Ævar Arnfjörð Bjarmason
  2021-03-09 18:53       ` Elijah Newren
  2021-03-08 15:06     ` [PATCH 29/30] tree.h API users: rename read_tree_fn_t's " Ævar Arnfjörð Bjarmason
                       ` (12 subsequent siblings)
  41 siblings, 1 reply; 262+ messages in thread
From: Ævar Arnfjörð Bjarmason @ 2021-03-08 15:06 UTC (permalink / raw)
  To: git
  Cc: Junio C Hamano, Elijah Newren, Kirill Smelkov,
	Nguyễn Thái Ngọc Duy,
	Ævar Arnfjörð Bjarmason

Now that most of the users of the "mode" variable have been moved to
use "object_type" instead let's rename it to "raw_mode" in preparation
for a revert of 7146e66f086 (tree-walk: finally switch over tree
descriptors to contain a pre-parsed entry, 2014-02-06).

This will allow API users who care about the actual mode bits in tree
objects to get access to them, such as fsck, the merge algorithm etc.

But most users will not want to have such potentially un-sanitized, so
let's indicate that by giving the variable a more scary name.

I am not renaming the variables being assigned to, i.e. it's now going
to be "int mode = entry.raw_mode", not "int raw_mode = [...]". This is
because we're going to be getting a sanitized "mode" via
"canon_mode()" in many of these functions soon, so renaming the local
variable back and forth will result in needless churn.

Signed-off-by: Ævar Arnfjörð Bjarmason <avarab@gmail.com>
---
 builtin/merge-tree.c |  8 ++++----
 match-trees.c        |  4 ++--
 merge-ort.c          | 12 ++++++------
 notes.c              |  2 +-
 tree-diff.c          | 22 +++++++++++-----------
 tree-walk.c          |  2 +-
 tree-walk.h          |  6 +++---
 tree.c               |  2 +-
 unpack-trees.c       |  6 +++---
 9 files changed, 32 insertions(+), 32 deletions(-)

diff --git a/builtin/merge-tree.c b/builtin/merge-tree.c
index eec5b906561..b4e736e4b72 100644
--- a/builtin/merge-tree.c
+++ b/builtin/merge-tree.c
@@ -160,7 +160,7 @@ static int same_entry(struct name_entry *a, struct name_entry *b)
 	return	!is_null_oid(&a->oid) &&
 		!is_null_oid(&b->oid) &&
 		oideq(&a->oid, &b->oid) &&
-		a->mode == b->mode;
+		a->raw_mode == b->raw_mode;
 }
 
 static int both_empty(struct name_entry *a, struct name_entry *b)
@@ -197,9 +197,9 @@ static void resolve(const struct traverse_info *info, struct name_entry *ours, s
 		return;
 
 	path = traverse_path(info, result);
-	orig_mode = ours->mode;
+	orig_mode = ours->raw_mode;
 	orig = create_entry(2, orig_mode, &ours->oid, path);
-	final_mode = result->mode;
+	final_mode = result->raw_mode;
 	final = create_entry(0, final_mode, &result->oid, path);
 
 	final->link = orig;
@@ -252,7 +252,7 @@ static struct merge_list *link_entry(unsigned stage, const struct traverse_info
 		path = entry->path;
 	else
 		path = traverse_path(info, n);
-	link_mode = n->mode;
+	link_mode = n->raw_mode;
 	link = create_entry(stage, link_mode, &n->oid, path);
 
 	link->link = entry;
diff --git a/match-trees.c b/match-trees.c
index 0636f6e58e9..d45c76ffa79 100644
--- a/match-trees.c
+++ b/match-trees.c
@@ -86,8 +86,8 @@ static int score_trees(const struct object_id *hash1, const struct object_id *ha
 
 	for (;;) {
 		int cmp;
-		unsigned int one_mode = one.entry.mode;
-		unsigned int two_mode = two.entry.mode;
+		unsigned int one_mode = one.entry.raw_mode;
+		unsigned int two_mode = two.entry.raw_mode;
 
 		if (one.size && two.size)
 			cmp = base_name_entries_compare(&one.entry, &two.entry);
diff --git a/merge-ort.c b/merge-ort.c
index cad10436504..ea20bbe2af3 100644
--- a/merge-ort.c
+++ b/merge-ort.c
@@ -502,7 +502,7 @@ static void setup_path_info(struct merge_options *opt,
 	mi->basename_offset = current_dir_name_len;
 	mi->clean = !!resolved;
 	if (resolved) {
-		mi->result.mode = merged_version->mode;
+		mi->result.mode = merged_version->raw_mode;
 		oidcpy(&mi->result.oid, &merged_version->oid);
 		mi->is_null = !!is_null;
 	} else {
@@ -512,7 +512,7 @@ static void setup_path_info(struct merge_options *opt,
 		ASSIGN_AND_VERIFY_CI(ci, mi);
 		for (i = MERGE_BASE; i <= MERGE_SIDE2; i++) {
 			ci->pathnames[i] = fullpath;
-			ci->stages[i].mode = names[i].mode;
+			ci->stages[i].mode = names[i].raw_mode;
 			oidcpy(&ci->stages[i].oid, &names[i].oid);
 		}
 		ci->filemask = filemask;
@@ -545,7 +545,7 @@ static void add_pair(struct merge_options *opt,
 	struct rename_info *renames = &opt->priv->renames;
 	int names_idx = is_add ? side : 0;
 	const struct object_id *oid = &names[names_idx].oid;
-	unsigned int mode = names[names_idx].mode;
+	unsigned int mode = names[names_idx].raw_mode;
 
 	one = alloc_filespec(pathname);
 	two = alloc_filespec(pathname);
@@ -616,13 +616,13 @@ static int collect_merge_info_callback(int n,
 	unsigned side1_null = !(mask & 2);
 	unsigned side2_null = !(mask & 4);
 	unsigned side1_matches_mbase = (!side1_null && !mbase_null &&
-					names[0].mode == names[1].mode &&
+					names[0].raw_mode == names[1].raw_mode &&
 					oideq(&names[0].oid, &names[1].oid));
 	unsigned side2_matches_mbase = (!side2_null && !mbase_null &&
-					names[0].mode == names[2].mode &&
+					names[0].raw_mode == names[2].raw_mode &&
 					oideq(&names[0].oid, &names[2].oid));
 	unsigned sides_match = (!side1_null && !side2_null &&
-				names[1].mode == names[2].mode &&
+				names[1].raw_mode == names[2].raw_mode &&
 				oideq(&names[1].oid, &names[2].oid));
 
 	/*
diff --git a/notes.c b/notes.c
index aa46cb2b09e..2817325651a 100644
--- a/notes.c
+++ b/notes.c
@@ -478,7 +478,7 @@ static void load_subtree(struct notes_tree *t, struct leaf_node *subtree,
 			struct strbuf non_note_path = STRBUF_INIT;
 			const char *q = oid_to_hex(&subtree->key_oid);
 			size_t i;
-			unsigned int mode = entry.mode;
+			unsigned int mode = entry.raw_mode;
 			for (i = 0; i < prefix_len; i++) {
 				strbuf_addch(&non_note_path, *q++);
 				strbuf_addch(&non_note_path, *q++);
diff --git a/tree-diff.c b/tree-diff.c
index 10c92d39c42..df8301d806a 100644
--- a/tree-diff.c
+++ b/tree-diff.c
@@ -232,7 +232,7 @@ static struct combine_diff_path *emit_path(struct combine_diff_path *p,
 			 * tp[i] is valid, if present and if tp[i]==tp[imin] -
 			 * otherwise, we should ignore it.
 			 */
-			int tpi_valid = tp && !(tp[i].entry.mode & S_IFXMIN_NEQ);
+			int tpi_valid = tp && !(tp[i].entry.raw_mode & S_IFXMIN_NEQ);
 
 			const struct object_id *oid_i;
 			unsigned mode_i;
@@ -245,7 +245,7 @@ static struct combine_diff_path *emit_path(struct combine_diff_path *p,
 
 			if (tpi_valid) {
 				oid_i = &tp[i].entry.oid;
-				mode_i = tp[i].entry.mode;
+				mode_i = tp[i].entry.raw_mode;
 			}
 			else {
 				oid_i = &null_oid;
@@ -283,7 +283,7 @@ static struct combine_diff_path *emit_path(struct combine_diff_path *p,
 		FAST_ARRAY_ALLOC(parents_oid, nparent);
 		for (i = 0; i < nparent; ++i) {
 			/* same rule as in emitthis */
-			int tpi_valid = tp && !(tp[i].entry.mode & S_IFXMIN_NEQ);
+			int tpi_valid = tp && !(tp[i].entry.raw_mode & S_IFXMIN_NEQ);
 
 			parents_oid[i] = tpi_valid ? &tp[i].entry.oid : NULL;
 		}
@@ -404,7 +404,7 @@ static inline void update_tp_entries(struct tree_desc *tp, int nparent)
 {
 	int i;
 	for (i = 0; i < nparent; ++i)
-		if (!(tp[i].entry.mode & S_IFXMIN_NEQ))
+		if (!(tp[i].entry.raw_mode & S_IFXMIN_NEQ))
 			update_tree_entry(&tp[i]);
 }
 
@@ -465,10 +465,10 @@ static struct combine_diff_path *ll_diff_tree_paths(
 		 * mark entries whether they =p[imin] along the way
 		 */
 		imin = 0;
-		tp[0].entry.mode &= ~S_IFXMIN_NEQ;
+		tp[0].entry.raw_mode &= ~S_IFXMIN_NEQ;
 
 		for (i = 1; i < nparent; ++i) {
-			unsigned int mode = tp[i].entry.mode;
+			unsigned int mode = tp[i].entry.raw_mode;
 			cmp = tree_entry_pathcmp(&tp[i], &tp[imin]);
 			if (cmp < 0) {
 				imin = i;
@@ -480,12 +480,12 @@ static struct combine_diff_path *ll_diff_tree_paths(
 			else {
 				mode |= S_IFXMIN_NEQ;
 			}
-			tp[i].entry.mode = mode;
+			tp[i].entry.raw_mode = mode;
 		}
 
 		/* fixup markings for entries before imin */
 		for (i = 0; i < imin; ++i)
-			tp[i].entry.mode |= S_IFXMIN_NEQ;	/* pi > p[imin] */
+			tp[i].entry.raw_mode |= S_IFXMIN_NEQ;	/* pi > p[imin] */
 
 
 
@@ -497,14 +497,14 @@ static struct combine_diff_path *ll_diff_tree_paths(
 			/* are either pi > p[imin] or diff(t,pi) != ø ? */
 			if (!opt->flags.find_copies_harder) {
 				for (i = 0; i < nparent; ++i) {
-					unsigned int mode = tp[i].entry.mode;
+					unsigned int mode = tp[i].entry.raw_mode;
 					/* p[i] > p[imin] */
 					if (mode & S_IFXMIN_NEQ)
 						continue;
 
 					/* diff(t,pi) != ø */
 					if (!oideq(&t.entry.oid, &tp[i].entry.oid) ||
-					    (t.entry.mode != mode))
+					    (t.entry.raw_mode != mode))
 						continue;
 
 					goto skip_emit_t_tp;
@@ -536,7 +536,7 @@ static struct combine_diff_path *ll_diff_tree_paths(
 			/* ∀i pi=p[imin] -> D += "-p[imin]" */
 			if (!opt->flags.find_copies_harder) {
 				for (i = 0; i < nparent; ++i)
-					if (tp[i].entry.mode & S_IFXMIN_NEQ)
+					if (tp[i].entry.raw_mode & S_IFXMIN_NEQ)
 						goto skip_emit_tp;
 			}
 
diff --git a/tree-walk.c b/tree-walk.c
index 12e0ed4e250..099a9b3bd77 100644
--- a/tree-walk.c
+++ b/tree-walk.c
@@ -48,7 +48,7 @@ static int decode_tree_entry(struct tree_desc *desc, const char *buf, unsigned l
 	/* Initialize the descriptor entry */
 	desc->entry.path = path;
 	mode = canon_mode(mode);
-	desc->entry.mode = mode;
+	desc->entry.raw_mode = mode;
 	desc->entry.object_type = object_type(mode);
 	desc->entry.pathlen = len - 1;
 	hashcpy(desc->entry.oid.hash, (const unsigned char *)path + len);
diff --git a/tree-walk.h b/tree-walk.h
index 1f69e57db4c..885ced74258 100644
--- a/tree-walk.h
+++ b/tree-walk.h
@@ -16,7 +16,7 @@ struct name_entry {
 	struct object_id oid;
 	const char *path;
 	int pathlen;
-	unsigned int mode;
+	unsigned int raw_mode;
 	/* simple 'mode': Only OBJ_{BLOB,TREE,COMMIT} */
 	enum object_type object_type;
 };
@@ -55,7 +55,7 @@ static inline const struct object_id *tree_entry_extract_mode(struct tree_desc *
 							      unsigned short *modep)
 {
 	*pathp = desc->entry.path;
-	*modep = desc->entry.mode;
+	*modep = desc->entry.raw_mode;
 	return &desc->entry.oid;
 }
 
@@ -75,7 +75,7 @@ static inline const struct object_id *tree_entry_extract_all(struct tree_desc *d
 							     enum object_type *object_typep)
 {
 	*pathp = desc->entry.path;
-	*modep = desc->entry.mode;
+	*modep = desc->entry.raw_mode;
 	*object_typep = desc->entry.object_type;
 	return &desc->entry.oid;
 }
diff --git a/tree.c b/tree.c
index e4402fad69b..215d17e1295 100644
--- a/tree.c
+++ b/tree.c
@@ -40,7 +40,7 @@ static int read_tree_1(struct repository *r,
 		}
 
 		switch (fn(&entry.oid, base,
-			   entry.path, entry.object_type, entry.mode, context)) {
+			   entry.path, entry.object_type, entry.raw_mode, context)) {
 		case 0:
 			continue;
 		case READ_TREE_RECURSIVE:
diff --git a/unpack-trees.c b/unpack-trees.c
index 9471c19de72..dcdf8130745 100644
--- a/unpack-trees.c
+++ b/unpack-trees.c
@@ -867,7 +867,7 @@ static int traverse_trees_recursive(int n, unsigned long dirmask,
 	newinfo.pathspec = info->pathspec;
 	newinfo.name = p->path;
 	newinfo.namelen = p->pathlen;
-	newinfo.mode = p->mode;
+	newinfo.mode = p->raw_mode;
 	newinfo.pathlen = st_add3(newinfo.pathlen, tree_entry_len(p), 1);
 	newinfo.df_conflicts |= df_conflicts;
 
@@ -1020,7 +1020,7 @@ static struct cache_entry *create_ce_entry(const struct traverse_info *info,
 		is_transient ?
 		make_empty_transient_cache_entry(len) :
 		make_empty_cache_entry(istate, len);
-	unsigned int mode = n->mode;
+	unsigned int mode = n->raw_mode;
 
 	ce->ce_mode = create_ce_mode(mode);
 	ce->ce_flags = create_ce_flags(stage);
@@ -1209,7 +1209,7 @@ static void debug_path(struct traverse_info *info)
 static void debug_name_entry(int i, struct name_entry *n)
 {
 	printf("ent#%d %06o %s\n", i,
-	       n->path ? n->mode : 0,
+	       n->path ? n->raw_mode : 0,
 	       n->path ? n->path : "(missing)");
 }
 
-- 
2.31.0.rc0.126.g04f22c5b82


^ permalink raw reply	[flat|nested] 262+ messages in thread

* [PATCH 29/30] tree.h API users: rename read_tree_fn_t's "mode" to "raw_mode"
  2021-03-08  2:21   ` [PATCH v2 0/6] " Ævar Arnfjörð Bjarmason
                       ` (28 preceding siblings ...)
  2021-03-08 15:06     ` [PATCH 28/30] tree-walk.h API users: rename "struct name_entry"'s "mode" to "raw_mode" Ævar Arnfjörð Bjarmason
@ 2021-03-08 15:06     ` Ævar Arnfjörð Bjarmason
  2021-03-09 19:02       ` Elijah Newren
  2021-03-08 15:06     ` [PATCH 30/30] tree-walk.h API: move canon_mode() back out of decode_tree_entry() Ævar Arnfjörð Bjarmason
                       ` (11 subsequent siblings)
  41 siblings, 1 reply; 262+ messages in thread
From: Ævar Arnfjörð Bjarmason @ 2021-03-08 15:06 UTC (permalink / raw)
  To: git
  Cc: Junio C Hamano, Elijah Newren, Kirill Smelkov,
	Nguyễn Thái Ngọc Duy,
	Ævar Arnfjörð Bjarmason

Rename the "mode" variable passed to read_tree_fn_t callbacks to
"raw_mode". This variable comes to us from the tree-walk.h API. By
renaming this variable we can easily see where its downstream users
are in a subsequent commit where we'll sprinkle some canon_mode()
here.

Signed-off-by: Ævar Arnfjörð Bjarmason <avarab@gmail.com>
---
 archive.c          |  5 +++--
 builtin/log.c      |  2 +-
 builtin/ls-files.c | 11 ++++++-----
 builtin/ls-tree.c  |  6 +++---
 merge-recursive.c  |  2 +-
 5 files changed, 14 insertions(+), 12 deletions(-)

diff --git a/archive.c b/archive.c
index bc8f1c7546f..5b85aae8106 100644
--- a/archive.c
+++ b/archive.c
@@ -232,10 +232,11 @@ static int write_directory(struct archiver_context *c)
 
 static int queue_or_write_archive_entry(const struct object_id *oid,
 					struct strbuf *base, const char *filename,
-					enum object_type object_type, unsigned mode,
+					enum object_type object_type, unsigned raw_mode,
 					void *context)
 {
 	struct archiver_context *c = context;
+	unsigned mode = raw_mode;
 
 	while (c->bottom &&
 	       !(base->len >= c->bottom->len &&
@@ -382,7 +383,7 @@ struct path_exists_context {
 
 static int reject_entry(const struct object_id *oid, struct strbuf *base,
 			const char *filename,
-			enum object_type object_type, unsigned mode,
+			enum object_type object_type, unsigned raw_mode,
 			void *context)
 {
 	int ret = -1;
diff --git a/builtin/log.c b/builtin/log.c
index 19a916221d5..c3ef1b3e22d 100644
--- a/builtin/log.c
+++ b/builtin/log.c
@@ -599,7 +599,7 @@ static int show_tag_object(const struct object_id *oid, struct rev_info *rev)
 
 static int show_tree_object(const struct object_id *oid,
 			    struct strbuf *base, const char *pathname,
-			    enum object_type object_type, unsigned mode,
+			    enum object_type object_type, unsigned raw_mode,
 			    void *context)
 {
 	FILE *file = context;
diff --git a/builtin/ls-files.c b/builtin/ls-files.c
index f38df439410..391e6a9f141 100644
--- a/builtin/ls-files.c
+++ b/builtin/ls-files.c
@@ -425,10 +425,11 @@ static int read_one_entry_opt(struct index_state *istate,
 			      const struct object_id *oid,
 			      struct strbuf *base,
 			      const char *pathname,
-			      unsigned mode, int opt)
+			      unsigned raw_mode, int opt)
 {
 	int len;
 	struct cache_entry *ce;
+	unsigned mode = raw_mode;
 
 	if (S_ISDIR(mode))
 		return READ_TREE_RECURSIVE;
@@ -447,12 +448,12 @@ static int read_one_entry_opt(struct index_state *istate,
 
 static int read_one_entry(const struct object_id *oid, struct strbuf *base,
 			  const char *pathname,
-			  enum object_type object_type, unsigned mode,
+			  enum object_type object_type, unsigned raw_mode,
 			  void *context)
 {
 	struct index_state *istate = context;
 	return read_one_entry_opt(istate, oid, base, pathname,
-				  mode,
+				  raw_mode,
 				  ADD_CACHE_OK_TO_ADD|ADD_CACHE_SKIP_DFCHECK);
 }
 
@@ -462,12 +463,12 @@ static int read_one_entry(const struct object_id *oid, struct strbuf *base,
  */
 static int read_one_entry_quick(const struct object_id *oid, struct strbuf *base,
 				const char *pathname,
-				enum object_type object_type, unsigned mode,
+				enum object_type object_type, unsigned raw_mode,
 				void *context)
 {
 	struct index_state *istate = context;
 	return read_one_entry_opt(istate, oid, base, pathname,
-				  mode,
+				  raw_mode,
 				  ADD_CACHE_JUST_APPEND);
 }
 
diff --git a/builtin/ls-tree.c b/builtin/ls-tree.c
index c6ec3ca751e..3f84603d391 100644
--- a/builtin/ls-tree.c
+++ b/builtin/ls-tree.c
@@ -63,7 +63,7 @@ static int show_recursive(const char *base, int baselen, const char *pathname)
 
 static int show_tree(const struct object_id *oid, struct strbuf *base,
 		     const char *pathname,
-		     enum object_type object_type, unsigned mode,
+		     enum object_type object_type, unsigned raw_mode,
 		     void *context)
 {
 	int retval = 0;
@@ -103,11 +103,11 @@ static int show_tree(const struct object_id *oid, struct strbuf *base,
 						  "%"PRIuMAX, (uintmax_t)size);
 			} else
 				xsnprintf(size_text, sizeof(size_text), "-");
-			printf("%06o %s %s %7s\t", mode, type,
+			printf("%06o %s %s %7s\t", raw_mode, type,
 			       find_unique_abbrev(oid, abbrev),
 			       size_text);
 		} else
-			printf("%06o %s %s\t", mode, type,
+			printf("%06o %s %s\t", raw_mode, type,
 			       find_unique_abbrev(oid, abbrev));
 	}
 	baselen = base->len;
diff --git a/merge-recursive.c b/merge-recursive.c
index b26d9d418f9..30fbe72ca06 100644
--- a/merge-recursive.c
+++ b/merge-recursive.c
@@ -453,7 +453,7 @@ static void unpack_trees_finish(struct merge_options *opt)
 
 static int save_files_dirs(const struct object_id *oid,
 			   struct strbuf *base, const char *path,
-			   enum object_type object_type, unsigned int mode,
+			   enum object_type object_type, unsigned int raw_mode,
 			   void *context)
 {
 	struct path_hashmap_entry *entry;
-- 
2.31.0.rc0.126.g04f22c5b82


^ permalink raw reply	[flat|nested] 262+ messages in thread

* [PATCH 30/30] tree-walk.h API: move canon_mode() back out of decode_tree_entry()
  2021-03-08  2:21   ` [PATCH v2 0/6] " Ævar Arnfjörð Bjarmason
                       ` (29 preceding siblings ...)
  2021-03-08 15:06     ` [PATCH 29/30] tree.h API users: rename read_tree_fn_t's " Ævar Arnfjörð Bjarmason
@ 2021-03-08 15:06     ` Ævar Arnfjörð Bjarmason
  2021-03-09 20:23       ` Elijah Newren
  2021-03-08 19:18     ` [PATCH v2 0/6] Move the read_tree() function to its only user Elijah Newren
                       ` (10 subsequent siblings)
  41 siblings, 1 reply; 262+ messages in thread
From: Ævar Arnfjörð Bjarmason @ 2021-03-08 15:06 UTC (permalink / raw)
  To: git
  Cc: Junio C Hamano, Elijah Newren, Kirill Smelkov,
	Nguyễn Thái Ngọc Duy,
	Ævar Arnfjörð Bjarmason

Move the canon_mode() call back out of decode_tree_entry(), and
instead make it the responsibility of its callers to canonicalize the
tree modes we get.

This effectively reverts 7146e66f086 (tree-walk: finally switch over
tree descriptors to contain a pre-parsed entry, 2014-02-06), with the
recent of most callers away from "mode" (now "raw_mode") towards "enum
object_id" in recent commit the motivation for that commit effectively
doesn't exist anymore.

I.e. I'm not adding the canon_mode() call back to
tree_entry_extract(), instead it's now become sane to move this
responsibility to those callers that still care about the "raw_mode".

That change was meant as a pure optimization change, but it actually
introduced a subtle bug. We were left without any low-level API to get
non-standard mode bits out of trees. Having non-standard modes isn't
the norm, and fsck should warn about it.

Except after 7146e66f086 it couldn't anymore, since the modes
fsck_tree() got would be pre-sanitized for it. I believe that fsck
issue is per-se a serious bug, the "bad mode" was a default warning,
not an error.

This change makes that fsck check work again, why aren't there any
test changes for fsck here? Because we didn't have a test for that
fsck feature in the first place, which is why the regression in
7146e66f086 snuck by us. A follow-up commit will add such a test.

It is possible that this commit is introducing some subtle regression
that I've missed.

We are now propagating the "raw_mode" outside of everything downstream
of decode_tree_entry(), which is everything we have that decodes
trees. It's our most low-level tree decoding API.

As shown here we rely parsing out a "raw" (and possibly something fsck
would complain about) mode as-is, but when we run merge, add something
new to the index, create an archive etc. we don't want to propagate
that bad mode when we create new data. We want to canon_mode() it.

I'm also pretty sure that we don't have good enough test coverage for
those scenarios. We barely have tests for these bad mode bits at
all (not even one for fsck). We definitely are not testing all
merge/index/archive etc. interactions.

Still, I think this change is worth it overall, because:

 1. We must have a way to get at these raw modes in some way, even if
    just for fsck. There's also other things that care, see e.g. the
    FIXME comment in 62fdec17a11 (merge-ort: flesh out implementation of
    handle_content_merge(), 2021-01-01)

 2. #1 is not a justification for this change, I could have e.g. just
    added the ability to pass some "want_raw" flag into
    decode_tree_entry() for use in fsck. But I think with the migration
    of most tree iteration towards "enum object_type" it's become worth
    it.

 3. Yes our test coverage sucks, but before 7146e66f086 we were also
    spreading what's now the "raw_mode" all over the place. That commit
    was first released with Git v2.0.0 in mid-2014. A while ago for sure,
    but most of this code existed in something approximating its current
    form then. This isn't new territory.

Signed-off-by: Ævar Arnfjörð Bjarmason <avarab@gmail.com>
---
 archive.c              |  2 +-
 builtin/checkout.c     |  1 +
 builtin/ls-files.c     |  2 +-
 builtin/merge-tree.c   |  6 +++---
 builtin/update-index.c |  1 +
 merge-ort.c            | 13 ++++++++++++-
 notes.c                |  1 +
 tree-walk.c            |  1 -
 unpack-trees.c         |  4 +++-
 9 files changed, 23 insertions(+), 8 deletions(-)

diff --git a/archive.c b/archive.c
index 5b85aae8106..8083f15f3ba 100644
--- a/archive.c
+++ b/archive.c
@@ -236,7 +236,7 @@ static int queue_or_write_archive_entry(const struct object_id *oid,
 					void *context)
 {
 	struct archiver_context *c = context;
-	unsigned mode = raw_mode;
+	unsigned mode = canon_mode(raw_mode);
 
 	while (c->bottom &&
 	       !(base->len >= c->bottom->len &&
diff --git a/builtin/checkout.c b/builtin/checkout.c
index d4adfdb5046..7f25b955616 100644
--- a/builtin/checkout.c
+++ b/builtin/checkout.c
@@ -132,6 +132,7 @@ static int update_some(const struct object_id *oid, struct strbuf *base,
 	memcpy(ce->name + base->len, pathname, len - base->len);
 	ce->ce_flags = create_ce_flags(0) | CE_UPDATE;
 	ce->ce_namelen = len;
+	mode = canon_mode(mode);
 	ce->ce_mode = create_ce_mode(mode);
 
 	/*
diff --git a/builtin/ls-files.c b/builtin/ls-files.c
index 391e6a9f141..926523d77a7 100644
--- a/builtin/ls-files.c
+++ b/builtin/ls-files.c
@@ -429,7 +429,7 @@ static int read_one_entry_opt(struct index_state *istate,
 {
 	int len;
 	struct cache_entry *ce;
-	unsigned mode = raw_mode;
+	unsigned mode = canon_mode(raw_mode);
 
 	if (S_ISDIR(mode))
 		return READ_TREE_RECURSIVE;
diff --git a/builtin/merge-tree.c b/builtin/merge-tree.c
index b4e736e4b72..f8733a86eb7 100644
--- a/builtin/merge-tree.c
+++ b/builtin/merge-tree.c
@@ -197,9 +197,9 @@ static void resolve(const struct traverse_info *info, struct name_entry *ours, s
 		return;
 
 	path = traverse_path(info, result);
-	orig_mode = ours->raw_mode;
+	orig_mode = canon_mode(ours->raw_mode);
 	orig = create_entry(2, orig_mode, &ours->oid, path);
-	final_mode = result->raw_mode;
+	final_mode = canon_mode(result->raw_mode);
 	final = create_entry(0, final_mode, &result->oid, path);
 
 	final->link = orig;
@@ -252,7 +252,7 @@ static struct merge_list *link_entry(unsigned stage, const struct traverse_info
 		path = entry->path;
 	else
 		path = traverse_path(info, n);
-	link_mode = n->raw_mode;
+	link_mode = canon_mode(n->raw_mode);
 	link = create_entry(stage, link_mode, &n->oid, path);
 
 	link->link = entry;
diff --git a/builtin/update-index.c b/builtin/update-index.c
index b489a876392..1996fdd97af 100644
--- a/builtin/update-index.c
+++ b/builtin/update-index.c
@@ -621,6 +621,7 @@ static struct cache_entry *read_one_ent(const char *which,
 	memcpy(ce->name, path, namelen);
 	ce->ce_flags = create_ce_flags(stage);
 	ce->ce_namelen = namelen;
+	mode = canon_mode(mode);
 	ce->ce_mode = create_ce_mode(mode);
 	return ce;
 }
diff --git a/merge-ort.c b/merge-ort.c
index ea20bbe2af3..d1e8a2823e0 100644
--- a/merge-ort.c
+++ b/merge-ort.c
@@ -502,7 +502,7 @@ static void setup_path_info(struct merge_options *opt,
 	mi->basename_offset = current_dir_name_len;
 	mi->clean = !!resolved;
 	if (resolved) {
-		mi->result.mode = merged_version->raw_mode;
+		mi->result.mode = canon_mode(merged_version->raw_mode);
 		oidcpy(&mi->result.oid, &merged_version->oid);
 		mi->is_null = !!is_null;
 	} else {
@@ -512,6 +512,16 @@ static void setup_path_info(struct merge_options *opt,
 		ASSIGN_AND_VERIFY_CI(ci, mi);
 		for (i = MERGE_BASE; i <= MERGE_SIDE2; i++) {
 			ci->pathnames[i] = fullpath;
+			/*
+			 * We must not use canon_mode() here. Will
+			 * fail on an the is_null assertion in
+			 * 6a02dd90c99 (merge-ort: add a preliminary
+			 * simple process_entries() implementation,
+			 * 2020-12-13) when combined with the tests in
+			 * "[PATCH 00/11] Complete merge-ort
+			 * implementation...almost" (see
+			 * https://lore.kernel.org/git/pull.973.git.git.1614905738.gitgitgadget@gmail.com/)
+			 */
 			ci->stages[i].mode = names[i].raw_mode;
 			oidcpy(&ci->stages[i].oid, &names[i].oid);
 		}
@@ -546,6 +556,7 @@ static void add_pair(struct merge_options *opt,
 	int names_idx = is_add ? side : 0;
 	const struct object_id *oid = &names[names_idx].oid;
 	unsigned int mode = names[names_idx].raw_mode;
+	mode = canon_mode(mode);
 
 	one = alloc_filespec(pathname);
 	two = alloc_filespec(pathname);
diff --git a/notes.c b/notes.c
index 2817325651a..78b1b38d36b 100644
--- a/notes.c
+++ b/notes.c
@@ -479,6 +479,7 @@ static void load_subtree(struct notes_tree *t, struct leaf_node *subtree,
 			const char *q = oid_to_hex(&subtree->key_oid);
 			size_t i;
 			unsigned int mode = entry.raw_mode;
+			mode = canon_mode(mode);
 			for (i = 0; i < prefix_len; i++) {
 				strbuf_addch(&non_note_path, *q++);
 				strbuf_addch(&non_note_path, *q++);
diff --git a/tree-walk.c b/tree-walk.c
index 099a9b3bd77..3175430d049 100644
--- a/tree-walk.c
+++ b/tree-walk.c
@@ -47,7 +47,6 @@ static int decode_tree_entry(struct tree_desc *desc, const char *buf, unsigned l
 
 	/* Initialize the descriptor entry */
 	desc->entry.path = path;
-	mode = canon_mode(mode);
 	desc->entry.raw_mode = mode;
 	desc->entry.object_type = object_type(mode);
 	desc->entry.pathlen = len - 1;
diff --git a/unpack-trees.c b/unpack-trees.c
index dcdf8130745..2fb346714b3 100644
--- a/unpack-trees.c
+++ b/unpack-trees.c
@@ -868,6 +868,7 @@ static int traverse_trees_recursive(int n, unsigned long dirmask,
 	newinfo.name = p->path;
 	newinfo.namelen = p->pathlen;
 	newinfo.mode = p->raw_mode;
+	newinfo.mode = canon_mode(newinfo.mode);
 	newinfo.pathlen = st_add3(newinfo.pathlen, tree_entry_len(p), 1);
 	newinfo.df_conflicts |= df_conflicts;
 
@@ -1020,7 +1021,8 @@ static struct cache_entry *create_ce_entry(const struct traverse_info *info,
 		is_transient ?
 		make_empty_transient_cache_entry(len) :
 		make_empty_cache_entry(istate, len);
-	unsigned int mode = n->raw_mode;
+	unsigned int mode = canon_mode(n->raw_mode);
+	mode = canon_mode(mode);
 
 	ce->ce_mode = create_ce_mode(mode);
 	ce->ce_flags = create_ce_flags(stage);
-- 
2.31.0.rc0.126.g04f22c5b82


^ permalink raw reply	[flat|nested] 262+ messages in thread

* Re: [PATCH v2 2/6] tree.c API: move read_tree() into builtin/ls-files.c
  2021-03-08  2:21   ` [PATCH v2 2/6] tree.c API: move read_tree() into builtin/ls-files.c Ævar Arnfjörð Bjarmason
@ 2021-03-08 18:06     ` Junio C Hamano
  2021-03-12 21:41     ` Junio C Hamano
  1 sibling, 0 replies; 262+ messages in thread
From: Junio C Hamano @ 2021-03-08 18:06 UTC (permalink / raw)
  To: Ævar Arnfjörð Bjarmason; +Cc: git, Elijah Newren

Ævar Arnfjörð Bjarmason  <avarab@gmail.com> writes:

> Now builtin/ls-files.c is the last user of this code, let's move all
> the relevant code there. This allows for subsequent simplification of
> it, and an eventual move to read_tree_recursive().

A nice goal to keep in mind while reading the series.

Is one already a subset of the other, or does the surviving version
need to gain a bit more feature or performance to replace the other?

Thanks.

^ permalink raw reply	[flat|nested] 262+ messages in thread

* Re: [PATCH v2 3/6] ls-files: don't needlessly pass around stage variable
  2021-03-08  2:21   ` [PATCH v2 3/6] ls-files: don't needlessly pass around stage variable Ævar Arnfjörð Bjarmason
@ 2021-03-08 18:18     ` Junio C Hamano
  0 siblings, 0 replies; 262+ messages in thread
From: Junio C Hamano @ 2021-03-08 18:18 UTC (permalink / raw)
  To: Ævar Arnfjörð Bjarmason; +Cc: git, Elijah Newren

Ævar Arnfjörð Bjarmason  <avarab@gmail.com> writes:

> Now that read_tree() has been moved to ls-files.c we can get rid of
> the stage != 1 case that'll never happen.
>
> Signed-off-by: Ævar Arnfjörð Bjarmason <avarab@gmail.com>
> ---
>  builtin/ls-files.c | 17 ++++-------------
>  1 file changed, 4 insertions(+), 13 deletions(-)
>
> diff --git a/builtin/ls-files.c b/builtin/ls-files.c
> index a4458622813..74d572a3e4a 100644
> --- a/builtin/ls-files.c
> +++ b/builtin/ls-files.c
> @@ -470,21 +470,12 @@ static int read_one_entry_quick(const struct object_id *oid, struct strbuf *base
>  }
>  
>  
> -static int read_tree(struct repository *r, struct tree *tree, int stage,
> +static int read_tree(struct repository *r, struct tree *tree,
>  		     struct pathspec *match, struct index_state *istate)
>  {
>  	read_tree_fn_t fn = NULL;
>  	int i, err;
>  
> -	/*
> -	 * Currently the only existing callers of this function all
> -	 * call it with stage=1 and after making sure there is nothing
> -	 * at that stage; we could always use read_one_entry_quick().
> -	 *
> -	 * But when we decide to straighten out git-read-tree not to
> -	 * use unpack_trees() in some cases, this will probably start
> -	 * to matter.
> -	 */

The "hoist everything to stage#1, read and compare" the commit that
introduced this comment talks about (cf. af3785dc5a7) was entirely
rewritten by d1f2d7e8 (Make run_diff_index() use unpack_trees(), not
read_tree(), 2008-01-19); this clean-up is long overdue.

Looking good.





>  	/*
>  	 * See if we have cache entry at the stage.  If so,
> @@ -493,13 +484,13 @@ static int read_tree(struct repository *r, struct tree *tree, int stage,
>  	 */
>  	for (i = 0; !fn && i < istate->cache_nr; i++) {
>  		const struct cache_entry *ce = istate->cache[i];
> -		if (ce_stage(ce) == stage)
> +		if (ce_stage(ce) == 1)
>  			fn = read_one_entry;
>  	}
>  
>  	if (!fn)
>  		fn = read_one_entry_quick;
> -	err = read_tree_recursive(r, tree, "", 0, stage, match, fn, istate);
> +	err = read_tree_recursive(r, tree, "", 0, 1, match, fn, istate);
>  	if (fn == read_one_entry || err)
>  		return err;
>  
> @@ -549,7 +540,7 @@ void overlay_tree_on_index(struct index_state *istate,
>  			       PATHSPEC_PREFER_CWD, prefix, matchbuf);
>  	} else
>  		memset(&pathspec, 0, sizeof(pathspec));
> -	if (read_tree(the_repository, tree, 1, &pathspec, istate))
> +	if (read_tree(the_repository, tree, &pathspec, istate))
>  		die("unable to read tree entries %s", tree_name);
>  
>  	for (i = 0; i < istate->cache_nr; i++) {

^ permalink raw reply	[flat|nested] 262+ messages in thread

* Re: [PATCH v2 4/6] ls-files: refactor away read_tree()
  2021-03-08  2:21   ` [PATCH v2 4/6] ls-files: refactor away read_tree() Ævar Arnfjörð Bjarmason
@ 2021-03-08 18:19     ` Junio C Hamano
  0 siblings, 0 replies; 262+ messages in thread
From: Junio C Hamano @ 2021-03-08 18:19 UTC (permalink / raw)
  To: Ævar Arnfjörð Bjarmason; +Cc: git, Elijah Newren

Ævar Arnfjörð Bjarmason  <avarab@gmail.com> writes:

> Refactor away the read_tree() function into its only user,
> overlay_tree_on_index().

Nice.

^ permalink raw reply	[flat|nested] 262+ messages in thread

* Re: [PATCH v2 0/6] Move the read_tree() function to its only user
  2021-03-08  2:21   ` [PATCH v2 0/6] " Ævar Arnfjörð Bjarmason
                       ` (30 preceding siblings ...)
  2021-03-08 15:06     ` [PATCH 30/30] tree-walk.h API: move canon_mode() back out of decode_tree_entry() Ævar Arnfjörð Bjarmason
@ 2021-03-08 19:18     ` Elijah Newren
  2021-03-15 23:43     ` [PATCH v3 0/9] read_tree() and read_tree_recursive() refactoring Ævar Arnfjörð Bjarmason
                       ` (9 subsequent siblings)
  41 siblings, 0 replies; 262+ messages in thread
From: Elijah Newren @ 2021-03-08 19:18 UTC (permalink / raw)
  To: Ævar Arnfjörð Bjarmason; +Cc: Git Mailing List, Junio C Hamano

On Sun, Mar 7, 2021 at 6:22 PM Ævar Arnfjörð Bjarmason <avarab@gmail.com> wrote:
>
> v1 of this series over-removed code supporting the "ls-files
> --with-tree=*" parameter. In v2 there's no change to its behavior,
> just refactoring away of read_tree() from the tree.c API and the
> cleanup of read_tree_recursive(). Thanks to Elijah for spotting that.
>
> I've added a test at the start of this series that would have caught
> that regression in v1 (and more).
>
> 1. https://lore.kernel.org/git/CABPp-BF982muRS4GO=zYegvetQyrPMwaEM3uEBvcbPRP=krfmQ@mail.gmail.com/

This addresses my concerns with v1; so:

Reviewed-by: Elijah Newren <newren@gmail.com>

>
> Ævar Arnfjörð Bjarmason (6):
>   ls-files tests: add meaningful --with-tree tests
>   tree.c API: move read_tree() into builtin/ls-files.c
>   ls-files: don't needlessly pass around stage variable
>   ls-files: refactor away read_tree()
>   tree.h API: remove support for starting at prefix != ""
>   tree.h API: remove "stage" parameter from read_tree_recursive()
>
>  archive.c                     |  13 +++--
>  builtin/checkout.c            |   4 +-
>  builtin/log.c                 |   6 +-
>  builtin/ls-files.c            |  76 ++++++++++++++++++++++++-
>  builtin/ls-tree.c             |   4 +-
>  merge-recursive.c             |   4 +-
>  t/t3060-ls-files-with-tree.sh |  41 ++++++++++++++
>  tree.c                        | 101 ++--------------------------------
>  tree.h                        |  10 +---
>  9 files changed, 139 insertions(+), 120 deletions(-)
>
> Range-diff:
> -:  ----------- > 1:  6416da0dee2 ls-files tests: add meaningful --with-tree tests
> 1:  020534164d3 ! 2:  765001b44cd tree.c API: move read_tree() into builtin/ls-files.c
>     @@ tree.c: int cmp_cache_name_compare(const void *a_, const void *b_)
>
>       ## tree.h ##
>      @@ tree.h: int read_tree_recursive(struct repository *r,
>     +                   const char *base, int baselen,
>                         int stage, const struct pathspec *pathspec,
>                         read_tree_fn_t fn, void *context);
>     -
>     +-
>      -int read_tree(struct repository *r, struct tree *tree,
>      -        int stage, struct pathspec *pathspec,
>      -        struct index_state *istate);
> 2:  6aa6ba2fbb5 = 3:  a71ffba7d04 ls-files: don't needlessly pass around stage variable
> 3:  4f27e5d2970 ! 4:  e78d1810b89 ls-files: remove cache juggling + sorting
>     @@ Metadata
>      Author: Ævar Arnfjörð Bjarmason <avarab@gmail.com>
>
>       ## Commit message ##
>     -    ls-files: remove cache juggling + sorting
>     +    ls-files: refactor away read_tree()
>
>     -    Remove the "ce_stage(ce) == 1" and "Sort the cache entry" code from
>     -    read_tree(), which allows us to remove the function entirely and move
>     -    over to read_tree_recursive().
>     +    Refactor away the read_tree() function into its only user,
>     +    overlay_tree_on_index().
>
>     -    I don't think the "Sort the cached entry" code was needed here, see
>     -    af3785dc5a7 (Optimize "diff --cached" performance., 2007-08-09) for
>     -    the use-case it was intended for. The only user of this code is
>     -    "ls-files --with-tree", which isn't the sort of use-case that needs to
>     -    care about "ce_stage(ce) != 0" or sorting tree entries.
>     +    First, change read_one_entry_opt() to use the strbuf parameter
>     +    read_tree_recursive() passes down in place. This finishes up a partial
>     +    refactoring started in 6a0b0b6de99 (tree.c: update read_tree_recursive
>     +    callback to pass strbuf as base, 2014-11-30).
>     +
>     +    Moving the rest into overlay_tree_on_index() makes this index juggling
>     +    we're doing easier to read.
>
>          Signed-off-by: Ævar Arnfjörð Bjarmason <avarab@gmail.com>
>
>       ## builtin/ls-files.c ##
>     -@@
>     - #include "dir.h"
>     - #include "builtin.h"
>     - #include "tree.h"
>     --#include "cache-tree.h"
>     - #include "parse-options.h"
>     - #include "resolve-undo.h"
>     - #include "string-list.h"
>      @@ builtin/ls-files.c: static int get_common_prefix_len(const char *common_prefix)
>     -   return common_prefix_len;
>     - }
>
>     --static int read_one_entry_opt(struct index_state *istate,
>     --                        const struct object_id *oid,
>     + static int read_one_entry_opt(struct index_state *istate,
>     +                         const struct object_id *oid,
>      -                        const char *base, int baselen,
>     --                        const char *pathname,
>     --                        unsigned mode, int stage, int opt)
>     -+static int read_one_entry_quick(const struct object_id *oid,
>     -+                          struct strbuf *basebuf,
>     -+                          const char *pathname,
>     -+                          unsigned mode,
>     -+                          int stage, void *context)
>     ++                        struct strbuf *base,
>     +                         const char *pathname,
>     +                         unsigned mode, int stage, int opt)
>       {
>     -+  struct index_state *istate = context;
>     -+  const char *base = basebuf->buf;
>     -+  const int baselen = basebuf->len;
>     -   int len;
>     -   struct cache_entry *ce;
>     -
>      @@ builtin/ls-files.c: static int read_one_entry_opt(struct index_state *istate,
>     -   memcpy(ce->name, base, baselen);
>     -   memcpy(ce->name + baselen, pathname, len+1);
>     +           return READ_TREE_RECURSIVE;
>     +
>     +   len = strlen(pathname);
>     +-  ce = make_empty_cache_entry(istate, baselen + len);
>     ++  ce = make_empty_cache_entry(istate, base->len + len);
>     +
>     +   ce->ce_mode = create_ce_mode(mode);
>     +   ce->ce_flags = create_ce_flags(stage);
>     +-  ce->ce_namelen = baselen + len;
>     +-  memcpy(ce->name, base, baselen);
>     +-  memcpy(ce->name + baselen, pathname, len+1);
>     ++  ce->ce_namelen = base->len + len;
>     ++  memcpy(ce->name, base->buf, base->len);
>     ++  memcpy(ce->name + base->len, pathname, len+1);
>         oidcpy(&ce->oid, oid);
>     --  return add_index_entry(istate, ce, opt);
>     --}
>     --
>     --static int read_one_entry(const struct object_id *oid, struct strbuf *base,
>     --                    const char *pathname, unsigned mode, int stage,
>     --                    void *context)
>     --{
>     --  struct index_state *istate = context;
>     +   return add_index_entry(istate, ce, opt);
>     + }
>     +@@ builtin/ls-files.c: static int read_one_entry(const struct object_id *oid, struct strbuf *base,
>     +                     void *context)
>     + {
>     +   struct index_state *istate = context;
>      -  return read_one_entry_opt(istate, oid, base->buf, base->len, pathname,
>     --                            mode, stage,
>     --                            ADD_CACHE_OK_TO_ADD|ADD_CACHE_SKIP_DFCHECK);
>     --}
>     --
>     --/*
>     -- * This is used when the caller knows there is no existing entries at
>     -- * the stage that will conflict with the entry being added.
>     -- */
>     --static int read_one_entry_quick(const struct object_id *oid, struct strbuf *base,
>     --                          const char *pathname, unsigned mode, int stage,
>     --                          void *context)
>     --{
>     --  struct index_state *istate = context;
>     ++  return read_one_entry_opt(istate, oid, base, pathname,
>     +                             mode, stage,
>     +                             ADD_CACHE_OK_TO_ADD|ADD_CACHE_SKIP_DFCHECK);
>     + }
>     +@@ builtin/ls-files.c: static int read_one_entry_quick(const struct object_id *oid, struct strbuf *base
>     +                           void *context)
>     + {
>     +   struct index_state *istate = context;
>      -  return read_one_entry_opt(istate, oid, base->buf, base->len, pathname,
>     --                            mode, stage,
>     --                            ADD_CACHE_JUST_APPEND);
>     --}
>     --
>     ++  return read_one_entry_opt(istate, oid, base, pathname,
>     +                             mode, stage,
>     +                             ADD_CACHE_JUST_APPEND);
>     + }
>     +
>      -
>      -static int read_tree(struct repository *r, struct tree *tree,
>      -               struct pathspec *match, struct index_state *istate)
>     @@ builtin/ls-files.c: static int read_one_entry_opt(struct index_state *istate,
>      -  cache_tree_free(&istate->cache_tree);
>      -  QSORT(istate->cache, istate->cache_nr, cmp_cache_name_compare);
>      -  return 0;
>     -+  return add_index_entry(istate, ce, ADD_CACHE_JUST_APPEND);
>     - }
>     -
>     +-}
>     +-
>       /*
>     +  * Read the tree specified with --with-tree option
>     +  * (typically, HEAD) into stage #1 and then
>     +@@ builtin/ls-files.c: void overlay_tree_on_index(struct index_state *istate,
>     +   struct pathspec pathspec;
>     +   struct cache_entry *last_stage0 = NULL;
>     +   int i;
>     ++  read_tree_fn_t fn = NULL;
>     ++  int err;
>     +
>     +   if (get_oid(tree_name, &oid))
>     +           die("tree-ish %s not found.", tree_name);
>      @@ builtin/ls-files.c: void overlay_tree_on_index(struct index_state *istate,
>                                PATHSPEC_PREFER_CWD, prefix, matchbuf);
>         } else
>                 memset(&pathspec, 0, sizeof(pathspec));
>      -  if (read_tree(the_repository, tree, &pathspec, istate))
>     -+  if (read_tree_recursive(the_repository, tree, "", 0, 1,
>     -+                          &pathspec, read_one_entry_quick, istate))
>     ++
>     ++  /*
>     ++   * See if we have cache entry at the stage.  If so,
>     ++   * do it the original slow way, otherwise, append and then
>     ++   * sort at the end.
>     ++   */
>     ++  for (i = 0; !fn && i < istate->cache_nr; i++) {
>     ++          const struct cache_entry *ce = istate->cache[i];
>     ++          if (ce_stage(ce) == 1)
>     ++                  fn = read_one_entry;
>     ++  }
>     ++
>     ++  if (!fn)
>     ++          fn = read_one_entry_quick;
>     ++  err = read_tree_recursive(the_repository, tree, "", 0, 1, &pathspec, fn, istate);
>     ++  if (err)
>                 die("unable to read tree entries %s", tree_name);
>
>     ++  /*
>     ++   * Sort the cache entry -- we need to nuke the cache tree, though.
>     ++   */
>     ++  if (fn == read_one_entry_quick) {
>     ++          cache_tree_free(&istate->cache_tree);
>     ++          QSORT(istate->cache, istate->cache_nr, cmp_cache_name_compare);
>     ++  }
>     ++
>         for (i = 0; i < istate->cache_nr; i++) {
>     +           struct cache_entry *ce = istate->cache[i];
>     +           switch (ce_stage(ce)) {
> 4:  33810d3c10c < -:  ----------- merge-ort: move cmp_cache_name_compare() from tree.c
> 5:  fb10246b85b < -:  ----------- ls-files: refactor read_one_entry_quick() to use a strbuf
> 6:  0c065615aec ! 5:  05eecdd7519 tree.h API: remove support for starting at prefix != ""
>     @@ Metadata
>       ## Commit message ##
>          tree.h API: remove support for starting at prefix != ""
>
>     -    Every caller or the read_tree_recursive() function hardcoded a
>     +    Every caller of the read_tree_recursive() function hardcoded a
>          starting point of "" in the tree. So let's simply remove that
>          parameter.
>
>     -    It might be useful in the future to get this functionality back,
>     -    there's no reason we won't have a read_tree_recursive() use-case that
>     -    would want to start in a subdirectory.
>     +    The last function to call read_tree_recursive() with a non-"" path was
>     +    read_tree_recursive() itself, but that was changed in
>     +    ffd31f661d5 (Reimplement read_tree_recursive() using
>     +    tree_entry_interesting(), 2011-03-25).
>
>     -    But if and when that happens we can just add something like a
>     -    read_tree_recursive_subdir() and have both read_tree_recursive() and
>     -    that function be a thin wrapper for read_tree_1().
>     +    If in the future we need to support recursively reading trees without
>     +    starting at the root we can easily add a read_tree_recursive_subdir(),
>     +    and make that function a thin wrapper for read_tree_1().
>
>          In the meantime there's no reason to keep around what amounts to dead
>     -    code just in case we need it in the future.
>     +    code, just in case we need it in the future.
>
>          Signed-off-by: Ævar Arnfjörð Bjarmason <avarab@gmail.com>
>
>     @@ builtin/log.c: int cmd_show(int argc, const char **argv, const char *prefix)
>
>       ## builtin/ls-files.c ##
>      @@ builtin/ls-files.c: void overlay_tree_on_index(struct index_state *istate,
>     -                          PATHSPEC_PREFER_CWD, prefix, matchbuf);
>     -   } else
>     -           memset(&pathspec, 0, sizeof(pathspec));
>     --  if (read_tree_recursive(the_repository, tree, "", 0, 1,
>     -+  if (read_tree_recursive(the_repository, tree, 1,
>     -                           &pathspec, read_one_entry_quick, istate))
>     +
>     +   if (!fn)
>     +           fn = read_one_entry_quick;
>     +-  err = read_tree_recursive(the_repository, tree, "", 0, 1, &pathspec, fn, istate);
>     ++  err = read_tree_recursive(the_repository, tree, 1, &pathspec, fn, istate);
>     +   if (err)
>                 die("unable to read tree entries %s", tree_name);
>
>
>     @@ tree.h: typedef int (*read_tree_fn_t)(const struct object_id *, struct strbuf *,
>      -                  const char *base, int baselen,
>                         int stage, const struct pathspec *pathspec,
>                         read_tree_fn_t fn, void *context);
>     -
>     + #endif /* TREE_H */
> 7:  9685c7c5c50 ! 6:  fcecc82e1c8 tree.h API: remove "stage" parameter from read_tree_recursive()
>     @@ builtin/log.c: int cmd_show(int argc, const char **argv, const char *prefix)
>                         break;
>
>       ## builtin/ls-files.c ##
>     -@@ builtin/ls-files.c: static int read_one_entry_quick(const struct object_id *oid,
>     -                           struct strbuf *base,
>     -                           const char *pathname,
>     -                           unsigned mode,
>     --                          int stage, void *context)
>     -+                          void *context)
>     +@@ builtin/ls-files.c: static int read_one_entry_opt(struct index_state *istate,
>     +                         const struct object_id *oid,
>     +                         struct strbuf *base,
>     +                         const char *pathname,
>     +-                        unsigned mode, int stage, int opt)
>     ++                        unsigned mode, int opt)
>       {
>     -   struct index_state *istate = context;
>         int len;
>     -@@ builtin/ls-files.c: static int read_one_entry_quick(const struct object_id *oid,
>     +   struct cache_entry *ce;
>     +@@ builtin/ls-files.c: static int read_one_entry_opt(struct index_state *istate,
>         ce = make_empty_cache_entry(istate, base->len + len);
>
>         ce->ce_mode = create_ce_mode(mode);
>     @@ builtin/ls-files.c: static int read_one_entry_quick(const struct object_id *oid,
>         ce->ce_namelen = base->len + len;
>         memcpy(ce->name, base->buf, base->len);
>         memcpy(ce->name + base->len, pathname, len+1);
>     +@@ builtin/ls-files.c: static int read_one_entry_opt(struct index_state *istate,
>     + }
>     +
>     + static int read_one_entry(const struct object_id *oid, struct strbuf *base,
>     +-                    const char *pathname, unsigned mode, int stage,
>     ++                    const char *pathname, unsigned mode,
>     +                     void *context)
>     + {
>     +   struct index_state *istate = context;
>     +   return read_one_entry_opt(istate, oid, base, pathname,
>     +-                            mode, stage,
>     ++                            mode,
>     +                             ADD_CACHE_OK_TO_ADD|ADD_CACHE_SKIP_DFCHECK);
>     + }
>     +
>     +@@ builtin/ls-files.c: static int read_one_entry(const struct object_id *oid, struct strbuf *base,
>     +  * the stage that will conflict with the entry being added.
>     +  */
>     + static int read_one_entry_quick(const struct object_id *oid, struct strbuf *base,
>     +-                          const char *pathname, unsigned mode, int stage,
>     ++                          const char *pathname, unsigned mode,
>     +                           void *context)
>     + {
>     +   struct index_state *istate = context;
>     +   return read_one_entry_opt(istate, oid, base, pathname,
>     +-                            mode, stage,
>     ++                            mode,
>     +                             ADD_CACHE_JUST_APPEND);
>     + }
>     +
>      @@ builtin/ls-files.c: void overlay_tree_on_index(struct index_state *istate,
>     -                          PATHSPEC_PREFER_CWD, prefix, matchbuf);
>     -   } else
>     -           memset(&pathspec, 0, sizeof(pathspec));
>     --  if (read_tree_recursive(the_repository, tree, 1,
>     -+  if (read_tree_recursive(the_repository, tree,
>     -                           &pathspec, read_one_entry_quick, istate))
>     +
>     +   if (!fn)
>     +           fn = read_one_entry_quick;
>     +-  err = read_tree_recursive(the_repository, tree, 1, &pathspec, fn, istate);
>     ++  err = read_tree_recursive(the_repository, tree, &pathspec, fn, istate);
>     +   if (err)
>                 die("unable to read tree entries %s", tree_name);
>
>
>     @@ tree.c: static int read_tree_1(struct repository *r,
>       }
>
>       ## tree.h ##
>     -@@ tree.h: void free_tree_buffer(struct tree *tree);
>     - struct tree *parse_tree_indirect(const struct object_id *oid);
>     +@@ tree.h: struct tree *parse_tree_indirect(const struct object_id *oid);
>     + int cmp_cache_name_compare(const void *a_, const void *b_);
>
>       #define READ_TREE_RECURSIVE 1
>      -typedef int (*read_tree_fn_t)(const struct object_id *, struct strbuf *, const char *, unsigned int, int, void *);
>     @@ tree.h: void free_tree_buffer(struct tree *tree);
>      -                  int stage, const struct pathspec *pathspec,
>      +                  const struct pathspec *pathspec,
>                         read_tree_fn_t fn, void *context);
>     -
>       #endif /* TREE_H */
> --
> 2.31.0.rc0.126.g04f22c5b82
>

^ permalink raw reply	[flat|nested] 262+ messages in thread

* Re: [PATCH 00/30] tree-walk: mostly "mode" to "enum object_type"
  2021-03-08 15:06     ` [PATCH 00/30] tree-walk: mostly "mode" to "enum object_type" Ævar Arnfjörð Bjarmason
@ 2021-03-09  0:10       ` Elijah Newren
  2021-03-09 20:41       ` Elijah Newren
                         ` (30 subsequent siblings)
  31 siblings, 0 replies; 262+ messages in thread
From: Elijah Newren @ 2021-03-09  0:10 UTC (permalink / raw)
  To: Ævar Arnfjörð Bjarmason
  Cc: Git Mailing List, Junio C Hamano, Kirill Smelkov,
	Nguyễn Thái Ngọc Duy

On Mon, Mar 8, 2021 at 7:07 AM Ævar Arnfjörð Bjarmason <avarab@gmail.com> wrote:
>
> This large series goes on top of my 6 patch series for
> read_tree_recursive() as this one further refactors that function. See
> https://lore.kernel.org/git/20210308022138.28166-1-avarab@gmail.com/
> for that series.
>
> I noticed that since 2014 or so we haven't been doing the fsck checks
> for bad file modes in trees. This series fixes that. I plan to add
> tests etc. for that in another follow-up series.
>
> I wanted to get this out for review sooner than later, particularly
> since the fsck testing will probably get me down another refactoring
> path (fsck testing in general in this area is pretty bad...).
>
> As noted in 30/30 it would have been way easier to simply do an
> isolated fix for that bug by introducing some fsck-specific API for
> raw tree reading.
>
> But I thought the bug was symptomatic of a wider problem in our
> codebase. Namely that we pass around the tree's mode *a lot*.
>
> But almost everything that then deals with the mode doesn't per-se
> care about the mode bits in the tree, but using them to map that mode
> to a tree entry for one of of OBJ_{BLOB,TREE,COMMIT}.
>
> So this is a large refactoring of all users of the widely used
> tree-walk.h API to "enum obj2ect_type", finally in 29/30 I rename the
> field to a scary "raw_mode".
>
> At that point we have just ~30-50 grep hits left for "raw_mode" in the
> codebase (depending on whether we count names in function parameters).
>
> Hopefully being in that state alleviates e.g. Elijah's concerns
> expressed in
> https://lore.kernel.org/git/CABPp-BEdu1PqV5W=FuL0f08iFhGzvzV8oSUybNj4eF0aAwTnAw@mail.gmail.com/
> I agree that doing the equivalent of 30/30 on top of master would be
> way too scary, but once we're at 29/30 I think it's sane.
>
> I tested this in combination with his on-list series to add more
> merge-ort testing:
> https://lore.kernel.org/git/pull.973.git.git.1614905738.gitgitgadget@gmail.com/
>
> I found a regression I'd caused in the merge-ort.c code with those
> tests, fixed here. See the comment in merge-ort.c in 30/30.

I'll start reading through this series, but two quick early notes:
  - I was worried about touching the tree-walk code message up
performance.  Since collect_rename_info() in merge-ort.c takes the
most time (and it's mostly a tree-walk), I was worried this would
regress performance for me.  A couple runs of my mega-renames big
rebase testcase suggests performance is not that different, so my
fears look unfounded.  (Note: I tested in combination with all my
performance improvements, because otherwise tree-walking would just be
in the noise of overall runtime.)
  - There's a textual conflict with this series and my sets of patch
series that finish off the ort implementation[1], but it's just two
lines that are pretty easy to resolve.

[1] https://github.com/gitgitgadget/git/pulls?q=is%3Aopen+is%3Apr+author%3Anewren+Optimization+batch


> Ævar Arnfjörð Bjarmason (30):
>   diff.c: remove redundant canon_mode() call
>   notes & match-trees: use name_entry's "pathlen" member
>   cache.h: add a comment to object_type()
>   tree-walk.h: add object_type member to name_entry
>   tree-walk.c: migrate to using new "object_type" field when possible
>   cache.h: have base_name_compare() take "is tree?", not "mode"
>   tree-walk.h users: switch object_type(...) to new .object_type
>   tree.h: format argument lists of read_tree_recursive() users
>   tree.h users: format argument lists in archive.c
>   archive: get rid of 'stage' parameter
>   tree.h API: make read_tree_fn_t take an "enum object_type"
>   tree-walk.h users: migrate "p->mode &&" pattern
>   tree-walk.h users: refactor chained "mode" if/else into switch
>   tree-walk.h users: migrate miscellaneous "mode" to "object_type"
>   merge-tree tests: test for the mode comparison in same_entry()
>   merge-ort: correct reference to test in 62fdec17a11
>   fsck.c: switch on "object_type" in fsck_walk_tree()
>   tree-walk.h users: use temporary variable(s) for "mode"
>   tree-walk.h API: formatting changes for subsequent commit
>   tree-walk.h API: rename get_tree_entry() to get_tree_entry_mode()
>   tree-walk.h API users: use "tmp" for mode in shift_tree_by()
>   tree-walk.h API: Add get_tree_entry_type()
>   tree-walk.h API: add a get_tree_entry_path() function
>   tree-walk.h API: document and format tree_entry_extract()
>   tree-entry.h API: rename tree_entry_extract() to
>     tree_entry_extract_mode()
>   tree-walk.h API: add a tree_entry_extract_all() function
>   tree-walk.h API: add a tree_entry_extract_type() function
>   tree-walk.h API users: rename "struct name_entry"'s "mode" to
>     "raw_mode"
>   tree.h API users: rename read_tree_fn_t's "mode" to "raw_mode"
>   tree-walk.h API: move canon_mode() back out of decode_tree_entry()
>
>  archive.c              | 51 +++++++++++++-----------
>  blame.c                |  9 +++--
>  builtin/checkout.c     |  7 +++-
>  builtin/fast-import.c  |  8 ++--
>  builtin/grep.c         |  6 +--
>  builtin/log.c          |  7 ++--
>  builtin/ls-files.c     | 13 +++---
>  builtin/ls-tree.c      | 18 ++++-----
>  builtin/merge-tree.c   | 32 +++++++++------
>  builtin/mktree.c       |  4 +-
>  builtin/pack-objects.c |  6 +--
>  builtin/reflog.c       |  3 +-
>  builtin/rm.c           |  2 +-
>  builtin/update-index.c |  7 +++-
>  cache-tree.c           |  2 +-
>  cache.h                | 11 ++++--
>  combine-diff.c         |  8 ++--
>  delta-islands.c        |  2 +-
>  diff.c                 |  2 +-
>  fsck.c                 | 23 +++++------
>  http-push.c            |  6 ++-
>  line-log.c             |  2 +-
>  list-objects.c         | 20 +++++++---
>  match-trees.c          | 52 ++++++++++++------------
>  merge-ort.c            | 34 ++++++++++------
>  merge-recursive.c      | 33 ++++++++--------
>  notes.c                | 15 +++----
>  object-name.c          |  7 ++--
>  pack-bitmap-write.c    |  8 ++--
>  read-cache.c           | 16 ++++----
>  revision.c             | 12 ++++--
>  t/t4300-merge-tree.sh  | 44 +++++++++++++++++++++
>  tree-diff.c            | 44 ++++++++++++---------
>  tree-walk.c            | 89 +++++++++++++++++++++++++++++++-----------
>  tree-walk.h            | 67 ++++++++++++++++++++++++++-----
>  tree.c                 | 19 +++++----
>  tree.h                 |  5 ++-
>  unpack-trees.c         | 30 ++++++++------
>  walker.c               | 22 ++++++-----
>  39 files changed, 482 insertions(+), 264 deletions(-)
>
> --
> 2.31.0.rc0.126.g04f22c5b82
>

^ permalink raw reply	[flat|nested] 262+ messages in thread

* Re: [PATCH 03/30] cache.h: add a comment to object_type()
  2021-03-08 15:06     ` [PATCH 03/30] cache.h: add a comment to object_type() Ævar Arnfjörð Bjarmason
@ 2021-03-09 16:40       ` Elijah Newren
  0 siblings, 0 replies; 262+ messages in thread
From: Elijah Newren @ 2021-03-09 16:40 UTC (permalink / raw)
  To: Ævar Arnfjörð Bjarmason
  Cc: Git Mailing List, Junio C Hamano, Kirill Smelkov,
	Nguyễn Thái Ngọc Duy

On Mon, Mar 8, 2021 at 7:07 AM Ævar Arnfjörð Bjarmason <avarab@gmail.com> wrote:
>
> Add a comment to the object_type() function to explain what it
> returns, and whet the "mode" is in the "else" case.

s/whet/what/ ?


>
> The object_type() function dates back to 4d1012c3709 (Fix rev-list
> when showing objects involving submodules, 2007-11-11). It's not
> immediately obvious to someone looking at its history and how it's
> come to be used.
>
> Despite what Linus noted in 4d1012c3709 (Fix rev-list when showing
> objects involving submodules, 2007-11-11) about wanting to move away
> from users of object_type() relying on S_ISLNK(mode) being true here
> we do currently rely on that. If this is changed to a condition to
> only return OBJ_BLOB on S_ISREG(mode) then t4008, t4023 and t7415 will
> have failing tests.
>
> Signed-off-by: Ævar Arnfjörð Bjarmason <avarab@gmail.com>
> ---
>  cache.h | 7 ++++++-
>  1 file changed, 6 insertions(+), 1 deletion(-)
>
> diff --git a/cache.h b/cache.h
> index d9281496140..e513f0ee5b4 100644
> --- a/cache.h
> +++ b/cache.h
> @@ -451,11 +451,16 @@ enum object_type {
>         OBJ_MAX
>  };
>
> +/*
> + * object_type() returns an object of a type that'll appear in a tree,
> + * so no OBJ_TAG is possible. This is mostly (and dates back to)
> + * consumers of the tree-walk.h API's "mode" field.
> + */
>  static inline enum object_type object_type(unsigned int mode)
>  {
>         return S_ISDIR(mode) ? OBJ_TREE :
>                 S_ISGITLINK(mode) ? OBJ_COMMIT :
> -               OBJ_BLOB;
> +               OBJ_BLOB; /* S_ISREG(mode) || S_ISLNK(mode) */
>  }
>
>  /* Double-check local_repo_env below if you add to this list. */
> --
> 2.31.0.rc0.126.g04f22c5b82

^ permalink raw reply	[flat|nested] 262+ messages in thread

* Re: [PATCH 05/30] tree-walk.c: migrate to using new "object_type" field when possible
  2021-03-08 15:06     ` [PATCH 05/30] tree-walk.c: migrate to using new "object_type" field when possible Ævar Arnfjörð Bjarmason
@ 2021-03-09 16:44       ` Elijah Newren
  0 siblings, 0 replies; 262+ messages in thread
From: Elijah Newren @ 2021-03-09 16:44 UTC (permalink / raw)
  To: Ævar Arnfjörð Bjarmason
  Cc: Git Mailing List, Junio C Hamano, Kirill Smelkov,
	Nguyễn Thái Ngọc Duy

On Mon, Mar 8, 2021 at 7:07 AM Ævar Arnfjörð Bjarmason <avarab@gmail.com> wrote:
>
> Signed-off-by: Ævar Arnfjörð Bjarmason <avarab@gmail.com>
> ---
>  tree-walk.c | 24 +++++++++++++-----------
>  1 file changed, 13 insertions(+), 11 deletions(-)
>
> diff --git a/tree-walk.c b/tree-walk.c
> index b210967b73b..6e9161901d8 100644
> --- a/tree-walk.c
> +++ b/tree-walk.c
> @@ -521,7 +521,7 @@ int traverse_trees(struct index_state *istate,
>                         if (!entry[i].path)
>                                 continue;
>                         mask |= 1ul << i;
> -                       if (S_ISDIR(entry[i].mode))
> +                       if (entry[i].object_type == OBJ_TREE)
>                                 dirmask |= 1ul << i;
>                         e = &entry[i];
>                 }
> @@ -892,8 +892,8 @@ static int match_entry(const struct pathspec_item *item,
>                  * nothing else (to handle 'submod/' and 'submod'
>                  * uniformly).
>                  */
> -               if (!S_ISDIR(entry->mode) &&
> -                   (!S_ISGITLINK(entry->mode) || matchlen > pathlen + 1))
> +               if (entry->object_type != OBJ_TREE &&
> +                   (entry->object_type != OBJ_COMMIT || matchlen > pathlen + 1))
>                         return 0;
>         }
>
> @@ -1038,7 +1038,7 @@ static enum interesting do_match(struct index_state *istate,
>                     ps->max_depth == -1)
>                         return all_entries_interesting;
>                 return within_depth(base->buf + base_offset, baselen,
> -                                   !!S_ISDIR(entry->mode),
> +                                   entry->object_type == OBJ_TREE,
>                                     ps->max_depth) ?
>                         entry_interesting : entry_not_interesting;
>         }
> @@ -1071,7 +1071,7 @@ static enum interesting do_match(struct index_state *istate,
>
>                         if (within_depth(base_str + matchlen + 1,
>                                          baselen - matchlen - 1,
> -                                        !!S_ISDIR(entry->mode),
> +                                        entry->object_type == OBJ_TREE,
>                                          ps->max_depth))
>                                 goto interesting;
>                         else
> @@ -1094,7 +1094,8 @@ static enum interesting do_match(struct index_state *istate,
>                                  * Match all directories. We'll try to
>                                  * match files later on.
>                                  */
> -                               if (ps->recursive && S_ISDIR(entry->mode))
> +                               if (ps->recursive &&
> +                                   entry->object_type == OBJ_TREE)
>                                         return entry_interesting;
>
>                                 /*
> @@ -1105,7 +1106,7 @@ static enum interesting do_match(struct index_state *istate,
>                                  * be performed in the submodule itself.
>                                  */
>                                 if (ps->recurse_submodules &&
> -                                   S_ISGITLINK(entry->mode) &&
> +                                   entry->object_type == OBJ_COMMIT &&
>                                     !ps_strncmp(item, match + baselen,
>                                                 entry->path,
>                                                 item->nowildcard_len - baselen))
> @@ -1154,7 +1155,8 @@ static enum interesting do_match(struct index_state *istate,
>                  * character.  More accurate matching can then
>                  * be performed in the submodule itself.
>                  */
> -               if (ps->recurse_submodules && S_ISGITLINK(entry->mode) &&
> +               if (ps->recurse_submodules &&
> +                   entry->object_type == OBJ_COMMIT &&
>                     !ps_strncmp(item, match, base->buf + base_offset,
>                                 item->nowildcard_len)) {
>                         strbuf_setlen(base, base_offset + baselen);
> @@ -1170,7 +1172,7 @@ static enum interesting do_match(struct index_state *istate,
>                  * in future, see
>                  * https://lore.kernel.org/git/7vmxo5l2g4.fsf@alter.siamese.dyndns.org/
>                  */
> -               if (ps->recursive && S_ISDIR(entry->mode))
> +               if (ps->recursive && entry->object_type == OBJ_TREE)
>                         return entry_interesting;
>                 continue;
>  interesting:
> @@ -1193,7 +1195,7 @@ static enum interesting do_match(struct index_state *istate,
>                          * can probably return all_entries_interesting or
>                          * all_entries_not_interesting here if matched.
>                          */
> -                       if (S_ISDIR(entry->mode))
> +                       if (entry->object_type == OBJ_TREE)
>                                 return entry_interesting;
>
>                         strbuf_add(base, entry->path, pathlen);
> @@ -1269,7 +1271,7 @@ enum interesting tree_entry_interesting(struct index_state *istate,
>                 return positive;
>
>         /* #15, #19 */
> -       if (S_ISDIR(entry->mode) &&
> +       if (entry->object_type == OBJ_TREE &&
>             positive >= entry_interesting &&
>             negative == entry_interesting)
>                 return entry_interesting;
> --
> 2.31.0.rc0.126.g04f22c5b82

To me, this commit shows the advantage of the new field; the new code
looks much more readable.

^ permalink raw reply	[flat|nested] 262+ messages in thread

* Re: [PATCH 06/30] cache.h: have base_name_compare() take "is tree?", not "mode"
  2021-03-08 15:06     ` [PATCH 06/30] cache.h: have base_name_compare() take "is tree?", not "mode" Ævar Arnfjörð Bjarmason
@ 2021-03-09 16:56       ` Elijah Newren
  0 siblings, 0 replies; 262+ messages in thread
From: Elijah Newren @ 2021-03-09 16:56 UTC (permalink / raw)
  To: Ævar Arnfjörð Bjarmason
  Cc: Git Mailing List, Junio C Hamano, Kirill Smelkov,
	Nguyễn Thái Ngọc Duy

On Mon, Mar 8, 2021 at 7:07 AM Ævar Arnfjörð Bjarmason <avarab@gmail.com> wrote:
>
> Change the base_name_compare() API and the related df_name_compare()
> function to take a boolean argument indicating whether the entry is a
> tree or not, instead of having them call S_ISDIR(mode) on their own.
>
> This makes use of the new "object_type" field in the "name_entry".
>
> The API being modified here was originally added way back in
> 958ba6c96eb (Introduce "base_name_compare()" helper function,
> 2005-05-20).
>
> Signed-off-by: Ævar Arnfjörð Bjarmason <avarab@gmail.com>
> ---
>  builtin/fast-import.c |  8 ++++----
>  builtin/mktree.c      |  4 ++--
>  cache.h               |  4 ++--
>  combine-diff.c        |  8 +++++---
>  match-trees.c         |  6 ++++--
>  merge-ort.c           |  4 ++--
>  merge-recursive.c     |  6 +++---
>  read-cache.c          | 16 ++++++++--------
>  tree-diff.c           |  7 +++++--
>  unpack-trees.c        | 15 ++++++++-------
>  10 files changed, 43 insertions(+), 35 deletions(-)
>
> diff --git a/builtin/fast-import.c b/builtin/fast-import.c
> index dd4d09ceceb..ce4613c1595 100644
> --- a/builtin/fast-import.c
> +++ b/builtin/fast-import.c
> @@ -1288,8 +1288,8 @@ static int tecmp0 (const void *_a, const void *_b)
>         struct tree_entry *a = *((struct tree_entry**)_a);
>         struct tree_entry *b = *((struct tree_entry**)_b);
>         return base_name_compare(
> -               a->name->str_dat, a->name->str_len, a->versions[0].mode,
> -               b->name->str_dat, b->name->str_len, b->versions[0].mode);
> +               a->name->str_dat, a->name->str_len, 1,
> +               b->name->str_dat, b->name->str_len, 1);
>  }
>
>  static int tecmp1 (const void *_a, const void *_b)
> @@ -1297,8 +1297,8 @@ static int tecmp1 (const void *_a, const void *_b)
>         struct tree_entry *a = *((struct tree_entry**)_a);
>         struct tree_entry *b = *((struct tree_entry**)_b);
>         return base_name_compare(
> -               a->name->str_dat, a->name->str_len, a->versions[1].mode,
> -               b->name->str_dat, b->name->str_len, b->versions[1].mode);
> +               a->name->str_dat, a->name->str_len, 1,
> +               b->name->str_dat, b->name->str_len, 1);
>  }

You've treated all files as directories, and in doing so broken the
sorting order of paths like the following
    foo
    foo.txt
foo needs to sort after foo.txt if it's a directory, and before
foo.txt if it's a file; that's the whole reason base_name_compare()
wants to know is_tree-ness.

It looks like we have a whole in our regression test coverage, since
they didn't catch this breakage.  (git will accept and work with trees
in the wrong sort-order, but it can create confusing diffs and
whatnot.)

>  static void mktree(struct tree_content *t, int v, struct strbuf *b)
> diff --git a/builtin/mktree.c b/builtin/mktree.c
> index 891991b00d6..2c1973229ac 100644
> --- a/builtin/mktree.c
> +++ b/builtin/mktree.c
> @@ -37,8 +37,8 @@ static int ent_compare(const void *a_, const void *b_)
>  {
>         struct treeent *a = *(struct treeent **)a_;
>         struct treeent *b = *(struct treeent **)b_;
> -       return base_name_compare(a->name, a->len, a->mode,
> -                                b->name, b->len, b->mode);
> +       return base_name_compare(a->name, a->len, S_ISDIR(a->mode),
> +                                b->name, b->len, S_ISDIR(b->mode));
>  }
>
>  static void write_tree(struct object_id *oid)
> diff --git a/cache.h b/cache.h
> index e513f0ee5b4..49994dae916 100644
> --- a/cache.h
> +++ b/cache.h
> @@ -1506,8 +1506,8 @@ int repo_interpret_branch_name(struct repository *r,
>
>  int validate_headref(const char *ref);
>
> -int base_name_compare(const char *name1, int len1, int mode1, const char *name2, int len2, int mode2);
> -int df_name_compare(const char *name1, int len1, int mode1, const char *name2, int len2, int mode2);
> +int base_name_compare(const char *name1, int len1, int isdir1, const char *name2, int len2, int isdir2);
> +int df_name_compare(const char *name1, int len1, int isdir1, const char *name2, int len2, int isdir2);

A very minor nit/question:

Do we want to call this isdir or istree?  I know we use S_ISDIR() but
that's because it's a pre-existing macro pre-dating git.  As you
mentioned in your commit message, we want to know whether the object
in question is a git "tree", so I'm inclined to go with istree.

But, I'm probably bikeshedding here.

>  int name_compare(const char *name1, size_t len1, const char *name2, size_t len2);
>  int cache_name_stage_compare(const char *name1, int len1, int stage1, const char *name2, int len2, int stage2);
>
> diff --git a/combine-diff.c b/combine-diff.c
> index 9228aebc16b..64d7aaf1710 100644
> --- a/combine-diff.c
> +++ b/combine-diff.c
> @@ -16,11 +16,13 @@
>  static int compare_paths(const struct combine_diff_path *one,
>                           const struct diff_filespec *two)
>  {
> -       if (!S_ISDIR(one->mode) && !S_ISDIR(two->mode))
> +       int isdir_one = S_ISDIR(one->mode);
> +       int isdir_two = S_ISDIR(two->mode);
> +       if (!isdir_one && !isdir_two)
>                 return strcmp(one->path, two->path);
>
> -       return base_name_compare(one->path, strlen(one->path), one->mode,
> -                                two->path, strlen(two->path), two->mode);
> +       return base_name_compare(one->path, strlen(one->path), isdir_one,
> +                                two->path, strlen(two->path), isdir_two);
>  }
>
>  static int filename_changed(char status)
> diff --git a/match-trees.c b/match-trees.c
> index 1011357ad0c..4d124a0fd1b 100644
> --- a/match-trees.c
> +++ b/match-trees.c
> @@ -67,8 +67,10 @@ static void *fill_tree_desc_strict(struct tree_desc *desc,
>  static int base_name_entries_compare(const struct name_entry *a,
>                                      const struct name_entry *b)
>  {
> -       return base_name_compare(a->path, tree_entry_len(a), a->mode,
> -                                b->path, tree_entry_len(b), b->mode);
> +       int isdira = a->object_type == OBJ_TREE;
> +       int isdirb = b->object_type == OBJ_TREE;
> +       return base_name_compare(a->path, tree_entry_len(a), isdira,
> +                                b->path, tree_entry_len(b), isdirb);
>  }
>
>  /*
> diff --git a/merge-ort.c b/merge-ort.c
> index 603d30c5217..4075d13aaab 100644
> --- a/merge-ort.c
> +++ b/merge-ort.c
> @@ -2390,8 +2390,8 @@ static int tree_entry_order(const void *a_, const void *b_)
>
>         const struct merged_info *ami = a->util;
>         const struct merged_info *bmi = b->util;
> -       return base_name_compare(a->string, strlen(a->string), ami->result.mode,
> -                                b->string, strlen(b->string), bmi->result.mode);
> +       return base_name_compare(a->string, strlen(a->string), S_ISDIR(ami->result.mode),
> +                                b->string, strlen(b->string), S_ISDIR(bmi->result.mode));
>  }
>
>  static void write_tree(struct object_id *result_oid,
> diff --git a/merge-recursive.c b/merge-recursive.c
> index 1593f374495..0baa6b5ca56 100644
> --- a/merge-recursive.c
> +++ b/merge-recursive.c
> @@ -554,12 +554,12 @@ static int string_list_df_name_compare(const char *one, const char *two)
>          *
>          * To achieve this, we sort with df_name_compare and provide
>          * the mode S_IFDIR so that D/F conflicts will sort correctly.
> -        * We use the mode S_IFDIR for everything else for simplicity,
> +        * We say we have a directory for everything else for simplicity,
>          * since in other cases any changes in their order due to
>          * sorting cause no problems for us.
>          */
> -       int cmp = df_name_compare(one, onelen, S_IFDIR,
> -                                 two, twolen, S_IFDIR);
> +       int cmp = df_name_compare(one, onelen, 1, two, twolen, 1);
> +
>         /*
>          * Now that 'foo' and 'foo/bar' compare equal, we have to make sure
>          * that 'foo' comes before 'foo/bar'.
> diff --git a/read-cache.c b/read-cache.c
> index 1e9a50c6c73..edfce1f0cb8 100644
> --- a/read-cache.c
> +++ b/read-cache.c
> @@ -462,8 +462,8 @@ int ie_modified(struct index_state *istate,
>         return 0;
>  }
>
> -int base_name_compare(const char *name1, int len1, int mode1,
> -                     const char *name2, int len2, int mode2)
> +int base_name_compare(const char *name1, int len1, int isdir1,
> +                     const char *name2, int len2, int isdir2)
>  {
>         unsigned char c1, c2;
>         int len = len1 < len2 ? len1 : len2;
> @@ -474,9 +474,9 @@ int base_name_compare(const char *name1, int len1, int mode1,
>                 return cmp;
>         c1 = name1[len];
>         c2 = name2[len];
> -       if (!c1 && S_ISDIR(mode1))
> +       if (!c1 && isdir1)
>                 c1 = '/';
> -       if (!c2 && S_ISDIR(mode2))
> +       if (!c2 && isdir2)
>                 c2 = '/';
>         return (c1 < c2) ? -1 : (c1 > c2) ? 1 : 0;
>  }
> @@ -491,8 +491,8 @@ int base_name_compare(const char *name1, int len1, int mode1,
>   * This is used by routines that want to traverse the git namespace
>   * but then handle conflicting entries together when possible.
>   */
> -int df_name_compare(const char *name1, int len1, int mode1,
> -                   const char *name2, int len2, int mode2)
> +int df_name_compare(const char *name1, int len1, int isdir1,
> +                   const char *name2, int len2, int isdir2)
>  {
>         int len = len1 < len2 ? len1 : len2, cmp;
>         unsigned char c1, c2;
> @@ -504,10 +504,10 @@ int df_name_compare(const char *name1, int len1, int mode1,
>         if (len1 == len2)
>                 return 0;
>         c1 = name1[len];
> -       if (!c1 && S_ISDIR(mode1))
> +       if (!c1 && isdir1)
>                 c1 = '/';
>         c2 = name2[len];
> -       if (!c2 && S_ISDIR(mode2))
> +       if (!c2 && isdir2)
>                 c2 = '/';
>         if (c1 == '/' && !c2)
>                 return 0;
> diff --git a/tree-diff.c b/tree-diff.c
> index 7cebbb327e2..f133834597c 100644
> --- a/tree-diff.c
> +++ b/tree-diff.c
> @@ -50,6 +50,7 @@ static int tree_entry_pathcmp(struct tree_desc *t1, struct tree_desc *t2)
>  {
>         struct name_entry *e1, *e2;
>         int cmp;
> +       int e1_is_tree, e2_is_tree;
>
>         /* empty descriptors sort after valid tree entries */
>         if (!t1->size)
> @@ -58,9 +59,11 @@ static int tree_entry_pathcmp(struct tree_desc *t1, struct tree_desc *t2)
>                 return -1;
>
>         e1 = &t1->entry;
> +       e1_is_tree = e1->object_type == OBJ_TREE;

This would read slightly clearer with parenthesis around the right hand side.

>         e2 = &t2->entry;
> -       cmp = base_name_compare(e1->path, tree_entry_len(e1), e1->mode,
> -                               e2->path, tree_entry_len(e2), e2->mode);
> +       e2_is_tree = e2->object_type == OBJ_TREE;

Same.

> +       cmp = base_name_compare(e1->path, tree_entry_len(e1), e1_is_tree,
> +                               e2->path, tree_entry_len(e2), e2_is_tree);
>         return cmp;
>  }
>
> diff --git a/unpack-trees.c b/unpack-trees.c
> index f5f668f532d..802f7771d75 100644
> --- a/unpack-trees.c
> +++ b/unpack-trees.c
> @@ -922,7 +922,7 @@ static int traverse_trees_recursive(int n, unsigned long dirmask,
>  static int do_compare_entry_piecewise(const struct cache_entry *ce,
>                                       const struct traverse_info *info,
>                                       const char *name, size_t namelen,
> -                                     unsigned mode)
> +                                     unsigned is_tree)

isdir elsewhere and is_tree here?  ;-)

>  {
>         int pathlen, ce_len;
>         const char *ce_name;
> @@ -930,7 +930,7 @@ static int do_compare_entry_piecewise(const struct cache_entry *ce,
>         if (info->prev) {
>                 int cmp = do_compare_entry_piecewise(ce, info->prev,
>                                                      info->name, info->namelen,
> -                                                    info->mode);
> +                                                    S_ISDIR(info->mode));
>                 if (cmp)
>                         return cmp;
>         }
> @@ -944,13 +944,13 @@ static int do_compare_entry_piecewise(const struct cache_entry *ce,
>         ce_len -= pathlen;
>         ce_name = ce->name + pathlen;
>
> -       return df_name_compare(ce_name, ce_len, S_IFREG, name, namelen, mode);
> +       return df_name_compare(ce_name, ce_len, 0, name, namelen, is_tree);
>  }
>
>  static int do_compare_entry(const struct cache_entry *ce,
>                             const struct traverse_info *info,
>                             const char *name, size_t namelen,
> -                           unsigned mode)
> +                           unsigned is_tree)
>  {
>         int pathlen, ce_len;
>         const char *ce_name;
> @@ -962,7 +962,7 @@ static int do_compare_entry(const struct cache_entry *ce,
>          * it is quicker to use the precomputed version.
>          */
>         if (!info->traverse_path)
> -               return do_compare_entry_piecewise(ce, info, name, namelen, mode);
> +               return do_compare_entry_piecewise(ce, info, name, namelen, is_tree);
>
>         cmp = strncmp(ce->name, info->traverse_path, info->pathlen);
>         if (cmp)
> @@ -977,12 +977,13 @@ static int do_compare_entry(const struct cache_entry *ce,
>         ce_len -= pathlen;
>         ce_name = ce->name + pathlen;
>
> -       return df_name_compare(ce_name, ce_len, S_IFREG, name, namelen, mode);
> +       return df_name_compare(ce_name, ce_len, 0, name, namelen, is_tree);
>  }
>
>  static int compare_entry(const struct cache_entry *ce, const struct traverse_info *info, const struct name_entry *n)
>  {
> -       int cmp = do_compare_entry(ce, info, n->path, n->pathlen, n->mode);
> +       int is_tree = n->object_type == OBJ_TREE;

Another place where parentheses would speed my reading comprehension
just slightly.


> +       int cmp = do_compare_entry(ce, info, n->path, n->pathlen, is_tree);
>         if (cmp)
>                 return cmp;
>
> --
> 2.31.0.rc0.126.g04f22c5b82

^ permalink raw reply	[flat|nested] 262+ messages in thread

* Re: [PATCH 09/30] tree.h users: format argument lists in archive.c
  2021-03-08 15:06     ` [PATCH 09/30] tree.h users: format argument lists in archive.c Ævar Arnfjörð Bjarmason
@ 2021-03-09 17:04       ` Elijah Newren
  0 siblings, 0 replies; 262+ messages in thread
From: Elijah Newren @ 2021-03-09 17:04 UTC (permalink / raw)
  To: Ævar Arnfjörð Bjarmason
  Cc: Git Mailing List, Junio C Hamano, Kirill Smelkov,
	Nguyễn Thái Ngọc Duy

On Mon, Mar 8, 2021 at 7:07 AM Ævar Arnfjörð Bjarmason <avarab@gmail.com> wrote:
>
> Re-indent and re-flow the argument lists archive.c has downstream of
> its read_tree_recursive() call to make subsequent commits easier to
> read, as I only expect to be modifying the "stage" and "mode" lines.
>
> Signed-off-by: Ævar Arnfjörð Bjarmason <avarab@gmail.com>
> ---
>  archive.c | 25 +++++++++++++++++--------
>  1 file changed, 17 insertions(+), 8 deletions(-)
>
> diff --git a/archive.c b/archive.c
> index db69a8acadb..e245c0d5a54 100644
> --- a/archive.c
> +++ b/archive.c
> @@ -140,7 +140,8 @@ static int check_attr_export_subst(const struct attr_check *check)
>  static int write_archive_entry(const struct object_id *oid, const char *base,
>                                int baselen, const char *filename,
>                                unsigned mode,
> -                              int stage, void *context)
> +                              int stage,
> +                              void *context)

You just barely changed this function signature in the previous patch
to split long lines, but left stage & context on the same line.  It
seems like this change should be squashed into the previous patch.

>  {
>         static struct strbuf path = STRBUF_INIT;
>         struct archiver_context *c = context;
> @@ -197,8 +198,10 @@ static int write_archive_entry(const struct object_id *oid, const char *base,
>  }
>
>  static void queue_directory(const unsigned char *sha1,
> -               struct strbuf *base, const char *filename,
> -               unsigned mode, int stage, struct archiver_context *c)
> +                           struct strbuf *base, const char *filename,
> +                           unsigned mode,
> +                           int stage,
> +                           struct archiver_context *c)
>  {
>         struct directory *d;
>         size_t len = st_add4(base->len, 1, strlen(filename), 1);
> @@ -224,8 +227,10 @@ static int write_directory(struct archiver_context *c)
>         ret =
>                 write_directory(c) ||
>                 write_archive_entry(&d->oid, d->path, d->baselen,
> -                                   d->path + d->baselen, d->mode,
> -                                   d->stage, c) != READ_TREE_RECURSIVE;
> +                                   d->path + d->baselen,
> +                                   d->mode,
> +                                   d->stage,
> +                                   c) != READ_TREE_RECURSIVE;
>         free(d);
>         return ret ? -1 : 0;
>  }
> @@ -259,14 +264,18 @@ static int queue_or_write_archive_entry(const struct object_id *oid,
>                 if (check_attr_export_ignore(check))
>                         return 0;
>                 queue_directory(oid->hash, base, filename,
> -                               mode, stage, c);
> +                               mode,
> +                               stage,
> +                               c);
>                 return READ_TREE_RECURSIVE;
>         }
>
>         if (write_directory(c))
>                 return -1;
> -       return write_archive_entry(oid, base->buf, base->len, filename, mode,
> -                                  stage, context);
> +       return write_archive_entry(oid, base->buf, base->len, filename,
> +                                  mode,
> +                                  stage,
> +                                  context);
>  }
>
>  struct extra_file_info {
> --
> 2.31.0.rc0.126.g04f22c5b82
>

^ permalink raw reply	[flat|nested] 262+ messages in thread

* Re: [PATCH 12/30] tree-walk.h users: migrate "p->mode &&" pattern
  2021-03-08 15:06     ` [PATCH 12/30] tree-walk.h users: migrate "p->mode &&" pattern Ævar Arnfjörð Bjarmason
@ 2021-03-09 17:09       ` Elijah Newren
  0 siblings, 0 replies; 262+ messages in thread
From: Elijah Newren @ 2021-03-09 17:09 UTC (permalink / raw)
  To: Ævar Arnfjörð Bjarmason
  Cc: Git Mailing List, Junio C Hamano, Kirill Smelkov,
	Nguyễn Thái Ngọc Duy

On Mon, Mar 8, 2021 at 7:07 AM Ævar Arnfjörð Bjarmason <avarab@gmail.com> wrote:
>
> Change code that dpends on "p->mode" either being a valid mode or zero

s/dpends/depends/

> to use a p->object_type comparison to "OBJ_NONE".
>
> The object_type() function in cache.h will not return OBJ_NONE, but in
> this these API users are implicitly relying on the memzero() that
> happens in setup_traverse_info().

This is a bit hard to parse.  Perhaps just remove "in this"?

> Since OBJ_NONE is "0" we can also rely on that being zero'd out here,
> along with the rest of the structure. I think this is slightly less
> clever than "mode not set", and helps to get rid of more uses of
> "mode".
>
> Signed-off-by: Ævar Arnfjörð Bjarmason <avarab@gmail.com>
> ---
>  builtin/merge-tree.c | 9 +++++----
>  merge-ort.c          | 2 +-
>  unpack-trees.c       | 4 ++--
>  3 files changed, 8 insertions(+), 7 deletions(-)
>
> diff --git a/builtin/merge-tree.c b/builtin/merge-tree.c
> index de8520778d2..2de34c2d485 100644
> --- a/builtin/merge-tree.c
> +++ b/builtin/merge-tree.c
> @@ -214,7 +214,7 @@ static void unresolved_directory(const struct traverse_info *info,
>         void *buf0, *buf1, *buf2;
>
>         for (p = n; p < n + 3; p++) {
> -               if (p->mode && S_ISDIR(p->mode))
> +               if (p->object_type == OBJ_TREE)
>                         break;
>         }
>         if (n + 3 <= p)
> @@ -222,7 +222,7 @@ static void unresolved_directory(const struct traverse_info *info,
>
>         newbase = traverse_path(info, p);
>
> -#define ENTRY_OID(e) (((e)->mode && S_ISDIR((e)->mode)) ? &(e)->oid : NULL)
> +#define ENTRY_OID(e) (((e)->object_type == OBJ_TREE) ? &(e)->oid : NULL)
>         buf0 = fill_tree_descriptor(r, t + 0, ENTRY_OID(n + 0));
>         buf1 = fill_tree_descriptor(r, t + 1, ENTRY_OID(n + 1));
>         buf2 = fill_tree_descriptor(r, t + 2, ENTRY_OID(n + 2));
> @@ -242,7 +242,7 @@ static struct merge_list *link_entry(unsigned stage, const struct traverse_info
>         const char *path;
>         struct merge_list *link;
>
> -       if (!n->mode)
> +       if (n->object_type == OBJ_NONE)
>                 return entry;
>         if (entry)
>                 path = entry->path;
> @@ -265,7 +265,8 @@ static void unresolved(const struct traverse_info *info, struct name_entry n[3])
>                  * Treat missing entries as directories so that we return
>                  * after unresolved_directory has handled this.
>                  */
> -               if (!n[i].mode || S_ISDIR(n[i].mode))
> +               if (n[i].object_type == OBJ_NONE ||
> +                   n[i].object_type == OBJ_TREE)
>                         dirmask |= (1 << i);
>         }
>
> diff --git a/merge-ort.c b/merge-ort.c
> index 4075d13aaab..4375027914c 100644
> --- a/merge-ort.c
> +++ b/merge-ort.c
> @@ -668,7 +668,7 @@ static int collect_merge_info_callback(int n,
>          * setup_path_info() for tracking.
>          */
>         p = names;
> -       while (!p->mode)
> +       while (p->object_type == OBJ_NONE)
>                 p++;
>         len = traverse_path_len(info, p->pathlen);
>
> diff --git a/unpack-trees.c b/unpack-trees.c
> index 802f7771d75..92105135522 100644
> --- a/unpack-trees.c
> +++ b/unpack-trees.c
> @@ -859,7 +859,7 @@ static int traverse_trees_recursive(int n, unsigned long dirmask,
>         }
>
>         p = names;
> -       while (!p->mode)
> +       while (p->object_type == OBJ_NONE)
>                 p++;
>
>         newinfo = *info;
> @@ -1239,7 +1239,7 @@ static int unpack_callback(int n, unsigned long mask, unsigned long dirmask, str
>         const struct name_entry *p = names;
>
>         /* Find first entry with a real name (we could use "mask" too) */
> -       while (!p->mode)
> +       while (p->object_type == OBJ_NONE)
>                 p++;
>
>         if (o->debug_unpack)
> --
> 2.31.0.rc0.126.g04f22c5b82

^ permalink raw reply	[flat|nested] 262+ messages in thread

* Re: [PATCH 13/30] tree-walk.h users: refactor chained "mode" if/else into switch
  2021-03-08 15:06     ` [PATCH 13/30] tree-walk.h users: refactor chained "mode" if/else into switch Ævar Arnfjörð Bjarmason
@ 2021-03-09 17:11       ` Elijah Newren
  0 siblings, 0 replies; 262+ messages in thread
From: Elijah Newren @ 2021-03-09 17:11 UTC (permalink / raw)
  To: Ævar Arnfjörð Bjarmason
  Cc: Git Mailing List, Junio C Hamano, Kirill Smelkov,
	Nguyễn Thái Ngọc Duy

On Mon, Mar 8, 2021 at 7:07 AM Ævar Arnfjörð Bjarmason <avarab@gmail.com> wrote:
>
> Refactor a couple of "switch" statements that previously relied on
> "entry.mode" to switch on "entry.object_type" instead.
>
> This is more obvious, and allows us to explicitly handle all the OBJ_*
> cases, not just have a wildcard "else". That doesn't matter for the
> behavior of this code, but for its readability and maintainability.
>
> Signed-off-by: Ævar Arnfjörð Bjarmason <avarab@gmail.com>
> ---
>  list-objects.c | 20 ++++++++++++++------
>  walker.c       | 22 +++++++++++++---------
>  2 files changed, 27 insertions(+), 15 deletions(-)
>
> diff --git a/list-objects.c b/list-objects.c
> index e19589baa04..37434ba89d3 100644
> --- a/list-objects.c
> +++ b/list-objects.c
> @@ -111,6 +111,9 @@ static void process_tree_contents(struct traversal_context *ctx,
>         init_tree_desc(&desc, tree->buffer, tree->size);
>
>         while (tree_entry(&desc, &entry)) {
> +               struct tree *t;
> +               struct blob *b;
> +
>                 if (match != all_entries_interesting) {
>                         match = tree_entry_interesting(ctx->revs->repo->index,
>                                                        &entry, base, 0,
> @@ -121,8 +124,9 @@ static void process_tree_contents(struct traversal_context *ctx,
>                                 continue;
>                 }
>
> -               if (S_ISDIR(entry.mode)) {
> -                       struct tree *t = lookup_tree(ctx->revs->repo, &entry.oid);
> +               switch (entry.object_type) {
> +               case OBJ_TREE:
> +                       t = lookup_tree(ctx->revs->repo, &entry.oid);
>                         if (!t) {
>                                 die(_("entry '%s' in tree %s has tree mode, "
>                                       "but is not a tree"),
> @@ -130,12 +134,13 @@ static void process_tree_contents(struct traversal_context *ctx,
>                         }
>                         t->object.flags |= NOT_USER_GIVEN;
>                         process_tree(ctx, t, base, entry.path);
> -               }
> -               else if (S_ISGITLINK(entry.mode))
> +                       break;
> +               case OBJ_COMMIT:
>                         process_gitlink(ctx, entry.oid.hash,
>                                         base, entry.path);
> -               else {
> -                       struct blob *b = lookup_blob(ctx->revs->repo, &entry.oid);
> +                       break;
> +               case OBJ_BLOB:
> +                       b = lookup_blob(ctx->revs->repo, &entry.oid);
>                         if (!b) {
>                                 die(_("entry '%s' in tree %s has blob mode, "
>                                       "but is not a blob"),
> @@ -143,6 +148,9 @@ static void process_tree_contents(struct traversal_context *ctx,
>                         }
>                         b->object.flags |= NOT_USER_GIVEN;
>                         process_blob(ctx, b, base, entry.path);
> +                       break;
> +               default:
> +                       BUG("unreachable");
>                 }
>         }
>  }
> diff --git a/walker.c b/walker.c
> index 4984bf8b3d6..7ba757244e6 100644
> --- a/walker.c
> +++ b/walker.c
> @@ -45,21 +45,25 @@ static int process_tree(struct walker *walker, struct tree *tree)
>         init_tree_desc(&desc, tree->buffer, tree->size);
>         while (tree_entry(&desc, &entry)) {
>                 struct object *obj = NULL;
> +               struct tree *tree;
> +               struct blob *blob;
>
> -               /* submodule commits are not stored in the superproject */
> -               if (S_ISGITLINK(entry.mode))
> +               switch (entry.object_type) {
> +               case OBJ_COMMIT:
> +                       /* submodule commits are not stored in the superproject */
>                         continue;
> -               if (S_ISDIR(entry.mode)) {
> -                       struct tree *tree = lookup_tree(the_repository,
> -                                                       &entry.oid);
> +               case OBJ_TREE:
> +                       tree = lookup_tree(the_repository, &entry.oid);
>                         if (tree)
>                                 obj = &tree->object;
> -               }
> -               else {
> -                       struct blob *blob = lookup_blob(the_repository,
> -                                                       &entry.oid);
> +                       break;
> +               case OBJ_BLOB:
> +                       blob = lookup_blob(the_repository, &entry.oid);
>                         if (blob)
>                                 obj = &blob->object;
> +                       break;
> +               default:
> +                       BUG("unreachable");
>                 }
>                 if (!obj || process(walker, obj))
>                         return -1;
> --
> 2.31.0.rc0.126.g04f22c5b82

This does make it nicer.  :-)

^ permalink raw reply	[flat|nested] 262+ messages in thread

* Re: [PATCH 15/30] merge-tree tests: test for the mode comparison in same_entry()
  2021-03-08 15:06     ` [PATCH 15/30] merge-tree tests: test for the mode comparison in same_entry() Ævar Arnfjörð Bjarmason
@ 2021-03-09 17:19       ` Elijah Newren
  0 siblings, 0 replies; 262+ messages in thread
From: Elijah Newren @ 2021-03-09 17:19 UTC (permalink / raw)
  To: Ævar Arnfjörð Bjarmason
  Cc: Git Mailing List, Junio C Hamano, Kirill Smelkov,
	Nguyễn Thái Ngọc Duy

On Mon, Mar 8, 2021 at 7:07 AM Ævar Arnfjörð Bjarmason <avarab@gmail.com> wrote:
>
> Add a test to stress the "a->mode == b->mode" comparison in
> merge-tree.c's same_entry().

I can't remember now; did you remove the preliminary canon_mode()?  If
so, does this check actually need to be generalized?

For example, if someone has a git repository where a mode on a file in
one part of history is 100666, and on the other is 100644, then the
equality comparison no longer is satisfied because the modes haven't
been canonicalized.  Yet it's clear how the merge-tree should resolve
it -- both are regular, non-executable files, so the merged mode
should be 100644.

> That code was initially added by Linus in 33deb63a36f (Add
> "merge-tree" helper program. Maybe it's retarded, maybe it's helpful.,
> 2005-04-14), and then again in its current form in
> 492e0759bfe (Handling large files with GIT, 2006-02-14).
>
> However, nothing was testing that we handled this case
> correctly. Simply removing the mode comparison left all tests passing,
> but as seen here it's important that we don't think a path with the
> same content but different modes is the same_entry().
>
> The rest of this series will touch code that's relevant to this, but
> won't change its behavior. This test is just something I came up with
> in testing whether the mode test in same_entry() was needed at all.
>
> Signed-off-by: Ævar Arnfjörð Bjarmason <avarab@gmail.com>
> ---
>  t/t4300-merge-tree.sh | 44 +++++++++++++++++++++++++++++++++++++++++++
>  1 file changed, 44 insertions(+)
>
> diff --git a/t/t4300-merge-tree.sh b/t/t4300-merge-tree.sh
> index e59601e5fe9..f783d784d02 100755
> --- a/t/t4300-merge-tree.sh
> +++ b/t/t4300-merge-tree.sh
> @@ -40,6 +40,25 @@ test_expect_success 'file add A, B (same)' '
>         test_must_be_empty actual
>  '
>
> +test_expect_success 'file add A, B (different mode)' '
> +       git reset --hard initial &&
> +       test_commit "add-a-b-same-diff-mode-A" "ONE" "AAA" &&
> +       git reset --hard initial &&
> +       echo AAA >ONE &&
> +       test_chmod +x ONE &&
> +       test_tick &&
> +       git commit -m"add-a-b-same-diff-mode-B" &&
> +       git tag "add-a-b-same-diff-mode-B" HEAD &&
> +       git merge-tree initial add-a-b-same-diff-mode-A add-a-b-same-diff-mode-B >actual &&
> +       cat >expected <<EXPECTED &&
> +added in both
> +  our    100644 $(git rev-parse add-a-b-same-diff-mode-A:ONE) ONE
> +  their  100755 $(git rev-parse add-a-b-same-diff-mode-B:ONE) ONE
> +EXPECTED
> +
> +       test_cmp expected actual
> +'
> +
>  test_expect_success 'file add A, B (different)' '
>         git reset --hard initial &&
>         test_commit "add-a-b-diff-A" "ONE" "AAA" &&
> @@ -61,6 +80,31 @@ EXPECTED
>         test_cmp expected actual
>  '
>
> +test_expect_success 'file add A, B (different and different mode)' '
> +       git reset --hard initial &&
> +       test_commit "add-a-b-diff-diff-mode-A" "ONE" "AAA" &&
> +       git reset --hard initial &&
> +       echo BBB >ONE &&
> +       test_chmod +x ONE &&
> +       test_tick &&
> +       git commit -m"add-a-b-diff-diff-mode-B" &&
> +       git tag "add-a-b-diff-diff-mode-B" &&
> +       git merge-tree initial add-a-b-diff-diff-mode-A add-a-b-diff-diff-mode-B >actual &&
> +       cat >expected <<EXPECTED &&
> +added in both
> +  our    100644 $(git rev-parse add-a-b-diff-diff-mode-A:ONE) ONE
> +  their  100755 $(git rev-parse add-a-b-diff-diff-mode-B:ONE) ONE
> +@@ -1 +1,5 @@
> ++<<<<<<< .our
> + AAA
> ++=======
> ++BBB
> ++>>>>>>> .their
> +EXPECTED
> +
> +       test_cmp expected actual
> +'
> +
>  test_expect_success 'file change A, !B' '
>         git reset --hard initial &&
>         test_commit "change-a-not-b" "initial-file" "BBB" &&
> --
> 2.31.0.rc0.126.g04f22c5b82

^ permalink raw reply	[flat|nested] 262+ messages in thread

* Re: [PATCH 16/30] merge-ort: correct reference to test in 62fdec17a11
  2021-03-08 15:06     ` [PATCH 16/30] merge-ort: correct reference to test in 62fdec17a11 Ævar Arnfjörð Bjarmason
@ 2021-03-09 17:22       ` Elijah Newren
  0 siblings, 0 replies; 262+ messages in thread
From: Elijah Newren @ 2021-03-09 17:22 UTC (permalink / raw)
  To: Ævar Arnfjörð Bjarmason
  Cc: Git Mailing List, Junio C Hamano, Kirill Smelkov,
	Nguyễn Thái Ngọc Duy

On Mon, Mar 8, 2021 at 7:07 AM Ævar Arnfjörð Bjarmason <avarab@gmail.com> wrote:
>
> Fix a comment added in 62fdec17a11 (merge-ort: flesh out
> implementation of handle_content_merge(), 2021-01-01).
>
> The test being referred to here was moved from t6036 in
> 919df319555 (Collect merge-related tests to t64xx, 2020-08-10).
>
> It has also had the plural of "mode" in the name ever since being
> introduced in 5d1daf30cce (t6036: add a failed conflict detection
> case: regular files, different modes, 2018-06-30).
>
> Signed-off-by: Ævar Arnfjörð Bjarmason <avarab@gmail.com>
> ---
>  merge-ort.c | 2 +-
>  1 file changed, 1 insertion(+), 1 deletion(-)
>
> diff --git a/merge-ort.c b/merge-ort.c
> index 4375027914c..e54be179bd5 100644
> --- a/merge-ort.c
> +++ b/merge-ort.c
> @@ -1079,7 +1079,7 @@ static int handle_content_merge(struct merge_options *opt,
>                 /*
>                  * FIXME: If opt->priv->call_depth && !clean, then we really
>                  * should not make result->mode match either a->mode or
> -                * b->mode; that causes t6036 "check conflicting mode for
> +                * b->mode; that causes t6416 "check conflicting modes for
>                  * regular file" to fail.  It would be best to use some other
>                  * mode, but we'll confuse all kinds of stuff if we use one
>                  * where S_ISREG(result->mode) isn't true, and if we use
> --
> 2.31.0.rc0.126.g04f22c5b82

Oops.  Thanks for cleaning this up.

^ permalink raw reply	[flat|nested] 262+ messages in thread

* Re: [PATCH 21/30] tree-walk.h API users: use "tmp" for mode in shift_tree_by()
  2021-03-08 15:06     ` [PATCH 21/30] tree-walk.h API users: use "tmp" for mode in shift_tree_by() Ævar Arnfjörð Bjarmason
@ 2021-03-09 17:47       ` Elijah Newren
  0 siblings, 0 replies; 262+ messages in thread
From: Elijah Newren @ 2021-03-09 17:47 UTC (permalink / raw)
  To: Ævar Arnfjörð Bjarmason
  Cc: Git Mailing List, Junio C Hamano, Kirill Smelkov,
	Nguyễn Thái Ngọc Duy

On Mon, Mar 8, 2021 at 7:07 AM Ævar Arnfjörð Bjarmason <avarab@gmail.com> wrote:

Since there's only one API user, shouldn't the subject be
"match-trees: use tmp..." instead of "tree-walk.h API users: use
tmp..." ?

>
> Refactor code added in 85e51b783c3 (Make "subtree" part more
> orthogonal to the rest of merge-recursive., 2008-06-30) to make it
> obvious that we don't care about the "mode" here outside of the if
> statement it appears in.
>
> That's opposed to the sub1 & sub2 variables, where we use the two
> object ids later in this function.
>
> Signed-off-by: Ævar Arnfjörð Bjarmason <avarab@gmail.com>
> ---
>  match-trees.c | 10 +++++-----
>  1 file changed, 5 insertions(+), 5 deletions(-)
>
> diff --git a/match-trees.c b/match-trees.c
> index ba4aabf39d1..4f02768c01e 100644
> --- a/match-trees.c
> +++ b/match-trees.c
> @@ -317,17 +317,17 @@ void shift_tree_by(struct repository *r,
>                    const char *shift_prefix)
>  {
>         struct object_id sub1, sub2;
> -       unsigned short mode1, mode2;
> +       unsigned short tmp;
>         unsigned candidate = 0;
>
>         /* Can hash2 be a tree at shift_prefix in tree hash1? */
> -       if (!get_tree_entry_mode(r, hash1, shift_prefix, &sub1, &mode1) &&
> -           S_ISDIR(mode1))
> +       if (!get_tree_entry_mode(r, hash1, shift_prefix, &sub1, &tmp) &&
> +           S_ISDIR(tmp))
>                 candidate |= 1;
>
>         /* Can hash1 be a tree at shift_prefix in tree hash2? */
> -       if (!get_tree_entry_mode(r, hash2, shift_prefix, &sub2, &mode2) &&
> -           S_ISDIR(mode2))
> +       if (!get_tree_entry_mode(r, hash2, shift_prefix, &sub2, &tmp) &&
> +           S_ISDIR(tmp))
>                 candidate |= 2;
>
>         if (candidate == 3) {
> --
> 2.31.0.rc0.126.g04f22c5b82

^ permalink raw reply	[flat|nested] 262+ messages in thread

* Re: [PATCH 22/30] tree-walk.h API: Add get_tree_entry_type()
  2021-03-08 15:06     ` [PATCH 22/30] tree-walk.h API: Add get_tree_entry_type() Ævar Arnfjörð Bjarmason
@ 2021-03-09 17:56       ` Elijah Newren
  0 siblings, 0 replies; 262+ messages in thread
From: Elijah Newren @ 2021-03-09 17:56 UTC (permalink / raw)
  To: Ævar Arnfjörð Bjarmason
  Cc: Git Mailing List, Junio C Hamano, Kirill Smelkov,
	Nguyễn Thái Ngọc Duy

On Mon, Mar 8, 2021 at 7:07 AM Ævar Arnfjörð Bjarmason <avarab@gmail.com> wrote:
>
> Add a get_tree_entry_type() helper function to compliment the existing
> get_tree_entry(). Move those users of get_tree_entry_type() who didn't
> care about the mode specifically, but just want to know whether the
> tree entry is one of OBJ_{BLOB,COMMIT,TREE} over to it.

You added not one but two new functions (get_tree_entry_all() is the
other); should probably call out both in the commit message.

>
> Signed-off-by: Ævar Arnfjörð Bjarmason <avarab@gmail.com>
> ---
>  archive.c     |  8 ++++----
>  blame.c       |  8 ++++----
>  match-trees.c | 10 +++++-----
>  tree-walk.c   | 47 ++++++++++++++++++++++++++++++++++++-----------
>  tree-walk.h   | 15 +++++++++++++--
>  5 files changed, 62 insertions(+), 26 deletions(-)
>
> diff --git a/archive.c b/archive.c
> index 95fa759e1fb..bc8f1c7546f 100644
> --- a/archive.c
> +++ b/archive.c
> @@ -479,14 +479,14 @@ static void parse_treeish_arg(const char **argv,
>
>         if (prefix) {
>                 struct object_id tree_oid;
> -               unsigned short mode;
> +               enum object_type object_type;
>                 int err;
>
> -               err = get_tree_entry_mode(ar_args->repo,
> +               err = get_tree_entry_type(ar_args->repo,
>                                           &tree->object.oid,
>                                           prefix, &tree_oid,
> -                                         &mode);
> -               if (err || !S_ISDIR(mode))
> +                                         &object_type);
> +               if (err || object_type != OBJ_TREE)
>                         die(_("current working directory is untracked"));
>
>                 tree = parse_tree_indirect(&tree_oid);
> diff --git a/blame.c b/blame.c
> index 9e0543e13d4..4944582dc3c 100644
> --- a/blame.c
> +++ b/blame.c
> @@ -101,11 +101,11 @@ static void verify_working_tree_path(struct repository *r,
>         for (parents = work_tree->parents; parents; parents = parents->next) {
>                 const struct object_id *commit_oid = &parents->item->object.oid;
>                 struct object_id blob_oid;
> -               unsigned short mode;
> -               int ret = get_tree_entry_mode(r, commit_oid, path, &blob_oid,
> -                                             &mode);
> +               enum object_type object_type;
> +               int ret = get_tree_entry_type(r, commit_oid, path, &blob_oid,
> +                                             &object_type);
>
> -               if (!ret && oid_object_info(r, &blob_oid, NULL) == OBJ_BLOB)
> +               if (!ret && object_type == OBJ_BLOB)

Testing my understanding -- does this mean that even before your patch
that the oid_object_info() call wasn't needed?  In particular, we
could have replaced it with something like (!S_ISGITLNK(mode) &&
(S_ISREG(mode) || S_ISLNK(mode)))?

>                         return;
>         }
>
> diff --git a/match-trees.c b/match-trees.c
> index 4f02768c01e..ce3f811ec04 100644
> --- a/match-trees.c
> +++ b/match-trees.c
> @@ -317,17 +317,17 @@ void shift_tree_by(struct repository *r,
>                    const char *shift_prefix)
>  {
>         struct object_id sub1, sub2;
> -       unsigned short tmp;
> +       enum object_type tmp;
>         unsigned candidate = 0;
>
>         /* Can hash2 be a tree at shift_prefix in tree hash1? */
> -       if (!get_tree_entry_mode(r, hash1, shift_prefix, &sub1, &tmp) &&
> -           S_ISDIR(tmp))
> +       if (!get_tree_entry_type(r, hash1, shift_prefix, &sub1, &tmp) &&
> +           tmp == OBJ_TREE)
>                 candidate |= 1;
>
>         /* Can hash1 be a tree at shift_prefix in tree hash2? */
> -       if (!get_tree_entry_mode(r, hash2, shift_prefix, &sub2, &tmp) &&
> -           S_ISDIR(tmp))
> +       if (!get_tree_entry_type(r, hash2, shift_prefix, &sub2, &tmp) &&
> +           tmp == OBJ_TREE)
>                 candidate |= 2;
>
>         if (candidate == 3) {
> diff --git a/tree-walk.c b/tree-walk.c
> index 7819ff3e0ec..0ad3d80593e 100644
> --- a/tree-walk.c
> +++ b/tree-walk.c
> @@ -561,7 +561,8 @@ struct dir_state {
>
>  static int find_tree_entry(struct repository *r, struct tree_desc *t,
>                            const char *name, struct object_id *result,
> -                          unsigned short *mode)
> +                          unsigned short *mode,
> +                          enum object_type *object_type)
>  {
>         int namelen = strlen(name);
>         while (t->size) {
> @@ -585,23 +586,24 @@ static int find_tree_entry(struct repository *r, struct tree_desc *t,
>                 }
>                 if (name[entrylen] != '/')
>                         continue;
> -               if (!S_ISDIR(*mode))
> +               if (*object_type != OBJ_TREE)
>                         break;
>                 if (++entrylen == namelen) {
>                         oidcpy(result, &oid);
>                         return 0;
>                 }
> -               return get_tree_entry_mode(r, &oid, name + entrylen, result,
> -                                          mode);
> +               return get_tree_entry_all(r, &oid, name + entrylen, result,
> +                                         mode, object_type);
>         }
>         return -1;
>  }
>
> -int get_tree_entry_mode(struct repository *r,
> -                       const struct object_id *tree_oid,
> -                       const char *name,
> -                       struct object_id *oid,
> -                       unsigned short *mode)
> +int get_tree_entry_all(struct repository *r,
> +                      const struct object_id *tree_oid,
> +                      const char *name,
> +                      struct object_id *oid,
> +                      unsigned short *mode,
> +                      enum object_type *object_type)
>  {
>         int retval;
>         void *tree;
> @@ -624,12 +626,34 @@ int get_tree_entry_mode(struct repository *r,
>                 struct tree_desc t;
>                 init_tree_desc(&t, tree, size);
>                 retval = find_tree_entry(r, &t, name, oid,
> -                                        mode);
> +                                        mode, object_type);
>         }
>         free(tree);
>         return retval;
>  }
>
> +int get_tree_entry_mode(struct repository *r,
> +                       const struct object_id *tree_oid,
> +                       const char *name,
> +                       struct object_id *oid,
> +                       unsigned short *mode)
> +{
> +       enum object_type object_type;
> +       return get_tree_entry_all(r, tree_oid, name, oid,
> +                                 mode, &object_type);
> +}
> +
> +int get_tree_entry_type(struct repository *r,
> +                       const struct object_id *tree_oid,
> +                       const char *name,
> +                       struct object_id *oid,
> +                       enum object_type *object_type)
> +{
> +       unsigned short mode;
> +       return get_tree_entry_all(r, tree_oid, name, oid,
> +                                 &mode, object_type);
> +}
> +
>  /*
>   * This is Linux's built-in max for the number of symlinks to follow.
>   * That limit, of course, does not affect git, but it's a reasonable
> @@ -674,6 +698,7 @@ enum get_oid_result get_tree_entry_follow_symlinks(struct repository *r,
>                 int find_result;
>                 char *first_slash;
>                 char *remainder = NULL;
> +               enum object_type object_type;
>
>                 if (!t.buffer) {
>                         void *tree;
> @@ -751,7 +776,7 @@ enum get_oid_result get_tree_entry_follow_symlinks(struct repository *r,
>                 /* Look up the first (or only) path component in the tree. */
>                 find_result = find_tree_entry(r, &t, namebuf.buf,
>                                               &current_tree_oid,
> -                                             mode);
> +                                             mode, &object_type);
>                 if (find_result) {
>                         goto done;
>                 }
> diff --git a/tree-walk.h b/tree-walk.h
> index eb9b9de6ccc..5db38fcb575 100644
> --- a/tree-walk.h
> +++ b/tree-walk.h
> @@ -171,12 +171,23 @@ struct traverse_info {
>   * Find an entry in a tree given a pathname and the sha1 of a tree to
>   * search. Returns 0 if the entry is found and -1 otherwise.
>   *
> - * The third and fourth parameters are set to the entry's sha1 and
> - * mode respectively.
> + * There are variants of this function depending on what fields in the
> + * "struct name_entry" you'd like. You always need to pointer to an

s/to pointer to an/a pointer to an/ ?

> + * appropriate variable to fill in (NULL won't do!):
> + *
> + * get_tree_entry_mode(): unsigned int mode
> + * get_tree_entry_type(): enum object_type
> + * get_tree_entry_all(): unsigned int mode, enum object_type
>   */
>  int get_tree_entry_mode(struct repository *, const struct object_id *, const char *,
>                         struct object_id *,
>                         unsigned short *);
> +int get_tree_entry_type(struct repository *, const struct object_id *, const char *,
> +                       struct object_id *,
> +                       enum object_type *);
> +int get_tree_entry_all(struct repository *, const struct object_id *, const char *,
> +                      struct object_id *,
> +                      unsigned short *, enum object_type *);
>
>  /**
>   * Generate the full pathname of a tree entry based from the root of the
> --
> 2.31.0.rc0.126.g04f22c5b82
>

^ permalink raw reply	[flat|nested] 262+ messages in thread

* Re: [PATCH 23/30] tree-walk.h API: add a get_tree_entry_path() function
  2021-03-08 15:06     ` [PATCH 23/30] tree-walk.h API: add a get_tree_entry_path() function Ævar Arnfjörð Bjarmason
@ 2021-03-09 18:17       ` Elijah Newren
  0 siblings, 0 replies; 262+ messages in thread
From: Elijah Newren @ 2021-03-09 18:17 UTC (permalink / raw)
  To: Ævar Arnfjörð Bjarmason
  Cc: Git Mailing List, Junio C Hamano, Kirill Smelkov,
	Nguyễn Thái Ngọc Duy

On Mon, Mar 8, 2021 at 7:07 AM Ævar Arnfjörð Bjarmason <avarab@gmail.com> wrote:
>
> Add a get_tree_entry_path() variant in addition to
> get_tree_entry_path_{mode,type,all}(). This is for those callers that
> need neither the mode nor "enum object_type" parameters filled for
> them.
>
> There's callers here which doesn't need the "struct object_id" filled
> either, and provides a throwaway variable for us.

I think I understood this sentence, but perhaps we could reword it?
Something like:

There are callers here which don't need the "struct object_id" filled;
forcing callers to pass one just requires they create a throwaway
variable.

>
> See the following commits for the introduction of such code that's
> being modified here:
>
>  - shift_tree(): 68faf68938e (A new merge stragety 'subtree'.,
>     2007-02-15) for the shift_tree()

What a lovely commit.  I especially appreciate this gem:

"Heuristics galore!  That's the git way ;-)."

>
>  - tree_has_path(): 96e7ffbdc31 (merge-recursive: check for directory
>    level conflicts, 2018-04-19)
>
>  - init_notes(): fd53c9eb445 (Speed up git notes lookup, 2009-10-09)
>
>  - diagnose_invalid_oid_path(): 009fee4774d (Detailed diagnosis when
>    parsing an object name fails., 2009-12-07)
>
> Those could potentially be refactored too, but I've got to stop at
> some point, and right now I'm focusing downstream code that depends on
> "mode" (or "enum object_type").
>
> Signed-off-by: Ævar Arnfjörð Bjarmason <avarab@gmail.com>
> ---
>  match-trees.c     |  4 +---
>  merge-recursive.c |  6 ++----
>  notes.c           |  3 +--
>  object-name.c     |  3 +--
>  tree-walk.c       | 11 +++++++++++
>  tree-walk.h       |  3 +++
>  6 files changed, 19 insertions(+), 11 deletions(-)
>
> diff --git a/match-trees.c b/match-trees.c
> index ce3f811ec04..60a17b92d70 100644
> --- a/match-trees.c
> +++ b/match-trees.c
> @@ -288,12 +288,10 @@ void shift_tree(struct repository *r,
>
>         if (add_score < del_score) {
>                 /* We need to pick a subtree of two */
> -               unsigned short mode;
> -
>                 if (!*del_prefix)
>                         return;
>
> -               if (get_tree_entry_mode(r, hash2, del_prefix, shifted, &mode))
> +               if (get_tree_entry_path(r, hash2, del_prefix, shifted))
>                         die("cannot find path %s in tree %s",
>                             del_prefix, oid_to_hex(hash2));
>                 return;
> diff --git a/merge-recursive.c b/merge-recursive.c
> index 0e891360e7e..b26d9d418f9 100644
> --- a/merge-recursive.c
> +++ b/merge-recursive.c
> @@ -1884,11 +1884,9 @@ static int tree_has_path(struct repository *r, struct tree *tree,
>                          const char *path)
>  {
>         struct object_id hashy;
> -       unsigned short mode_o;
> -
> -       return !get_tree_entry_mode(r,
> +       return !get_tree_entry_path(r,
>                                     &tree->object.oid, path,
> -                                   &hashy, &mode_o);
> +                                   &hashy);

Poor Hashimoto has lost half his name and is now stuck with the
nickname of Hashy...  ;-)

(The mode was just a temporary and the name "mode_o" had no real
meaning; it was there just because I mis-remembered Quasimodo's name
at the time as Hashimodo and found "hashy mode_o" slightly amusing.)

>  }
>
>  /*
> diff --git a/notes.c b/notes.c
> index ef138606146..aa46cb2b09e 100644
> --- a/notes.c
> +++ b/notes.c
> @@ -994,7 +994,6 @@ void init_notes(struct notes_tree *t, const char *notes_ref,
>                 combine_notes_fn combine_notes, int flags)
>  {
>         struct object_id oid, object_oid;
> -       unsigned short mode;
>         struct leaf_node root_tree;
>
>         if (!t)
> @@ -1021,7 +1020,7 @@ void init_notes(struct notes_tree *t, const char *notes_ref,
>                 return;
>         if (flags & NOTES_INIT_WRITABLE && read_ref(notes_ref, &object_oid))
>                 die("Cannot use notes ref %s", notes_ref);
> -       if (get_tree_entry_mode(the_repository, &object_oid, "", &oid, &mode))
> +       if (get_tree_entry_path(the_repository, &object_oid, "", &oid))
>                 die("Failed to read notes tree referenced by %s (%s)",
>                     notes_ref, oid_to_hex(&object_oid));
>
> diff --git a/object-name.c b/object-name.c
> index 7e3b2d6d739..9ff5f83c1ff 100644
> --- a/object-name.c
> +++ b/object-name.c
> @@ -1693,7 +1693,6 @@ static void diagnose_invalid_oid_path(struct repository *r,
>                                       int object_name_len)
>  {
>         struct object_id oid;
> -       unsigned short mode;
>
>         if (!prefix)
>                 prefix = "";
> @@ -1704,7 +1703,7 @@ static void diagnose_invalid_oid_path(struct repository *r,
>         if (is_missing_file_error(errno)) {
>                 char *fullname = xstrfmt("%s%s", prefix, filename);
>
> -               if (!get_tree_entry_mode(r, tree_oid, fullname, &oid, &mode)) {
> +               if (!get_tree_entry_path(r, tree_oid, fullname, &oid)) {
>                         die(_("path '%s' exists, but not '%s'\n"
>                             "hint: Did you mean '%.*s:%s' aka '%.*s:./%s'?"),
>                             fullname,
> diff --git a/tree-walk.c b/tree-walk.c
> index 0ad3d80593e..83737634770 100644
> --- a/tree-walk.c
> +++ b/tree-walk.c
> @@ -632,6 +632,17 @@ int get_tree_entry_all(struct repository *r,
>         return retval;
>  }
>
> +int get_tree_entry_path(struct repository *r,
> +                       const struct object_id *tree_oid,
> +                       const char *name,
> +                       struct object_id *oid)
> +{
> +       unsigned short mode;
> +       enum object_type object_type;
> +       return get_tree_entry_all(r, tree_oid, name, oid,
> +                                 &mode, &object_type);
> +}
> +
>  int get_tree_entry_mode(struct repository *r,
>                         const struct object_id *tree_oid,
>                         const char *name,
> diff --git a/tree-walk.h b/tree-walk.h
> index 5db38fcb575..1bfa839b275 100644
> --- a/tree-walk.h
> +++ b/tree-walk.h
> @@ -175,10 +175,13 @@ struct traverse_info {
>   * "struct name_entry" you'd like. You always need to pointer to an
>   * appropriate variable to fill in (NULL won't do!):
>   *
> + * get_tree_entry_path(): <no extra argument, just get the common 'path'>
>   * get_tree_entry_mode(): unsigned int mode
>   * get_tree_entry_type(): enum object_type
>   * get_tree_entry_all(): unsigned int mode, enum object_type
>   */
> +int get_tree_entry_path(struct repository *, const struct object_id *, const char *,
> +                       struct object_id *);
>  int get_tree_entry_mode(struct repository *, const struct object_id *, const char *,
>                         struct object_id *,
>                         unsigned short *);
> --
> 2.31.0.rc0.126.g04f22c5b82

^ permalink raw reply	[flat|nested] 262+ messages in thread

* Re: [PATCH 24/30] tree-walk.h API: document and format tree_entry_extract()
  2021-03-08 15:06     ` [PATCH 24/30] tree-walk.h API: document and format tree_entry_extract() Ævar Arnfjörð Bjarmason
@ 2021-03-09 18:28       ` Elijah Newren
  0 siblings, 0 replies; 262+ messages in thread
From: Elijah Newren @ 2021-03-09 18:28 UTC (permalink / raw)
  To: Ævar Arnfjörð Bjarmason
  Cc: Git Mailing List, Junio C Hamano, Kirill Smelkov,
	Nguyễn Thái Ngọc Duy

On Mon, Mar 8, 2021 at 7:07 AM Ævar Arnfjörð Bjarmason <avarab@gmail.com> wrote:
>
> Document and format the argument list of the tree_entry_extract()
> function in preparation for adding a sister function.
>
> Signed-off-by: Ævar Arnfjörð Bjarmason <avarab@gmail.com>
> ---
>  tree-walk.h | 14 ++++++++++----
>  1 file changed, 10 insertions(+), 4 deletions(-)
>
> diff --git a/tree-walk.h b/tree-walk.h
> index 1bfa839b275..61fdcb166d2 100644
> --- a/tree-walk.h
> +++ b/tree-walk.h
> @@ -40,11 +40,17 @@ struct tree_desc {
>
>  /**
>   * Decode the entry currently being visited (the one pointed to by
> - * `tree_desc's` `entry` member) and return the sha1 of the entry. The
> - * `pathp` and `modep` arguments are set to the entry's pathname and mode
> - * respectively.
> + * `tree_desc's` `entry` member) and return the OID of the entry.
> +
> + * There are variants of this function depending on what fields in the
> + * "struct name_entry" you'd like. You always need to pointer to an

s/need to pointer/need a pointer/

> + * appropriate variable to fill in (NULL won't do!):
> + *
> + * tree_entry_extract_mode(): const char *path, unsigned int mode

Indenting this over slightly might make it easier to read

>   */
> -static inline const struct object_id *tree_entry_extract(struct tree_desc *desc, const char **pathp, unsigned short *modep)
> +static inline const struct object_id *tree_entry_extract(struct tree_desc *desc,
> +                                                        const char **pathp,
> +                                                        unsigned short *modep)
>  {
>         *pathp = desc->entry.path;
>         *modep = desc->entry.mode;
> --
> 2.31.0.rc0.126.g04f22c5b82
>

^ permalink raw reply	[flat|nested] 262+ messages in thread

* Re: [PATCH 26/30] tree-walk.h API: add a tree_entry_extract_all() function
  2021-03-08 15:06     ` [PATCH 26/30] tree-walk.h API: add a tree_entry_extract_all() function Ævar Arnfjörð Bjarmason
@ 2021-03-09 18:30       ` Elijah Newren
  0 siblings, 0 replies; 262+ messages in thread
From: Elijah Newren @ 2021-03-09 18:30 UTC (permalink / raw)
  To: Ævar Arnfjörð Bjarmason
  Cc: Git Mailing List, Junio C Hamano, Kirill Smelkov,
	Nguyễn Thái Ngọc Duy

On Mon, Mar 8, 2021 at 7:07 AM Ævar Arnfjörð Bjarmason <avarab@gmail.com> wrote:
>
> Add a tree_entry_extract_all() sibling function to the existing
> tree_entry_extract_mode().
>
> Having the OBJ_{BLOB,TREE,COMMIT} when you have the "mode" is strictly
> speaking redundant, but hopefully makes it easier to read the
> code. We'll now see which parts of the code are checking the types,
> v.s. those that care about the mode specifically.
>
> Only the first use of tree_entry_extract_mode() in emit_path() is
> converted here, the other branch will use a new
> get_tree_entry_mode_type() introduced in a subsequent commit.
>
> Signed-off-by: Ævar Arnfjörð Bjarmason <avarab@gmail.com>
> ---
>  builtin/update-index.c |  6 ++++--
>  tree-diff.c            |  5 +++--
>  tree-walk.c            |  3 ++-
>  tree-walk.h            | 12 ++++++++++++
>  4 files changed, 21 insertions(+), 5 deletions(-)
>
> diff --git a/builtin/update-index.c b/builtin/update-index.c
> index 070510d6a88..b489a876392 100644
> --- a/builtin/update-index.c
> +++ b/builtin/update-index.c
> @@ -599,16 +599,18 @@ static struct cache_entry *read_one_ent(const char *which,
>                                         struct object_id *ent, const char *path,
>                                         int namelen, int stage)
>  {
> +       enum object_type object_type;
>         unsigned short mode;
>         struct object_id oid;
>         struct cache_entry *ce;
>
> -       if (get_tree_entry_mode(the_repository, ent, path, &oid, &mode)) {
> +       if (get_tree_entry_all(the_repository, ent, path, &oid,
> +                              &mode, &object_type)) {
>                 if (which)
>                         error("%s: not in %s branch.", path, which);
>                 return NULL;
>         }
> -       if (mode == S_IFDIR) {
> +       if (object_type == OBJ_TREE) {
>                 if (which)
>                         error("%s: not a blob in %s branch.", path, which);
>                 return NULL;
> diff --git a/tree-diff.c b/tree-diff.c
> index b37348b7908..b25095c1164 100644
> --- a/tree-diff.c
> +++ b/tree-diff.c
> @@ -195,10 +195,11 @@ static struct combine_diff_path *emit_path(struct combine_diff_path *p,
>         assert(t || tp);
>
>         if (t) {
> +               enum object_type object_type;
>                 /* path present in resulting tree */
> -               oid = tree_entry_extract_mode(t, &path, &mode);
> +               oid = tree_entry_extract_all(t, &path, &mode, &object_type);
>                 pathlen = tree_entry_len(&t->entry);
> -               isdir = S_ISDIR(mode);
> +               isdir = object_type == OBJ_TREE;

Not worth a reroll, but parenthesis around the right-hand side would
make it a bit faster to parse and understand.

>         } else {
>                 /*
>                  * a path was removed - take path from imin parent. Also take
> diff --git a/tree-walk.c b/tree-walk.c
> index e613f273767..12e0ed4e250 100644
> --- a/tree-walk.c
> +++ b/tree-walk.c
> @@ -570,7 +570,8 @@ static int find_tree_entry(struct repository *r, struct tree_desc *t,
>                 struct object_id oid;
>                 int entrylen, cmp;
>
> -               oidcpy(&oid, tree_entry_extract_mode(t, &entry, mode));
> +               oidcpy(&oid, tree_entry_extract_all(t, &entry, mode, object_type));
> +
>                 entrylen = tree_entry_len(&t->entry);
>                 update_tree_entry(t);
>                 if (entrylen > namelen)
> diff --git a/tree-walk.h b/tree-walk.h
> index 892e77eda23..06ad40ab2f1 100644
> --- a/tree-walk.h
> +++ b/tree-walk.h
> @@ -47,6 +47,7 @@ struct tree_desc {
>   * appropriate variable to fill in (NULL won't do!):
>   *
>   * tree_entry_extract_mode(): const char *path, unsigned int mode
> + * tree_entry_extract_all(): const char *path, unsigned int mode, enum object_type
>   */
>  static inline const struct object_id *tree_entry_extract_mode(struct tree_desc *desc,
>                                                               const char **pathp,
> @@ -57,6 +58,17 @@ static inline const struct object_id *tree_entry_extract_mode(struct tree_desc *
>         return &desc->entry.oid;
>  }
>
> +static inline const struct object_id *tree_entry_extract_all(struct tree_desc *desc,
> +                                                            const char **pathp,
> +                                                            unsigned short *modep,
> +                                                            enum object_type *object_typep)
> +{
> +       *pathp = desc->entry.path;
> +       *modep = desc->entry.mode;
> +       *object_typep = desc->entry.object_type;
> +       return &desc->entry.oid;
> +}
> +
>  /**
>   * Calculate the length of a tree entry's pathname. This utilizes the
>   * memory structure of a tree entry to avoid the overhead of using a
> --
> 2.31.0.rc0.126.g04f22c5b82
>

^ permalink raw reply	[flat|nested] 262+ messages in thread

* Re: [PATCH 28/30] tree-walk.h API users: rename "struct name_entry"'s "mode" to "raw_mode"
  2021-03-08 15:06     ` [PATCH 28/30] tree-walk.h API users: rename "struct name_entry"'s "mode" to "raw_mode" Ævar Arnfjörð Bjarmason
@ 2021-03-09 18:53       ` Elijah Newren
  0 siblings, 0 replies; 262+ messages in thread
From: Elijah Newren @ 2021-03-09 18:53 UTC (permalink / raw)
  To: Ævar Arnfjörð Bjarmason
  Cc: Git Mailing List, Junio C Hamano, Kirill Smelkov,
	Nguyễn Thái Ngọc Duy

On Mon, Mar 8, 2021 at 7:07 AM Ævar Arnfjörð Bjarmason <avarab@gmail.com> wrote:
>
> Now that most of the users of the "mode" variable have been moved to
> use "object_type" instead let's rename it to "raw_mode" in preparation
> for a revert of 7146e66f086 (tree-walk: finally switch over tree
> descriptors to contain a pre-parsed entry, 2014-02-06).
>
> This will allow API users who care about the actual mode bits in tree
> objects to get access to them, such as fsck, the merge algorithm etc.

If you're going to feed the raw mode bits through to the merge
algorithm, then the merge algorithm logic needs to change in several
places to accommodate have raw modes instead of canonicalized modes.
I'm also curious what the other places are.  For example, will the
diff machinery show a diff now for files whose raw_mode differs even
if the canonicalized mode does not?  This would be a behavioral
change, but I'm getting ahead of myself since I should probably wait
until the subsequent patches to see what you did.

> But most users will not want to have such potentially un-sanitized, so
> let's indicate that by giving the variable a more scary name.
>
> I am not renaming the variables being assigned to, i.e. it's now going
> to be "int mode = entry.raw_mode", not "int raw_mode = [...]". This is
> because we're going to be getting a sanitized "mode" via
> "canon_mode()" in many of these functions soon, so renaming the local
> variable back and forth will result in needless churn.
>
> Signed-off-by: Ævar Arnfjörð Bjarmason <avarab@gmail.com>
> ---
>  builtin/merge-tree.c |  8 ++++----
>  match-trees.c        |  4 ++--
>  merge-ort.c          | 12 ++++++------
>  notes.c              |  2 +-
>  tree-diff.c          | 22 +++++++++++-----------
>  tree-walk.c          |  2 +-
>  tree-walk.h          |  6 +++---
>  tree.c               |  2 +-
>  unpack-trees.c       |  6 +++---
>  9 files changed, 32 insertions(+), 32 deletions(-)
>
> diff --git a/builtin/merge-tree.c b/builtin/merge-tree.c
> index eec5b906561..b4e736e4b72 100644
> --- a/builtin/merge-tree.c
> +++ b/builtin/merge-tree.c
> @@ -160,7 +160,7 @@ static int same_entry(struct name_entry *a, struct name_entry *b)
>         return  !is_null_oid(&a->oid) &&
>                 !is_null_oid(&b->oid) &&
>                 oideq(&a->oid, &b->oid) &&
> -               a->mode == b->mode;
> +               a->raw_mode == b->raw_mode;

This looks like a case that probably should operate on canonicalized modes.

>  }
>
>  static int both_empty(struct name_entry *a, struct name_entry *b)
> @@ -197,9 +197,9 @@ static void resolve(const struct traverse_info *info, struct name_entry *ours, s
>                 return;
>
>         path = traverse_path(info, result);
> -       orig_mode = ours->mode;
> +       orig_mode = ours->raw_mode;
>         orig = create_entry(2, orig_mode, &ours->oid, path);
> -       final_mode = result->mode;
> +       final_mode = result->raw_mode;
>         final = create_entry(0, final_mode, &result->oid, path);
>
>         final->link = orig;
> @@ -252,7 +252,7 @@ static struct merge_list *link_entry(unsigned stage, const struct traverse_info
>                 path = entry->path;
>         else
>                 path = traverse_path(info, n);
> -       link_mode = n->mode;
> +       link_mode = n->raw_mode;
>         link = create_entry(stage, link_mode, &n->oid, path);
>
>         link->link = entry;
> diff --git a/match-trees.c b/match-trees.c
> index 0636f6e58e9..d45c76ffa79 100644
> --- a/match-trees.c
> +++ b/match-trees.c
> @@ -86,8 +86,8 @@ static int score_trees(const struct object_id *hash1, const struct object_id *ha
>
>         for (;;) {
>                 int cmp;
> -               unsigned int one_mode = one.entry.mode;
> -               unsigned int two_mode = two.entry.mode;
> +               unsigned int one_mode = one.entry.raw_mode;
> +               unsigned int two_mode = two.entry.raw_mode;
>
>                 if (one.size && two.size)
>                         cmp = base_name_entries_compare(&one.entry, &two.entry);
> diff --git a/merge-ort.c b/merge-ort.c
> index cad10436504..ea20bbe2af3 100644
> --- a/merge-ort.c
> +++ b/merge-ort.c
> @@ -502,7 +502,7 @@ static void setup_path_info(struct merge_options *opt,
>         mi->basename_offset = current_dir_name_len;
>         mi->clean = !!resolved;
>         if (resolved) {
> -               mi->result.mode = merged_version->mode;
> +               mi->result.mode = merged_version->raw_mode;

This seems scary.

>                 oidcpy(&mi->result.oid, &merged_version->oid);
>                 mi->is_null = !!is_null;
>         } else {
> @@ -512,7 +512,7 @@ static void setup_path_info(struct merge_options *opt,
>                 ASSIGN_AND_VERIFY_CI(ci, mi);
>                 for (i = MERGE_BASE; i <= MERGE_SIDE2; i++) {
>                         ci->pathnames[i] = fullpath;
> -                       ci->stages[i].mode = names[i].mode;
> +                       ci->stages[i].mode = names[i].raw_mode;

likewise.

>                         oidcpy(&ci->stages[i].oid, &names[i].oid);
>                 }
>                 ci->filemask = filemask;
> @@ -545,7 +545,7 @@ static void add_pair(struct merge_options *opt,
>         struct rename_info *renames = &opt->priv->renames;
>         int names_idx = is_add ? side : 0;
>         const struct object_id *oid = &names[names_idx].oid;
> -       unsigned int mode = names[names_idx].mode;
> +       unsigned int mode = names[names_idx].raw_mode;
>
>         one = alloc_filespec(pathname);
>         two = alloc_filespec(pathname);
> @@ -616,13 +616,13 @@ static int collect_merge_info_callback(int n,
>         unsigned side1_null = !(mask & 2);
>         unsigned side2_null = !(mask & 4);
>         unsigned side1_matches_mbase = (!side1_null && !mbase_null &&
> -                                       names[0].mode == names[1].mode &&
> +                                       names[0].raw_mode == names[1].raw_mode &&
>                                         oideq(&names[0].oid, &names[1].oid));
>         unsigned side2_matches_mbase = (!side2_null && !mbase_null &&
> -                                       names[0].mode == names[2].mode &&
> +                                       names[0].raw_mode == names[2].raw_mode &&
>                                         oideq(&names[0].oid, &names[2].oid));
>         unsigned sides_match = (!side1_null && !side2_null &&
> -                               names[1].mode == names[2].mode &&
> +                               names[1].raw_mode == names[2].raw_mode &&
>                                 oideq(&names[1].oid, &names[2].oid));

If these three really start operating on the raw_mode, then this logic
will be wrong.  100644 and 100666 should be considered "equal and
matching" for the purposes used here.

>         /*
> diff --git a/notes.c b/notes.c
> index aa46cb2b09e..2817325651a 100644
> --- a/notes.c
> +++ b/notes.c
> @@ -478,7 +478,7 @@ static void load_subtree(struct notes_tree *t, struct leaf_node *subtree,
>                         struct strbuf non_note_path = STRBUF_INIT;
>                         const char *q = oid_to_hex(&subtree->key_oid);
>                         size_t i;
> -                       unsigned int mode = entry.mode;
> +                       unsigned int mode = entry.raw_mode;
>                         for (i = 0; i < prefix_len; i++) {
>                                 strbuf_addch(&non_note_path, *q++);
>                                 strbuf_addch(&non_note_path, *q++);
> diff --git a/tree-diff.c b/tree-diff.c
> index 10c92d39c42..df8301d806a 100644
> --- a/tree-diff.c
> +++ b/tree-diff.c
> @@ -232,7 +232,7 @@ static struct combine_diff_path *emit_path(struct combine_diff_path *p,
>                          * tp[i] is valid, if present and if tp[i]==tp[imin] -
>                          * otherwise, we should ignore it.
>                          */
> -                       int tpi_valid = tp && !(tp[i].entry.mode & S_IFXMIN_NEQ);
> +                       int tpi_valid = tp && !(tp[i].entry.raw_mode & S_IFXMIN_NEQ);
>
>                         const struct object_id *oid_i;
>                         unsigned mode_i;
> @@ -245,7 +245,7 @@ static struct combine_diff_path *emit_path(struct combine_diff_path *p,
>
>                         if (tpi_valid) {
>                                 oid_i = &tp[i].entry.oid;
> -                               mode_i = tp[i].entry.mode;
> +                               mode_i = tp[i].entry.raw_mode;

I don't know tree-diff enough but I'm wondering if it has similar
issues to merge-ort.

>                         }
>                         else {
>                                 oid_i = &null_oid;
> @@ -283,7 +283,7 @@ static struct combine_diff_path *emit_path(struct combine_diff_path *p,
>                 FAST_ARRAY_ALLOC(parents_oid, nparent);
>                 for (i = 0; i < nparent; ++i) {
>                         /* same rule as in emitthis */
> -                       int tpi_valid = tp && !(tp[i].entry.mode & S_IFXMIN_NEQ);
> +                       int tpi_valid = tp && !(tp[i].entry.raw_mode & S_IFXMIN_NEQ);
>
>                         parents_oid[i] = tpi_valid ? &tp[i].entry.oid : NULL;
>                 }
> @@ -404,7 +404,7 @@ static inline void update_tp_entries(struct tree_desc *tp, int nparent)
>  {
>         int i;
>         for (i = 0; i < nparent; ++i)
> -               if (!(tp[i].entry.mode & S_IFXMIN_NEQ))
> +               if (!(tp[i].entry.raw_mode & S_IFXMIN_NEQ))
>                         update_tree_entry(&tp[i]);
>  }
>
> @@ -465,10 +465,10 @@ static struct combine_diff_path *ll_diff_tree_paths(
>                  * mark entries whether they =p[imin] along the way
>                  */
>                 imin = 0;
> -               tp[0].entry.mode &= ~S_IFXMIN_NEQ;
> +               tp[0].entry.raw_mode &= ~S_IFXMIN_NEQ;
>
>                 for (i = 1; i < nparent; ++i) {
> -                       unsigned int mode = tp[i].entry.mode;
> +                       unsigned int mode = tp[i].entry.raw_mode;
>                         cmp = tree_entry_pathcmp(&tp[i], &tp[imin]);
>                         if (cmp < 0) {
>                                 imin = i;
> @@ -480,12 +480,12 @@ static struct combine_diff_path *ll_diff_tree_paths(
>                         else {
>                                 mode |= S_IFXMIN_NEQ;
>                         }
> -                       tp[i].entry.mode = mode;
> +                       tp[i].entry.raw_mode = mode;
>                 }
>
>                 /* fixup markings for entries before imin */
>                 for (i = 0; i < imin; ++i)
> -                       tp[i].entry.mode |= S_IFXMIN_NEQ;       /* pi > p[imin] */
> +                       tp[i].entry.raw_mode |= S_IFXMIN_NEQ;   /* pi > p[imin] */
>
>
>
> @@ -497,14 +497,14 @@ static struct combine_diff_path *ll_diff_tree_paths(
>                         /* are either pi > p[imin] or diff(t,pi) != ø ? */
>                         if (!opt->flags.find_copies_harder) {
>                                 for (i = 0; i < nparent; ++i) {
> -                                       unsigned int mode = tp[i].entry.mode;
> +                                       unsigned int mode = tp[i].entry.raw_mode;
>                                         /* p[i] > p[imin] */
>                                         if (mode & S_IFXMIN_NEQ)
>                                                 continue;
>
>                                         /* diff(t,pi) != ø */
>                                         if (!oideq(&t.entry.oid, &tp[i].entry.oid) ||
> -                                           (t.entry.mode != mode))
> +                                           (t.entry.raw_mode != mode))
>                                                 continue;
>
>                                         goto skip_emit_t_tp;
> @@ -536,7 +536,7 @@ static struct combine_diff_path *ll_diff_tree_paths(
>                         /* ∀i pi=p[imin] -> D += "-p[imin]" */
>                         if (!opt->flags.find_copies_harder) {
>                                 for (i = 0; i < nparent; ++i)
> -                                       if (tp[i].entry.mode & S_IFXMIN_NEQ)
> +                                       if (tp[i].entry.raw_mode & S_IFXMIN_NEQ)
>                                                 goto skip_emit_tp;
>                         }
>
> diff --git a/tree-walk.c b/tree-walk.c
> index 12e0ed4e250..099a9b3bd77 100644
> --- a/tree-walk.c
> +++ b/tree-walk.c
> @@ -48,7 +48,7 @@ static int decode_tree_entry(struct tree_desc *desc, const char *buf, unsigned l
>         /* Initialize the descriptor entry */
>         desc->entry.path = path;
>         mode = canon_mode(mode);
> -       desc->entry.mode = mode;
> +       desc->entry.raw_mode = mode;
>         desc->entry.object_type = object_type(mode);
>         desc->entry.pathlen = len - 1;
>         hashcpy(desc->entry.oid.hash, (const unsigned char *)path + len);
> diff --git a/tree-walk.h b/tree-walk.h
> index 1f69e57db4c..885ced74258 100644
> --- a/tree-walk.h
> +++ b/tree-walk.h
> @@ -16,7 +16,7 @@ struct name_entry {
>         struct object_id oid;
>         const char *path;
>         int pathlen;
> -       unsigned int mode;
> +       unsigned int raw_mode;
>         /* simple 'mode': Only OBJ_{BLOB,TREE,COMMIT} */
>         enum object_type object_type;
>  };
> @@ -55,7 +55,7 @@ static inline const struct object_id *tree_entry_extract_mode(struct tree_desc *
>                                                               unsigned short *modep)
>  {
>         *pathp = desc->entry.path;
> -       *modep = desc->entry.mode;
> +       *modep = desc->entry.raw_mode;
>         return &desc->entry.oid;
>  }
>
> @@ -75,7 +75,7 @@ static inline const struct object_id *tree_entry_extract_all(struct tree_desc *d
>                                                              enum object_type *object_typep)
>  {
>         *pathp = desc->entry.path;
> -       *modep = desc->entry.mode;
> +       *modep = desc->entry.raw_mode;
>         *object_typep = desc->entry.object_type;
>         return &desc->entry.oid;
>  }
> diff --git a/tree.c b/tree.c
> index e4402fad69b..215d17e1295 100644
> --- a/tree.c
> +++ b/tree.c
> @@ -40,7 +40,7 @@ static int read_tree_1(struct repository *r,
>                 }
>
>                 switch (fn(&entry.oid, base,
> -                          entry.path, entry.object_type, entry.mode, context)) {
> +                          entry.path, entry.object_type, entry.raw_mode, context)) {
>                 case 0:
>                         continue;
>                 case READ_TREE_RECURSIVE:
> diff --git a/unpack-trees.c b/unpack-trees.c
> index 9471c19de72..dcdf8130745 100644
> --- a/unpack-trees.c
> +++ b/unpack-trees.c
> @@ -867,7 +867,7 @@ static int traverse_trees_recursive(int n, unsigned long dirmask,
>         newinfo.pathspec = info->pathspec;
>         newinfo.name = p->path;
>         newinfo.namelen = p->pathlen;
> -       newinfo.mode = p->mode;
> +       newinfo.mode = p->raw_mode;

Oh boy...unpack-trees too?

Well, all of my worries may be unfounded depending on what you do in
subsequent commits.

>         newinfo.pathlen = st_add3(newinfo.pathlen, tree_entry_len(p), 1);
>         newinfo.df_conflicts |= df_conflicts;
>
> @@ -1020,7 +1020,7 @@ static struct cache_entry *create_ce_entry(const struct traverse_info *info,
>                 is_transient ?
>                 make_empty_transient_cache_entry(len) :
>                 make_empty_cache_entry(istate, len);
> -       unsigned int mode = n->mode;
> +       unsigned int mode = n->raw_mode;
>
>         ce->ce_mode = create_ce_mode(mode);
>         ce->ce_flags = create_ce_flags(stage);
> @@ -1209,7 +1209,7 @@ static void debug_path(struct traverse_info *info)
>  static void debug_name_entry(int i, struct name_entry *n)
>  {
>         printf("ent#%d %06o %s\n", i,
> -              n->path ? n->mode : 0,
> +              n->path ? n->raw_mode : 0,
>                n->path ? n->path : "(missing)");
>  }
>
> --
> 2.31.0.rc0.126.g04f22c5b82
>

^ permalink raw reply	[flat|nested] 262+ messages in thread

* Re: [PATCH 29/30] tree.h API users: rename read_tree_fn_t's "mode" to "raw_mode"
  2021-03-08 15:06     ` [PATCH 29/30] tree.h API users: rename read_tree_fn_t's " Ævar Arnfjörð Bjarmason
@ 2021-03-09 19:02       ` Elijah Newren
  0 siblings, 0 replies; 262+ messages in thread
From: Elijah Newren @ 2021-03-09 19:02 UTC (permalink / raw)
  To: Ævar Arnfjörð Bjarmason
  Cc: Git Mailing List, Junio C Hamano, Kirill Smelkov,
	Nguyễn Thái Ngọc Duy

On Mon, Mar 8, 2021 at 7:07 AM Ævar Arnfjörð Bjarmason <avarab@gmail.com> wrote:
>
> Rename the "mode" variable passed to read_tree_fn_t callbacks to
> "raw_mode". This variable comes to us from the tree-walk.h API. By
> renaming this variable we can easily see where its downstream users
> are in a subsequent commit where we'll sprinkle some canon_mode()
> here.
>
> Signed-off-by: Ævar Arnfjörð Bjarmason <avarab@gmail.com>
> ---
>  archive.c          |  5 +++--
>  builtin/log.c      |  2 +-
>  builtin/ls-files.c | 11 ++++++-----
>  builtin/ls-tree.c  |  6 +++---
>  merge-recursive.c  |  2 +-
>  5 files changed, 14 insertions(+), 12 deletions(-)
>
> diff --git a/archive.c b/archive.c
> index bc8f1c7546f..5b85aae8106 100644
> --- a/archive.c
> +++ b/archive.c
> @@ -232,10 +232,11 @@ static int write_directory(struct archiver_context *c)
>
>  static int queue_or_write_archive_entry(const struct object_id *oid,
>                                         struct strbuf *base, const char *filename,
> -                                       enum object_type object_type, unsigned mode,
> +                                       enum object_type object_type, unsigned raw_mode,
>                                         void *context)
>  {
>         struct archiver_context *c = context;
> +       unsigned mode = raw_mode;
>
>         while (c->bottom &&
>                !(base->len >= c->bottom->len &&
> @@ -382,7 +383,7 @@ struct path_exists_context {
>
>  static int reject_entry(const struct object_id *oid, struct strbuf *base,
>                         const char *filename,
> -                       enum object_type object_type, unsigned mode,
> +                       enum object_type object_type, unsigned raw_mode,
>                         void *context)
>  {
>         int ret = -1;
> diff --git a/builtin/log.c b/builtin/log.c
> index 19a916221d5..c3ef1b3e22d 100644
> --- a/builtin/log.c
> +++ b/builtin/log.c
> @@ -599,7 +599,7 @@ static int show_tag_object(const struct object_id *oid, struct rev_info *rev)
>
>  static int show_tree_object(const struct object_id *oid,
>                             struct strbuf *base, const char *pathname,
> -                           enum object_type object_type, unsigned mode,
> +                           enum object_type object_type, unsigned raw_mode,

This was surprising to me and had me worried, but it looks like this
function doesn't even use mode or raw_mode.

>                             void *context)
>  {
>         FILE *file = context;
> diff --git a/builtin/ls-files.c b/builtin/ls-files.c
> index f38df439410..391e6a9f141 100644
> --- a/builtin/ls-files.c
> +++ b/builtin/ls-files.c
> @@ -425,10 +425,11 @@ static int read_one_entry_opt(struct index_state *istate,
>                               const struct object_id *oid,
>                               struct strbuf *base,
>                               const char *pathname,
> -                             unsigned mode, int opt)
> +                             unsigned raw_mode, int opt)
>  {
>         int len;
>         struct cache_entry *ce;
> +       unsigned mode = raw_mode;

I was about to comment, but checked out the code in question and it
looks like you've modified further.  So perhaps I should wait until
the last patch in the series.

>
>         if (S_ISDIR(mode))
>                 return READ_TREE_RECURSIVE;
> @@ -447,12 +448,12 @@ static int read_one_entry_opt(struct index_state *istate,
>
>  static int read_one_entry(const struct object_id *oid, struct strbuf *base,
>                           const char *pathname,
> -                         enum object_type object_type, unsigned mode,
> +                         enum object_type object_type, unsigned raw_mode,
>                           void *context)
>  {
>         struct index_state *istate = context;
>         return read_one_entry_opt(istate, oid, base, pathname,
> -                                 mode,
> +                                 raw_mode,
>                                   ADD_CACHE_OK_TO_ADD|ADD_CACHE_SKIP_DFCHECK);
>  }
>
> @@ -462,12 +463,12 @@ static int read_one_entry(const struct object_id *oid, struct strbuf *base,
>   */
>  static int read_one_entry_quick(const struct object_id *oid, struct strbuf *base,
>                                 const char *pathname,
> -                               enum object_type object_type, unsigned mode,
> +                               enum object_type object_type, unsigned raw_mode,
>                                 void *context)
>  {
>         struct index_state *istate = context;
>         return read_one_entry_opt(istate, oid, base, pathname,
> -                                 mode,
> +                                 raw_mode,
>                                   ADD_CACHE_JUST_APPEND);
>  }
>
> diff --git a/builtin/ls-tree.c b/builtin/ls-tree.c
> index c6ec3ca751e..3f84603d391 100644
> --- a/builtin/ls-tree.c
> +++ b/builtin/ls-tree.c
> @@ -63,7 +63,7 @@ static int show_recursive(const char *base, int baselen, const char *pathname)
>
>  static int show_tree(const struct object_id *oid, struct strbuf *base,
>                      const char *pathname,
> -                    enum object_type object_type, unsigned mode,
> +                    enum object_type object_type, unsigned raw_mode,
>                      void *context)
>  {
>         int retval = 0;
> @@ -103,11 +103,11 @@ static int show_tree(const struct object_id *oid, struct strbuf *base,
>                                                   "%"PRIuMAX, (uintmax_t)size);
>                         } else
>                                 xsnprintf(size_text, sizeof(size_text), "-");
> -                       printf("%06o %s %s %7s\t", mode, type,
> +                       printf("%06o %s %s %7s\t", raw_mode, type,
>                                find_unique_abbrev(oid, abbrev),
>                                size_text);
>                 } else
> -                       printf("%06o %s %s\t", mode, type,
> +                       printf("%06o %s %s\t", raw_mode, type,
>                                find_unique_abbrev(oid, abbrev));

This looks like a behavioral change.  It might be desirable, but
shouldn't it be called out and documented with a testcase?

(Or is there no change yet because the raw_mode isn't actually yet raw?)

>         }
>         baselen = base->len;
> diff --git a/merge-recursive.c b/merge-recursive.c
> index b26d9d418f9..30fbe72ca06 100644
> --- a/merge-recursive.c
> +++ b/merge-recursive.c
> @@ -453,7 +453,7 @@ static void unpack_trees_finish(struct merge_options *opt)
>
>  static int save_files_dirs(const struct object_id *oid,
>                            struct strbuf *base, const char *path,
> -                          enum object_type object_type, unsigned int mode,
> +                          enum object_type object_type, unsigned int raw_mode,
>                            void *context)
>  {
>         struct path_hashmap_entry *entry;

Oh, man, merge-recursive.c gets modes from the index, from the diff
machinery, and from its own direct calls (get_tree_entry*() calls).
And might have comparisons in all kinds of places.  I'd be _very_
leery, much more so than with merge-ort.c, of having it deal with raw
modes.

^ permalink raw reply	[flat|nested] 262+ messages in thread

* Re: [PATCH 30/30] tree-walk.h API: move canon_mode() back out of decode_tree_entry()
  2021-03-08 15:06     ` [PATCH 30/30] tree-walk.h API: move canon_mode() back out of decode_tree_entry() Ævar Arnfjörð Bjarmason
@ 2021-03-09 20:23       ` Elijah Newren
  0 siblings, 0 replies; 262+ messages in thread
From: Elijah Newren @ 2021-03-09 20:23 UTC (permalink / raw)
  To: Ævar Arnfjörð Bjarmason
  Cc: Git Mailing List, Junio C Hamano, Kirill Smelkov,
	Nguyễn Thái Ngọc Duy

On Mon, Mar 8, 2021 at 7:07 AM Ævar Arnfjörð Bjarmason <avarab@gmail.com> wrote:
>
> Move the canon_mode() call back out of decode_tree_entry(), and
> instead make it the responsibility of its callers to canonicalize the
> tree modes we get.
>
> This effectively reverts 7146e66f086 (tree-walk: finally switch over
> tree descriptors to contain a pre-parsed entry, 2014-02-06), with the
> recent of most callers away from "mode" (now "raw_mode") towards "enum
> object_id" in recent commit the motivation for that commit effectively
> doesn't exist anymore.
>
> I.e. I'm not adding the canon_mode() call back to
> tree_entry_extract(), instead it's now become sane to move this
> responsibility to those callers that still care about the "raw_mode".
>
> That change was meant as a pure optimization change, but it actually
> introduced a subtle bug. We were left without any low-level API to get
> non-standard mode bits out of trees. Having non-standard modes isn't
> the norm, and fsck should warn about it.
>
> Except after 7146e66f086 it couldn't anymore, since the modes
> fsck_tree() got would be pre-sanitized for it. I believe that fsck
> issue is per-se a serious bug, the "bad mode" was a default warning,
> not an error.
>
> This change makes that fsck check work again, why aren't there any
> test changes for fsck here? Because we didn't have a test for that
> fsck feature in the first place, which is why the regression in
> 7146e66f086 snuck by us. A follow-up commit will add such a test.
>
> It is possible that this commit is introducing some subtle regression
> that I've missed.

I'm sure there are at least a few, and I suspect many more.  This is a
super scary change to me, even if it's only about corner cases that
should only exist in repositories that had objects created with super
old (or new and broken) git clients.

> We are now propagating the "raw_mode" outside of everything downstream
> of decode_tree_entry(), which is everything we have that decodes
> trees. It's our most low-level tree decoding API.
>
> As shown here we rely parsing out a "raw" (and possibly something fsck
> would complain about) mode as-is, but when we run merge, add something
> new to the index, create an archive etc. we don't want to propagate
> that bad mode when we create new data. We want to canon_mode() it.
>
> I'm also pretty sure that we don't have good enough test coverage for
> those scenarios. We barely have tests for these bad mode bits at
> all (not even one for fsck). We definitely are not testing all
> merge/index/archive etc. interactions.
>
> Still, I think this change is worth it overall, because:
>
>  1. We must have a way to get at these raw modes in some way, even if
>     just for fsck. There's also other things that care, see e.g. the
>     FIXME comment in 62fdec17a11 (merge-ort: flesh out implementation of
>     handle_content_merge(), 2021-01-01)
>
>  2. #1 is not a justification for this change, I could have e.g. just
>     added the ability to pass some "want_raw" flag into
>     decode_tree_entry() for use in fsck. But I think with the migration
>     of most tree iteration towards "enum object_type" it's become worth
>     it.

This seems like the safer route.  Then we can slowly convert callers
over to using the want_raw as we audit them and add appropriate tests.

>  3. Yes our test coverage sucks, but before 7146e66f086 we were also
>     spreading what's now the "raw_mode" all over the place. That commit
>     was first released with Git v2.0.0 in mid-2014. A while ago for sure,
>     but most of this code existed in something approximating its current
>     form then. This isn't new territory.

That's very helpful to know, actually.  That does lower my worry some.
But the fact that it was released as part of v2.0.0, a new major
release, suggests we knew there were potential breaking changes.  And
code has been built on top of those assumptions for quite a few years,
so we might again break things by reverting back, and having it be
part of a non-major release is worrisome without appropriate tests and
audits of the relevant code paths.

> Signed-off-by: Ævar Arnfjörð Bjarmason <avarab@gmail.com>
> ---
>  archive.c              |  2 +-
>  builtin/checkout.c     |  1 +
>  builtin/ls-files.c     |  2 +-
>  builtin/merge-tree.c   |  6 +++---
>  builtin/update-index.c |  1 +
>  merge-ort.c            | 13 ++++++++++++-
>  notes.c                |  1 +
>  tree-walk.c            |  1 -
>  unpack-trees.c         |  4 +++-

No tests...oh boy.  You did mention this in the commit message, but
I'm still having a hard time getting past making a very low level
change like this without either tests or bumping the major version
number of git.

>  9 files changed, 23 insertions(+), 8 deletions(-)
>
> diff --git a/archive.c b/archive.c
> index 5b85aae8106..8083f15f3ba 100644
> --- a/archive.c
> +++ b/archive.c
> @@ -236,7 +236,7 @@ static int queue_or_write_archive_entry(const struct object_id *oid,
>                                         void *context)
>  {
>         struct archiver_context *c = context;
> -       unsigned mode = raw_mode;
> +       unsigned mode = canon_mode(raw_mode);
>
>         while (c->bottom &&
>                !(base->len >= c->bottom->len &&
> diff --git a/builtin/checkout.c b/builtin/checkout.c
> index d4adfdb5046..7f25b955616 100644
> --- a/builtin/checkout.c
> +++ b/builtin/checkout.c
> @@ -132,6 +132,7 @@ static int update_some(const struct object_id *oid, struct strbuf *base,
>         memcpy(ce->name + base->len, pathname, len - base->len);
>         ce->ce_flags = create_ce_flags(0) | CE_UPDATE;
>         ce->ce_namelen = len;
> +       mode = canon_mode(mode);
>         ce->ce_mode = create_ce_mode(mode);
>
>         /*
> diff --git a/builtin/ls-files.c b/builtin/ls-files.c
> index 391e6a9f141..926523d77a7 100644
> --- a/builtin/ls-files.c
> +++ b/builtin/ls-files.c
> @@ -429,7 +429,7 @@ static int read_one_entry_opt(struct index_state *istate,
>  {
>         int len;
>         struct cache_entry *ce;
> -       unsigned mode = raw_mode;
> +       unsigned mode = canon_mode(raw_mode);
>
>         if (S_ISDIR(mode))
>                 return READ_TREE_RECURSIVE;
> diff --git a/builtin/merge-tree.c b/builtin/merge-tree.c
> index b4e736e4b72..f8733a86eb7 100644
> --- a/builtin/merge-tree.c
> +++ b/builtin/merge-tree.c
> @@ -197,9 +197,9 @@ static void resolve(const struct traverse_info *info, struct name_entry *ours, s
>                 return;
>
>         path = traverse_path(info, result);
> -       orig_mode = ours->raw_mode;
> +       orig_mode = canon_mode(ours->raw_mode);
>         orig = create_entry(2, orig_mode, &ours->oid, path);
> -       final_mode = result->raw_mode;
> +       final_mode = canon_mode(result->raw_mode);
>         final = create_entry(0, final_mode, &result->oid, path);
>
>         final->link = orig;
> @@ -252,7 +252,7 @@ static struct merge_list *link_entry(unsigned stage, const struct traverse_info
>                 path = entry->path;
>         else
>                 path = traverse_path(info, n);
> -       link_mode = n->raw_mode;
> +       link_mode = canon_mode(n->raw_mode);
>         link = create_entry(stage, link_mode, &n->oid, path);
>
>         link->link = entry;
> diff --git a/builtin/update-index.c b/builtin/update-index.c
> index b489a876392..1996fdd97af 100644
> --- a/builtin/update-index.c
> +++ b/builtin/update-index.c
> @@ -621,6 +621,7 @@ static struct cache_entry *read_one_ent(const char *which,
>         memcpy(ce->name, path, namelen);
>         ce->ce_flags = create_ce_flags(stage);
>         ce->ce_namelen = namelen;
> +       mode = canon_mode(mode);
>         ce->ce_mode = create_ce_mode(mode);
>         return ce;
>  }
> diff --git a/merge-ort.c b/merge-ort.c
> index ea20bbe2af3..d1e8a2823e0 100644
> --- a/merge-ort.c
> +++ b/merge-ort.c
> @@ -502,7 +502,7 @@ static void setup_path_info(struct merge_options *opt,
>         mi->basename_offset = current_dir_name_len;
>         mi->clean = !!resolved;
>         if (resolved) {
> -               mi->result.mode = merged_version->raw_mode;
> +               mi->result.mode = canon_mode(merged_version->raw_mode);

canon_mode() will change a mode of 0 into S_IFGITLINK, so this is
wrong.  It's wrong in a way that probably doesn't matter, since
is_null will be true and that is checked in preference to mode == 0
elsewhere, but the code should still be more careful.

>                 oidcpy(&mi->result.oid, &merged_version->oid);
>                 mi->is_null = !!is_null;
>         } else {
> @@ -512,6 +512,16 @@ static void setup_path_info(struct merge_options *opt,
>                 ASSIGN_AND_VERIFY_CI(ci, mi);
>                 for (i = MERGE_BASE; i <= MERGE_SIDE2; i++) {
>                         ci->pathnames[i] = fullpath;
> +                       /*
> +                        * We must not use canon_mode() here. Will
> +                        * fail on an the is_null assertion in
> +                        * 6a02dd90c99 (merge-ort: add a preliminary
> +                        * simple process_entries() implementation,
> +                        * 2020-12-13) when combined with the tests in
> +                        * "[PATCH 00/11] Complete merge-ort
> +                        * implementation...almost" (see
> +                        * https://lore.kernel.org/git/pull.973.git.git.1614905738.gitgitgadget@gmail.com/)
> +                        */
>                         ci->stages[i].mode = names[i].raw_mode;

I suspect the mapping of 0 to S_IFGITLINK might be the culprit here;
we're just lucky an assertion happened to catch this one.  (And
unlucky that nothing caught the one above.)

If you added a special check for that case and used canon_mode()
otherwise, I still think it'd be problematic, because the *only* value
of using raw_mode in the first place was that one special corner case
FIXME comment in handle_content_merge() -- that FIXME could only be
handled by allowing a wider range of modes, and if you canon_mode()
here, then handle_content_merge() only gets canonicalized modes.  At
that point, we might as well ask for special API from traverse_trees()
to just canonicalize for us (which, actually, sounds enticing).

>                         oidcpy(&ci->stages[i].oid, &names[i].oid);
>                 }
> @@ -546,6 +556,7 @@ static void add_pair(struct merge_options *opt,
>         int names_idx = is_add ? side : 0;
>         const struct object_id *oid = &names[names_idx].oid;
>         unsigned int mode = names[names_idx].raw_mode;
> +       mode = canon_mode(mode);

This is unnecessary; diffcore-rename.c only cares whether S_ISREG(mode).


Given that these are the only changes you made to merge-ort.c, and
this is the last patch in the series, my earlier comments and worries
about merge-ort from a few patches ago all look like justified
concerns and make me pretty sure you've introduced some regressions
relating to those.  (Namely, the fact that things comparing modes now
have to worry not about equality, but equality under
canonicalization.)

>         one = alloc_filespec(pathname);
>         two = alloc_filespec(pathname);
> diff --git a/notes.c b/notes.c
> index 2817325651a..78b1b38d36b 100644
> --- a/notes.c
> +++ b/notes.c
> @@ -479,6 +479,7 @@ static void load_subtree(struct notes_tree *t, struct leaf_node *subtree,
>                         const char *q = oid_to_hex(&subtree->key_oid);
>                         size_t i;
>                         unsigned int mode = entry.raw_mode;
> +                       mode = canon_mode(mode);
>                         for (i = 0; i < prefix_len; i++) {
>                                 strbuf_addch(&non_note_path, *q++);
>                                 strbuf_addch(&non_note_path, *q++);
> diff --git a/tree-walk.c b/tree-walk.c
> index 099a9b3bd77..3175430d049 100644
> --- a/tree-walk.c
> +++ b/tree-walk.c
> @@ -47,7 +47,6 @@ static int decode_tree_entry(struct tree_desc *desc, const char *buf, unsigned l
>
>         /* Initialize the descriptor entry */
>         desc->entry.path = path;
> -       mode = canon_mode(mode);
>         desc->entry.raw_mode = mode;
>         desc->entry.object_type = object_type(mode);
>         desc->entry.pathlen = len - 1;
> diff --git a/unpack-trees.c b/unpack-trees.c
> index dcdf8130745..2fb346714b3 100644
> --- a/unpack-trees.c
> +++ b/unpack-trees.c
> @@ -868,6 +868,7 @@ static int traverse_trees_recursive(int n, unsigned long dirmask,
>         newinfo.name = p->path;
>         newinfo.namelen = p->pathlen;
>         newinfo.mode = p->raw_mode;
> +       newinfo.mode = canon_mode(newinfo.mode);
>         newinfo.pathlen = st_add3(newinfo.pathlen, tree_entry_len(p), 1);
>         newinfo.df_conflicts |= df_conflicts;
>
> @@ -1020,7 +1021,8 @@ static struct cache_entry *create_ce_entry(const struct traverse_info *info,
>                 is_transient ?
>                 make_empty_transient_cache_entry(len) :
>                 make_empty_cache_entry(istate, len);
> -       unsigned int mode = n->raw_mode;
> +       unsigned int mode = canon_mode(n->raw_mode);
> +       mode = canon_mode(mode);

It looks like nearly everything in unpack_trees() goes through
create_ce_entry() so perhaps just these two hunks are good enough to
make sure unpack-trees.c and all its callers are dealing with
canonicalized modes.

Except now merge-recursive.c is some weird hybrid were some of its
modes come from unpack-trees (canonicalized), some come diff_tree_oid
(non-canonicalized as far as I can tell above) and various calls to
get_tree_entry_* (also non-canonicalized).  I suspect there are
various bugs there, similar in nature to the ones in merge-ort but
much harder to stamp out given the facts that merge-recursive gets
modes from many more places, and the fact that merge-recursive tends
to do many more comparisons due to checking for each type of
combination of conflicts and having special code for each one
resulting in combinatorial increasing number of nearly-duplicated
codepaths.  merge-recursive is probably a caller that really needs a
way to request that all calls it makes (directly or indirectly) to any
tree walking just return canonicalized modes.

>
>         ce->ce_mode = create_ce_mode(mode);
>         ce->ce_flags = create_ce_flags(stage);
> --

The fact that there are no canon_mode() calls in the diff machinery
makes me wonder if we've changed the behavior for diff/log whenever
there is an object with old modes around.  Perhaps that's a desired
change, but it seems like it should certainly be tested and
documented.  What about all callers of the diff machinery, though?
Are they prepared for such diffs?  One simple example is that
fast-export uses the revision walking and diff machinery, and without
canonicalized modes anymore, it would just print the raw modes.
fast-import sanely won't accept raw modes; it only wants canonical
modes.  So with this change, people may no longer be able to
round-trip fast-export output through fast-import on their existing
repositories.

I also don't like the fact that there is no canonicalization of modes
before writing objects to the git object store.  I believe mktree,
merge-ort, notes (unless your one change to that file is enough but
I'm suspect that it is) are all affected.  match-trees appears to be
affected, but is only called by merge-ort and merge-recursive to
create a temporary merge-base, though the "temporary" tree object will
continue to live in the git object store and could be accessed by
users.  cache-tree.c also writes trees out, but only using ce_mode
which looks like it is everywhere set by calls to e.g.
create_ce_mode(...).  fast-import also writes direct tree objects, but
it doesn't get its modes from reading tree objects, and sanitizes the
inputs it does get.  So, perhaps most tree writers are still sane, but
I'm certain merge-ort would need updates and I suspect mktree and
notes do too.  I think match-trees ought to be updated just for
cleanliness.  And I may have missed other places that directly write
trees out.

I'm worried there's a number of other regressions lurking; those are
just ones I thought about in areas of the code I'm more familiar with.

^ permalink raw reply	[flat|nested] 262+ messages in thread

* Re: [PATCH 00/30] tree-walk: mostly "mode" to "enum object_type"
  2021-03-08 15:06     ` [PATCH 00/30] tree-walk: mostly "mode" to "enum object_type" Ævar Arnfjörð Bjarmason
  2021-03-09  0:10       ` Elijah Newren
@ 2021-03-09 20:41       ` Elijah Newren
  2021-03-09 21:48         ` Ævar Arnfjörð Bjarmason
  2021-03-16  2:12       ` [PATCH v2 00/29] tree-walk: mostly replace "mode" with " Ævar Arnfjörð Bjarmason
                         ` (29 subsequent siblings)
  31 siblings, 1 reply; 262+ messages in thread
From: Elijah Newren @ 2021-03-09 20:41 UTC (permalink / raw)
  To: Ævar Arnfjörð Bjarmason
  Cc: Git Mailing List, Junio C Hamano, Kirill Smelkov,
	Nguyễn Thái Ngọc Duy

On Mon, Mar 8, 2021 at 7:07 AM Ævar Arnfjörð Bjarmason <avarab@gmail.com> wrote:
>
> This large series goes on top of my 6 patch series for
> read_tree_recursive() as this one further refactors that function. See
> https://lore.kernel.org/git/20210308022138.28166-1-avarab@gmail.com/
> for that series.
>
> I noticed that since 2014 or so we haven't been doing the fsck checks
> for bad file modes in trees. This series fixes that. I plan to add
> tests etc. for that in another follow-up series.
>
> I wanted to get this out for review sooner than later, particularly
> since the fsck testing will probably get me down another refactoring
> path (fsck testing in general in this area is pretty bad...).
>
> As noted in 30/30 it would have been way easier to simply do an
> isolated fix for that bug by introducing some fsck-specific API for
> raw tree reading.
>
> But I thought the bug was symptomatic of a wider problem in our
> codebase. Namely that we pass around the tree's mode *a lot*.
>
> But almost everything that then deals with the mode doesn't per-se
> care about the mode bits in the tree, but using them to map that mode
> to a tree entry for one of of OBJ_{BLOB,TREE,COMMIT}.
>
> So this is a large refactoring of all users of the widely used
> tree-walk.h API to "enum obj2ect_type", finally in 29/30 I rename the
> field to a scary "raw_mode".
>
> At that point we have just ~30-50 grep hits left for "raw_mode" in the
> codebase (depending on whether we count names in function parameters).
>
> Hopefully being in that state alleviates e.g. Elijah's concerns
> expressed in
> https://lore.kernel.org/git/CABPp-BEdu1PqV5W=FuL0f08iFhGzvzV8oSUybNj4eF0aAwTnAw@mail.gmail.com/
> I agree that doing the equivalent of 30/30 on top of master would be
> way too scary, but once we're at 29/30 I think it's sane.

It's partially less scary (good cleanups that help make things
clearer, your comment about the code having been in a similar state
once upon a time in patch 30), but in some ways even more scary (after
reading through 30/30 and readily noticing a few missing areas and
starting to dig and finding several more).

>
> I tested this in combination with his on-list series to add more
> merge-ort testing:
> https://lore.kernel.org/git/pull.973.git.git.1614905738.gitgitgadget@gmail.com/
>
> I found a regression I'd caused in the merge-ort.c code with those
> tests, fixed here. See the comment in merge-ort.c in 30/30.

I've read through the whole series now.  It is nicely structured, and
has lots of good cleanups.  Unfortunately, there are also some clear
regressions noted in my comments on both patches 6 and 30.

I'm particularly worried with patch 30's basic plan; I think it'd be
far safer to have the tree-walking default to returning canonicalized
modes but allowing callers to request it be off.  I think each caller
is going to need someone to audit the particular path for whether it
can be safely switched over to using raw modes on a case-by-case basis
and with the introduction of new tests.  Some callers probably aren't
worth the effort (e.g. merge-recursive).  Others might be, but require
a fair amount of work or other trade-offs.  I'm split about whether
merge-ort should consider it.  Using raw_modes might allow me to fix
one funny corner case issue in merge-ort that to my knowledge no user
has ever hit in practice, but I'm not sure fixing that testcase is
worth it.  To fix it, we'd also have to allow writing tree objects
with non-canonicalized modes to the object store (for a "temporary"
tree defining the virtual merge-base); that means new objects with
"broken"/"non-canonicalized" modes being written that users can
access.

> Ævar Arnfjörð Bjarmason (30):
>   diff.c: remove redundant canon_mode() call
>   notes & match-trees: use name_entry's "pathlen" member
>   cache.h: add a comment to object_type()
>   tree-walk.h: add object_type member to name_entry
>   tree-walk.c: migrate to using new "object_type" field when possible
>   cache.h: have base_name_compare() take "is tree?", not "mode"
>   tree-walk.h users: switch object_type(...) to new .object_type
>   tree.h: format argument lists of read_tree_recursive() users
>   tree.h users: format argument lists in archive.c
>   archive: get rid of 'stage' parameter
>   tree.h API: make read_tree_fn_t take an "enum object_type"
>   tree-walk.h users: migrate "p->mode &&" pattern
>   tree-walk.h users: refactor chained "mode" if/else into switch
>   tree-walk.h users: migrate miscellaneous "mode" to "object_type"
>   merge-tree tests: test for the mode comparison in same_entry()
>   merge-ort: correct reference to test in 62fdec17a11
>   fsck.c: switch on "object_type" in fsck_walk_tree()
>   tree-walk.h users: use temporary variable(s) for "mode"
>   tree-walk.h API: formatting changes for subsequent commit
>   tree-walk.h API: rename get_tree_entry() to get_tree_entry_mode()
>   tree-walk.h API users: use "tmp" for mode in shift_tree_by()
>   tree-walk.h API: Add get_tree_entry_type()
>   tree-walk.h API: add a get_tree_entry_path() function
>   tree-walk.h API: document and format tree_entry_extract()
>   tree-entry.h API: rename tree_entry_extract() to
>     tree_entry_extract_mode()
>   tree-walk.h API: add a tree_entry_extract_all() function
>   tree-walk.h API: add a tree_entry_extract_type() function
>   tree-walk.h API users: rename "struct name_entry"'s "mode" to
>     "raw_mode"
>   tree.h API users: rename read_tree_fn_t's "mode" to "raw_mode"
>   tree-walk.h API: move canon_mode() back out of decode_tree_entry()
>
>  archive.c              | 51 +++++++++++++-----------
>  blame.c                |  9 +++--
>  builtin/checkout.c     |  7 +++-
>  builtin/fast-import.c  |  8 ++--
>  builtin/grep.c         |  6 +--
>  builtin/log.c          |  7 ++--
>  builtin/ls-files.c     | 13 +++---
>  builtin/ls-tree.c      | 18 ++++-----
>  builtin/merge-tree.c   | 32 +++++++++------
>  builtin/mktree.c       |  4 +-
>  builtin/pack-objects.c |  6 +--
>  builtin/reflog.c       |  3 +-
>  builtin/rm.c           |  2 +-
>  builtin/update-index.c |  7 +++-
>  cache-tree.c           |  2 +-
>  cache.h                | 11 ++++--
>  combine-diff.c         |  8 ++--
>  delta-islands.c        |  2 +-
>  diff.c                 |  2 +-
>  fsck.c                 | 23 +++++------
>  http-push.c            |  6 ++-
>  line-log.c             |  2 +-
>  list-objects.c         | 20 +++++++---
>  match-trees.c          | 52 ++++++++++++------------
>  merge-ort.c            | 34 ++++++++++------
>  merge-recursive.c      | 33 ++++++++--------
>  notes.c                | 15 +++----
>  object-name.c          |  7 ++--
>  pack-bitmap-write.c    |  8 ++--
>  read-cache.c           | 16 ++++----
>  revision.c             | 12 ++++--
>  t/t4300-merge-tree.sh  | 44 +++++++++++++++++++++
>  tree-diff.c            | 44 ++++++++++++---------
>  tree-walk.c            | 89 +++++++++++++++++++++++++++++++-----------
>  tree-walk.h            | 67 ++++++++++++++++++++++++++-----
>  tree.c                 | 19 +++++----
>  tree.h                 |  5 ++-
>  unpack-trees.c         | 30 ++++++++------
>  walker.c               | 22 ++++++-----
>  39 files changed, 482 insertions(+), 264 deletions(-)
>
> --
> 2.31.0.rc0.126.g04f22c5b82
>

^ permalink raw reply	[flat|nested] 262+ messages in thread

* Re: [PATCH 00/30] tree-walk: mostly "mode" to "enum object_type"
  2021-03-09 20:41       ` Elijah Newren
@ 2021-03-09 21:48         ` Ævar Arnfjörð Bjarmason
  2021-03-12  6:44           ` Elijah Newren
  0 siblings, 1 reply; 262+ messages in thread
From: Ævar Arnfjörð Bjarmason @ 2021-03-09 21:48 UTC (permalink / raw)
  To: Elijah Newren
  Cc: Git Mailing List, Junio C Hamano, Kirill Smelkov,
	Nguyễn Thái Ngọc Duy, Jeff King


On Tue, Mar 09 2021, Elijah Newren wrote:

> On Mon, Mar 8, 2021 at 7:07 AM Ævar Arnfjörð Bjarmason <avarab@gmail.com> wrote:
>>
>> This large series goes on top of my 6 patch series for
>> read_tree_recursive() as this one further refactors that function. See
>> https://lore.kernel.org/git/20210308022138.28166-1-avarab@gmail.com/
>> for that series.
>>
>> I noticed that since 2014 or so we haven't been doing the fsck checks
>> for bad file modes in trees. This series fixes that. I plan to add
>> tests etc. for that in another follow-up series.
>>
>> I wanted to get this out for review sooner than later, particularly
>> since the fsck testing will probably get me down another refactoring
>> path (fsck testing in general in this area is pretty bad...).
>>
>> As noted in 30/30 it would have been way easier to simply do an
>> isolated fix for that bug by introducing some fsck-specific API for
>> raw tree reading.
>>
>> But I thought the bug was symptomatic of a wider problem in our
>> codebase. Namely that we pass around the tree's mode *a lot*.
>>
>> But almost everything that then deals with the mode doesn't per-se
>> care about the mode bits in the tree, but using them to map that mode
>> to a tree entry for one of of OBJ_{BLOB,TREE,COMMIT}.
>>
>> So this is a large refactoring of all users of the widely used
>> tree-walk.h API to "enum obj2ect_type", finally in 29/30 I rename the
>> field to a scary "raw_mode".
>>
>> At that point we have just ~30-50 grep hits left for "raw_mode" in the
>> codebase (depending on whether we count names in function parameters).
>>
>> Hopefully being in that state alleviates e.g. Elijah's concerns
>> expressed in
>> https://lore.kernel.org/git/CABPp-BEdu1PqV5W=FuL0f08iFhGzvzV8oSUybNj4eF0aAwTnAw@mail.gmail.com/
>> I agree that doing the equivalent of 30/30 on top of master would be
>> way too scary, but once we're at 29/30 I think it's sane.
>
> It's partially less scary (good cleanups that help make things
> clearer, your comment about the code having been in a similar state
> once upon a time in patch 30), but in some ways even more scary (after
> reading through 30/30 and readily noticing a few missing areas and
> starting to dig and finding several more).

Thanks a lot for your reviews. I'm going to let this sit for a fair bit
longer before any re-roll, especially with the rc period, other eyeballs
on this most welcome though :)

>>
>> I tested this in combination with his on-list series to add more
>> merge-ort testing:
>> https://lore.kernel.org/git/pull.973.git.git.1614905738.gitgitgadget@gmail.com/
>>
>> I found a regression I'd caused in the merge-ort.c code with those
>> tests, fixed here. See the comment in merge-ort.c in 30/30.
>
> I've read through the whole series now.  It is nicely structured, and
> has lots of good cleanups.  Unfortunately, there are also some clear
> regressions noted in my comments on both patches 6 and 30.
>
> I'm particularly worried with patch 30's basic plan; I think it'd be
> far safer to have the tree-walking default to returning canonicalized
> modes but allowing callers to request it be off.  I think each caller
> is going to need someone to audit the particular path for whether it
> can be safely switched over to using raw modes on a case-by-case basis
> and with the introduction of new tests.  Some callers probably aren't
> worth the effort (e.g. merge-recursive).  Others might be, but require
> a fair amount of work or other trade-offs.  I'm split about whether
> merge-ort should consider it.  Using raw_modes might allow me to fix
> one funny corner case issue in merge-ort that to my knowledge no user
> has ever hit in practice, but I'm not sure fixing that testcase is
> worth it.  To fix it, we'd also have to allow writing tree objects
> with non-canonicalized modes to the object store (for a "temporary"
> tree defining the virtual merge-base); that means new objects with
> "broken"/"non-canonicalized" modes being written that users can
> access.

To add a bit to your worries, I think your "[...]does lower my worry
some[...]" in 30/30 is unfortunately based on some unintentional lying
on my part.

I.e. my "yes our test coverage sucks, but[...]" was based on some
misreading of the history. Here's a correction:

7146e66f086 didn't break the fsck check in mid-2014, it had been broken
for much longer. See Jeff King's late-2014 E-mail about it here (which
I've just now discovered):
https://lore.kernel.org/git/20140923154751.GA19319@peff.net/#t

Basically, decode_tree_entry() didn't sanitize the mode, but we did that
in the tree_entry_extract() function, which is what fsck.c was using all
along, so it was always getting pre-sanitized modes.

But I think I was mostly right, somewhat by accident, AFAICT this was
the state of things back then:
    
    $ git grep '\b(init_tree_desc|fill_tree_descriptor|update_tree_entry|update_tree_entry|tree_entry)\(' -- '*.c' | wc -l
    78
    $ git grep '\b(get_tree_entry|tree_entry_extract)\(' -- '*.c' | wc -l
    25

Those were the API functions that gave you the un-canonical and
canonical mode, respectively.

But yes, I agree that it's probably a bit too scary.

Where I was mainly trying to get to with 30/30 was that for any future
code we'd more carefully review this whole "raw_mode" thing just because
of its name.

So what do you think about a version of 30/30 where existing API users
immediately call canon_mode() upon calling the current API functions?

It would be ugly and verbose now, but the benefit would be that we'd eye
any future change that deals with this "raw_mode" with more suspicion,
and likely convert it to use the object_type instead.

Or I could just back out of this whole 29-30 step and just add a "bare"
API for fsck in particular.

I'm partial to renaming it to *something* just to make it more grep-able
though, we have a "mode" in all sorts of structs all over the place...

>> Ævar Arnfjörð Bjarmason (30):
>>   diff.c: remove redundant canon_mode() call
>>   notes & match-trees: use name_entry's "pathlen" member
>>   cache.h: add a comment to object_type()
>>   tree-walk.h: add object_type member to name_entry
>>   tree-walk.c: migrate to using new "object_type" field when possible
>>   cache.h: have base_name_compare() take "is tree?", not "mode"
>>   tree-walk.h users: switch object_type(...) to new .object_type
>>   tree.h: format argument lists of read_tree_recursive() users
>>   tree.h users: format argument lists in archive.c
>>   archive: get rid of 'stage' parameter
>>   tree.h API: make read_tree_fn_t take an "enum object_type"
>>   tree-walk.h users: migrate "p->mode &&" pattern
>>   tree-walk.h users: refactor chained "mode" if/else into switch
>>   tree-walk.h users: migrate miscellaneous "mode" to "object_type"
>>   merge-tree tests: test for the mode comparison in same_entry()
>>   merge-ort: correct reference to test in 62fdec17a11
>>   fsck.c: switch on "object_type" in fsck_walk_tree()
>>   tree-walk.h users: use temporary variable(s) for "mode"
>>   tree-walk.h API: formatting changes for subsequent commit
>>   tree-walk.h API: rename get_tree_entry() to get_tree_entry_mode()
>>   tree-walk.h API users: use "tmp" for mode in shift_tree_by()
>>   tree-walk.h API: Add get_tree_entry_type()
>>   tree-walk.h API: add a get_tree_entry_path() function
>>   tree-walk.h API: document and format tree_entry_extract()
>>   tree-entry.h API: rename tree_entry_extract() to
>>     tree_entry_extract_mode()
>>   tree-walk.h API: add a tree_entry_extract_all() function
>>   tree-walk.h API: add a tree_entry_extract_type() function
>>   tree-walk.h API users: rename "struct name_entry"'s "mode" to
>>     "raw_mode"
>>   tree.h API users: rename read_tree_fn_t's "mode" to "raw_mode"
>>   tree-walk.h API: move canon_mode() back out of decode_tree_entry()
>>
>>  archive.c              | 51 +++++++++++++-----------
>>  blame.c                |  9 +++--
>>  builtin/checkout.c     |  7 +++-
>>  builtin/fast-import.c  |  8 ++--
>>  builtin/grep.c         |  6 +--
>>  builtin/log.c          |  7 ++--
>>  builtin/ls-files.c     | 13 +++---
>>  builtin/ls-tree.c      | 18 ++++-----
>>  builtin/merge-tree.c   | 32 +++++++++------
>>  builtin/mktree.c       |  4 +-
>>  builtin/pack-objects.c |  6 +--
>>  builtin/reflog.c       |  3 +-
>>  builtin/rm.c           |  2 +-
>>  builtin/update-index.c |  7 +++-
>>  cache-tree.c           |  2 +-
>>  cache.h                | 11 ++++--
>>  combine-diff.c         |  8 ++--
>>  delta-islands.c        |  2 +-
>>  diff.c                 |  2 +-
>>  fsck.c                 | 23 +++++------
>>  http-push.c            |  6 ++-
>>  line-log.c             |  2 +-
>>  list-objects.c         | 20 +++++++---
>>  match-trees.c          | 52 ++++++++++++------------
>>  merge-ort.c            | 34 ++++++++++------
>>  merge-recursive.c      | 33 ++++++++--------
>>  notes.c                | 15 +++----
>>  object-name.c          |  7 ++--
>>  pack-bitmap-write.c    |  8 ++--
>>  read-cache.c           | 16 ++++----
>>  revision.c             | 12 ++++--
>>  t/t4300-merge-tree.sh  | 44 +++++++++++++++++++++
>>  tree-diff.c            | 44 ++++++++++++---------
>>  tree-walk.c            | 89 +++++++++++++++++++++++++++++++-----------
>>  tree-walk.h            | 67 ++++++++++++++++++++++++++-----
>>  tree.c                 | 19 +++++----
>>  tree.h                 |  5 ++-
>>  unpack-trees.c         | 30 ++++++++------
>>  walker.c               | 22 ++++++-----
>>  39 files changed, 482 insertions(+), 264 deletions(-)
>>
>> --
>> 2.31.0.rc0.126.g04f22c5b82
>>


^ permalink raw reply	[flat|nested] 262+ messages in thread

* Re: [PATCH 00/30] tree-walk: mostly "mode" to "enum object_type"
  2021-03-09 21:48         ` Ævar Arnfjörð Bjarmason
@ 2021-03-12  6:44           ` Elijah Newren
  0 siblings, 0 replies; 262+ messages in thread
From: Elijah Newren @ 2021-03-12  6:44 UTC (permalink / raw)
  To: Ævar Arnfjörð Bjarmason
  Cc: Git Mailing List, Junio C Hamano, Kirill Smelkov,
	Nguyễn Thái Ngọc Duy, Jeff King

On Tue, Mar 9, 2021 at 1:48 PM Ævar Arnfjörð Bjarmason <avarab@gmail.com> wrote:
>
> On Tue, Mar 09 2021, Elijah Newren wrote:
>
> > On Mon, Mar 8, 2021 at 7:07 AM Ævar Arnfjörð Bjarmason <avarab@gmail.com> wrote:
> >>
> >> This large series goes on top of my 6 patch series for
> >> read_tree_recursive() as this one further refactors that function. See
> >> https://lore.kernel.org/git/20210308022138.28166-1-avarab@gmail.com/
> >> for that series.
> >>
> >> I noticed that since 2014 or so we haven't been doing the fsck checks
> >> for bad file modes in trees. This series fixes that. I plan to add
> >> tests etc. for that in another follow-up series.
> >>
> >> I wanted to get this out for review sooner than later, particularly
> >> since the fsck testing will probably get me down another refactoring
> >> path (fsck testing in general in this area is pretty bad...).
> >>
> >> As noted in 30/30 it would have been way easier to simply do an
> >> isolated fix for that bug by introducing some fsck-specific API for
> >> raw tree reading.
> >>
> >> But I thought the bug was symptomatic of a wider problem in our
> >> codebase. Namely that we pass around the tree's mode *a lot*.
> >>
> >> But almost everything that then deals with the mode doesn't per-se
> >> care about the mode bits in the tree, but using them to map that mode
> >> to a tree entry for one of of OBJ_{BLOB,TREE,COMMIT}.
> >>
> >> So this is a large refactoring of all users of the widely used
> >> tree-walk.h API to "enum obj2ect_type", finally in 29/30 I rename the
> >> field to a scary "raw_mode".
> >>
> >> At that point we have just ~30-50 grep hits left for "raw_mode" in the
> >> codebase (depending on whether we count names in function parameters).
> >>
> >> Hopefully being in that state alleviates e.g. Elijah's concerns
> >> expressed in
> >> https://lore.kernel.org/git/CABPp-BEdu1PqV5W=FuL0f08iFhGzvzV8oSUybNj4eF0aAwTnAw@mail.gmail.com/
> >> I agree that doing the equivalent of 30/30 on top of master would be
> >> way too scary, but once we're at 29/30 I think it's sane.
> >
> > It's partially less scary (good cleanups that help make things
> > clearer, your comment about the code having been in a similar state
> > once upon a time in patch 30), but in some ways even more scary (after
> > reading through 30/30 and readily noticing a few missing areas and
> > starting to dig and finding several more).
>
> Thanks a lot for your reviews. I'm going to let this sit for a fair bit
> longer before any re-roll, especially with the rc period, other eyeballs
> on this most welcome though :)
>
> >>
> >> I tested this in combination with his on-list series to add more
> >> merge-ort testing:
> >> https://lore.kernel.org/git/pull.973.git.git.1614905738.gitgitgadget@gmail.com/
> >>
> >> I found a regression I'd caused in the merge-ort.c code with those
> >> tests, fixed here. See the comment in merge-ort.c in 30/30.
> >
> > I've read through the whole series now.  It is nicely structured, and
> > has lots of good cleanups.  Unfortunately, there are also some clear
> > regressions noted in my comments on both patches 6 and 30.
> >
> > I'm particularly worried with patch 30's basic plan; I think it'd be
> > far safer to have the tree-walking default to returning canonicalized
> > modes but allowing callers to request it be off.  I think each caller
> > is going to need someone to audit the particular path for whether it
> > can be safely switched over to using raw modes on a case-by-case basis
> > and with the introduction of new tests.  Some callers probably aren't
> > worth the effort (e.g. merge-recursive).  Others might be, but require
> > a fair amount of work or other trade-offs.  I'm split about whether
> > merge-ort should consider it.  Using raw_modes might allow me to fix
> > one funny corner case issue in merge-ort that to my knowledge no user
> > has ever hit in practice, but I'm not sure fixing that testcase is
> > worth it.  To fix it, we'd also have to allow writing tree objects
> > with non-canonicalized modes to the object store (for a "temporary"
> > tree defining the virtual merge-base); that means new objects with
> > "broken"/"non-canonicalized" modes being written that users can
> > access.
>
> To add a bit to your worries, I think your "[...]does lower my worry
> some[...]" in 30/30 is unfortunately based on some unintentional lying
> on my part.
>
> I.e. my "yes our test coverage sucks, but[...]" was based on some
> misreading of the history. Here's a correction:
>
> 7146e66f086 didn't break the fsck check in mid-2014, it had been broken
> for much longer. See Jeff King's late-2014 E-mail about it here (which
> I've just now discovered):
> https://lore.kernel.org/git/20140923154751.GA19319@peff.net/#t
>
> Basically, decode_tree_entry() didn't sanitize the mode, but we did that
> in the tree_entry_extract() function, which is what fsck.c was using all
> along, so it was always getting pre-sanitized modes.
>
> But I think I was mostly right, somewhat by accident, AFAICT this was
> the state of things back then:
>
>     $ git grep '\b(init_tree_desc|fill_tree_descriptor|update_tree_entry|update_tree_entry|tree_entry)\(' -- '*.c' | wc -l
>     78
>     $ git grep '\b(get_tree_entry|tree_entry_extract)\(' -- '*.c' | wc -l
>     25
>
> Those were the API functions that gave you the un-canonical and
> canonical mode, respectively.
>
> But yes, I agree that it's probably a bit too scary.
>
> Where I was mainly trying to get to with 30/30 was that for any future
> code we'd more carefully review this whole "raw_mode" thing just because
> of its name.
>
> So what do you think about a version of 30/30 where existing API users
> immediately call canon_mode() upon calling the current API functions?
>
> It would be ugly and verbose now, but the benefit would be that we'd eye
> any future change that deals with this "raw_mode" with more suspicion,
> and likely convert it to use the object_type instead.

I don't have any strong objections to this.  I'm less worried about
ugly and verbose now, than I am in missing cases while converting;
it'd be easy to get some of the conversions wrong accidentally
(similar to the mode->is_tree changes for fast-import in patch 06 of
this series or the original read_tree() removal patch before you fixed
it up in v2), so I think it'd need to be done with some care.

> Or I could just back out of this whole 29-30 step and just add a "bare"
> API for fsck in particular.

That'd be fine as well, and certainly less concerning; perhaps it's
even the first step.  But I don't think we have to do it this way,
just that if we move towards raw_mode it needs to be done with a lot
of caution.

> I'm partial to renaming it to *something* just to make it more grep-able
> though, we have a "mode" in all sorts of structs all over the place...
>
> >> Ævar Arnfjörð Bjarmason (30):
> >>   diff.c: remove redundant canon_mode() call
> >>   notes & match-trees: use name_entry's "pathlen" member
> >>   cache.h: add a comment to object_type()
> >>   tree-walk.h: add object_type member to name_entry
> >>   tree-walk.c: migrate to using new "object_type" field when possible
> >>   cache.h: have base_name_compare() take "is tree?", not "mode"
> >>   tree-walk.h users: switch object_type(...) to new .object_type
> >>   tree.h: format argument lists of read_tree_recursive() users
> >>   tree.h users: format argument lists in archive.c
> >>   archive: get rid of 'stage' parameter
> >>   tree.h API: make read_tree_fn_t take an "enum object_type"
> >>   tree-walk.h users: migrate "p->mode &&" pattern
> >>   tree-walk.h users: refactor chained "mode" if/else into switch
> >>   tree-walk.h users: migrate miscellaneous "mode" to "object_type"
> >>   merge-tree tests: test for the mode comparison in same_entry()
> >>   merge-ort: correct reference to test in 62fdec17a11
> >>   fsck.c: switch on "object_type" in fsck_walk_tree()
> >>   tree-walk.h users: use temporary variable(s) for "mode"
> >>   tree-walk.h API: formatting changes for subsequent commit
> >>   tree-walk.h API: rename get_tree_entry() to get_tree_entry_mode()
> >>   tree-walk.h API users: use "tmp" for mode in shift_tree_by()
> >>   tree-walk.h API: Add get_tree_entry_type()
> >>   tree-walk.h API: add a get_tree_entry_path() function
> >>   tree-walk.h API: document and format tree_entry_extract()
> >>   tree-entry.h API: rename tree_entry_extract() to
> >>     tree_entry_extract_mode()
> >>   tree-walk.h API: add a tree_entry_extract_all() function
> >>   tree-walk.h API: add a tree_entry_extract_type() function
> >>   tree-walk.h API users: rename "struct name_entry"'s "mode" to
> >>     "raw_mode"
> >>   tree.h API users: rename read_tree_fn_t's "mode" to "raw_mode"
> >>   tree-walk.h API: move canon_mode() back out of decode_tree_entry()
> >>
> >>  archive.c              | 51 +++++++++++++-----------
> >>  blame.c                |  9 +++--
> >>  builtin/checkout.c     |  7 +++-
> >>  builtin/fast-import.c  |  8 ++--
> >>  builtin/grep.c         |  6 +--
> >>  builtin/log.c          |  7 ++--
> >>  builtin/ls-files.c     | 13 +++---
> >>  builtin/ls-tree.c      | 18 ++++-----
> >>  builtin/merge-tree.c   | 32 +++++++++------
> >>  builtin/mktree.c       |  4 +-
> >>  builtin/pack-objects.c |  6 +--
> >>  builtin/reflog.c       |  3 +-
> >>  builtin/rm.c           |  2 +-
> >>  builtin/update-index.c |  7 +++-
> >>  cache-tree.c           |  2 +-
> >>  cache.h                | 11 ++++--
> >>  combine-diff.c         |  8 ++--
> >>  delta-islands.c        |  2 +-
> >>  diff.c                 |  2 +-
> >>  fsck.c                 | 23 +++++------
> >>  http-push.c            |  6 ++-
> >>  line-log.c             |  2 +-
> >>  list-objects.c         | 20 +++++++---
> >>  match-trees.c          | 52 ++++++++++++------------
> >>  merge-ort.c            | 34 ++++++++++------
> >>  merge-recursive.c      | 33 ++++++++--------
> >>  notes.c                | 15 +++----
> >>  object-name.c          |  7 ++--
> >>  pack-bitmap-write.c    |  8 ++--
> >>  read-cache.c           | 16 ++++----
> >>  revision.c             | 12 ++++--
> >>  t/t4300-merge-tree.sh  | 44 +++++++++++++++++++++
> >>  tree-diff.c            | 44 ++++++++++++---------
> >>  tree-walk.c            | 89 +++++++++++++++++++++++++++++++-----------
> >>  tree-walk.h            | 67 ++++++++++++++++++++++++++-----
> >>  tree.c                 | 19 +++++----
> >>  tree.h                 |  5 ++-
> >>  unpack-trees.c         | 30 ++++++++------
> >>  walker.c               | 22 ++++++-----
> >>  39 files changed, 482 insertions(+), 264 deletions(-)
> >>
> >> --
> >> 2.31.0.rc0.126.g04f22c5b82

^ permalink raw reply	[flat|nested] 262+ messages in thread

* Re: [PATCH v2 2/6] tree.c API: move read_tree() into builtin/ls-files.c
  2021-03-08  2:21   ` [PATCH v2 2/6] tree.c API: move read_tree() into builtin/ls-files.c Ævar Arnfjörð Bjarmason
  2021-03-08 18:06     ` Junio C Hamano
@ 2021-03-12 21:41     ` Junio C Hamano
  1 sibling, 0 replies; 262+ messages in thread
From: Junio C Hamano @ 2021-03-12 21:41 UTC (permalink / raw)
  To: Ævar Arnfjörð Bjarmason; +Cc: git, Elijah Newren

Ævar Arnfjörð Bjarmason  <avarab@gmail.com> writes:

> Now builtin/ls-files.c is the last user of this code, let's move all
> the relevant code there. This allows for subsequent simplification of
> it, and an eventual move to read_tree_recursive().

There is a comment in cache.h that has long been a tad stale but not
wrong.  This finally makes it incorrect.

#define ADD_CACHE_JUST_APPEND 8		/* Append only; tree.c::read_tree() */

It would be sufficient to remove the mention of tree.c::read_tree().
It does use this bit, but there are a few others, and there is not
much point in singling out the oldest user the bit was invented for.


^ permalink raw reply	[flat|nested] 262+ messages in thread

* [PATCH v3 0/9] read_tree() and read_tree_recursive() refactoring
  2021-03-08  2:21   ` [PATCH v2 0/6] " Ævar Arnfjörð Bjarmason
                       ` (31 preceding siblings ...)
  2021-03-08 19:18     ` [PATCH v2 0/6] Move the read_tree() function to its only user Elijah Newren
@ 2021-03-15 23:43     ` Ævar Arnfjörð Bjarmason
  2021-03-16  5:37       ` Elijah Newren
                         ` (11 more replies)
  2021-03-15 23:43     ` [PATCH v3 1/9] ls-files tests: add meaningful --with-tree tests Ævar Arnfjörð Bjarmason
                       ` (8 subsequent siblings)
  41 siblings, 12 replies; 262+ messages in thread
From: Ævar Arnfjörð Bjarmason @ 2021-03-15 23:43 UTC (permalink / raw)
  To: git
  Cc: Junio C Hamano, Elijah Newren, Derrick Stolee,
	Ævar Arnfjörð Bjarmason

A v3 of a refactoring of tree.c. See v2 at
https://lore.kernel.org/git/20210308022138.28166-1-avarab@gmail.com/

This brings back pretty much the old read_tree_recursive() under the
name read_tree_at() as suggested in
https://lore.kernel.org/git/xmqqft106sok.fsf@gitster.g/

Ævar Arnfjörð Bjarmason (9):
  ls-files tests: add meaningful --with-tree tests
  tree.c API: move read_tree() into builtin/ls-files.c
  ls-files: don't needlessly pass around stage variable
  ls-files: refactor away read_tree()
  tree.h API: remove support for starting at prefix != ""
  tree.h API: remove "stage" parameter from read_tree_recursive()
  tree.h API: rename read_tree_recursive() to read_tree()
  show tests: add test for "git show <tree>"
  tree.h API: expose read_tree_1() as read_tree_at()

 archive.c                     |  19 +++---
 builtin/checkout.c            |   8 +--
 builtin/log.c                 |   8 +--
 builtin/ls-files.c            |  76 +++++++++++++++++++++-
 builtin/ls-tree.c             |   6 +-
 cache.h                       |   2 +-
 merge-recursive.c             |   6 +-
 t/t3060-ls-files-with-tree.sh |  41 ++++++++++++
 t/t7007-show.sh               |  39 ++++++++++++
 tree.c                        | 117 ++++------------------------------
 tree.h                        |  24 +++----
 11 files changed, 205 insertions(+), 141 deletions(-)

Range-diff:
 1:  6416da0dee2 =  1:  b338f2c01a4 ls-files tests: add meaningful --with-tree tests
 2:  765001b44cd !  2:  4578b83944c tree.c API: move read_tree() into builtin/ls-files.c
    @@ builtin/ls-files.c: static int get_common_prefix_len(const char *common_prefix)
       * Read the tree specified with --with-tree option
       * (typically, HEAD) into stage #1 and then
     
    + ## cache.h ##
    +@@ cache.h: static inline int index_pos_to_insert_pos(uintmax_t pos)
    + #define ADD_CACHE_OK_TO_ADD 1		/* Ok to add */
    + #define ADD_CACHE_OK_TO_REPLACE 2	/* Ok to replace file/directory */
    + #define ADD_CACHE_SKIP_DFCHECK 4	/* Ok to skip DF conflict checks */
    +-#define ADD_CACHE_JUST_APPEND 8		/* Append only; tree.c::read_tree() */
    ++#define ADD_CACHE_JUST_APPEND 8		/* Append only */
    + #define ADD_CACHE_NEW_ONLY 16		/* Do not replace existing ones */
    + #define ADD_CACHE_KEEP_CACHE_TREE 32	/* Do not invalidate cache-tree */
    + #define ADD_CACHE_RENORMALIZE 64        /* Pass along HASH_RENORMALIZE */
    +
      ## tree.c ##
     @@
      
 3:  a71ffba7d04 =  3:  33656ff63b8 ls-files: don't needlessly pass around stage variable
 4:  e78d1810b89 =  4:  1c96d5d3611 ls-files: refactor away read_tree()
 5:  05eecdd7519 !  5:  367cb99224b tree.h API: remove support for starting at prefix != ""
    @@ Commit message
         ffd31f661d5 (Reimplement read_tree_recursive() using
         tree_entry_interesting(), 2011-03-25).
     
    -    If in the future we need to support recursively reading trees without
    -    starting at the root we can easily add a read_tree_recursive_subdir(),
    -    and make that function a thin wrapper for read_tree_1().
    +    As it turns out (Murphy's law and all) we're just about to gain a new
    +    in-tree user that would need this parameter[1]. Let's remove it anyway
    +    as the common case is going to be to not supply it, A later commit
    +    will bring back this functionality in different form.
     
    -    In the meantime there's no reason to keep around what amounts to dead
    -    code, just in case we need it in the future.
    +    1. https://lore.kernel.org/git/xmqqft106sok.fsf@gitster.g/
     
         Signed-off-by: Ævar Arnfjörð Bjarmason <avarab@gmail.com>
     
 6:  fcecc82e1c8 =  6:  38e36780e22 tree.h API: remove "stage" parameter from read_tree_recursive()
 -:  ----------- >  7:  859902ffd83 tree.h API: rename read_tree_recursive() to read_tree()
 -:  ----------- >  8:  a63c9b49f13 show tests: add test for "git show <tree>"
 -:  ----------- >  9:  570642c8625 tree.h API: expose read_tree_1() as read_tree_at()
-- 
2.31.0.rc2.211.g1d0b8788b3


^ permalink raw reply	[flat|nested] 262+ messages in thread

* [PATCH v3 1/9] ls-files tests: add meaningful --with-tree tests
  2021-03-08  2:21   ` [PATCH v2 0/6] " Ævar Arnfjörð Bjarmason
                       ` (32 preceding siblings ...)
  2021-03-15 23:43     ` [PATCH v3 0/9] read_tree() and read_tree_recursive() refactoring Ævar Arnfjörð Bjarmason
@ 2021-03-15 23:43     ` Ævar Arnfjörð Bjarmason
  2021-03-15 23:43     ` [PATCH v3 2/9] tree.c API: move read_tree() into builtin/ls-files.c Ævar Arnfjörð Bjarmason
                       ` (7 subsequent siblings)
  41 siblings, 0 replies; 262+ messages in thread
From: Ævar Arnfjörð Bjarmason @ 2021-03-15 23:43 UTC (permalink / raw)
  To: git
  Cc: Junio C Hamano, Elijah Newren, Derrick Stolee,
	Ævar Arnfjörð Bjarmason

Add tests for "ls-files --with-tree". There was effectively no
coverage for any normal usage of this command, only the tests added in
54e1abce90e (Add test case for ls-files --with-tree, 2007-10-03) for
an obscure bug.

Signed-off-by: Ævar Arnfjörð Bjarmason <avarab@gmail.com>
---
 t/t3060-ls-files-with-tree.sh | 41 +++++++++++++++++++++++++++++++++++
 1 file changed, 41 insertions(+)

diff --git a/t/t3060-ls-files-with-tree.sh b/t/t3060-ls-files-with-tree.sh
index 52ed665fcd2..b257c792a46 100755
--- a/t/t3060-ls-files-with-tree.sh
+++ b/t/t3060-ls-files-with-tree.sh
@@ -47,6 +47,12 @@ test_expect_success setup '
 	git add .
 '
 
+test_expect_success 'usage' '
+	test_expect_code 128 git ls-files --with-tree=HEAD -u &&
+	test_expect_code 128 git ls-files --with-tree=HEAD -s &&
+	test_expect_code 128 git ls-files --recurse-submodules --with-tree=HEAD
+'
+
 test_expect_success 'git ls-files --with-tree should succeed from subdir' '
 	# We have to run from a sub-directory to trigger prune_path
 	# Then we finally get to run our --with-tree test
@@ -60,4 +66,39 @@ test_expect_success \
     'git ls-files --with-tree should add entries from named tree.' \
     'test_cmp expected output'
 
+test_expect_success 'no duplicates in --with-tree output' '
+	git ls-files --with-tree=HEAD >actual &&
+	sort -u actual >expected &&
+	test_cmp expected actual
+'
+
+test_expect_success 'setup: output in a conflict' '
+	test_create_repo conflict &&
+	test_commit -C conflict BASE file &&
+	test_commit -C conflict A file foo &&
+	git -C conflict reset --hard BASE &&
+	test_commit -C conflict B file bar
+'
+
+test_expect_success 'output in a conflict' '
+	test_must_fail git -C conflict merge A B &&
+	cat >expected <<-\EOF &&
+	file
+	file
+	file
+	file
+	EOF
+	git -C conflict ls-files --with-tree=HEAD >actual &&
+	test_cmp expected actual
+'
+
+test_expect_success 'output with removed .git/index' '
+	cat >expected <<-\EOF &&
+	file
+	EOF
+	rm conflict/.git/index &&
+	git -C conflict ls-files --with-tree=HEAD >actual &&
+	test_cmp expected actual
+'
+
 test_done
-- 
2.31.0.rc2.211.g1d0b8788b3


^ permalink raw reply	[flat|nested] 262+ messages in thread

* [PATCH v3 2/9] tree.c API: move read_tree() into builtin/ls-files.c
  2021-03-08  2:21   ` [PATCH v2 0/6] " Ævar Arnfjörð Bjarmason
                       ` (33 preceding siblings ...)
  2021-03-15 23:43     ` [PATCH v3 1/9] ls-files tests: add meaningful --with-tree tests Ævar Arnfjörð Bjarmason
@ 2021-03-15 23:43     ` Ævar Arnfjörð Bjarmason
  2021-03-15 23:43     ` [PATCH v3 3/9] ls-files: don't needlessly pass around stage variable Ævar Arnfjörð Bjarmason
                       ` (6 subsequent siblings)
  41 siblings, 0 replies; 262+ messages in thread
From: Ævar Arnfjörð Bjarmason @ 2021-03-15 23:43 UTC (permalink / raw)
  To: git
  Cc: Junio C Hamano, Elijah Newren, Derrick Stolee,
	Ævar Arnfjörð Bjarmason

Since the read_tree() API was added around the same time as
read_tree_recursive() in 94537c78a82 (Move "read_tree()" to
"tree.c"[...], 2005-04-22) and b12ec373b8e ([PATCH] Teach read-tree
about commit objects, 2005-04-20) things have gradually migrated over
to the read_tree_recursive() version.

Now builtin/ls-files.c is the last user of this code, let's move all
the relevant code there. This allows for subsequent simplification of
it, and an eventual move to read_tree_recursive().

Signed-off-by: Ævar Arnfjörð Bjarmason <avarab@gmail.com>
---
 builtin/ls-files.c | 91 ++++++++++++++++++++++++++++++++++++++++++++++
 cache.h            |  2 +-
 tree.c             | 89 ---------------------------------------------
 tree.h             |  5 ---
 4 files changed, 92 insertions(+), 95 deletions(-)

diff --git a/builtin/ls-files.c b/builtin/ls-files.c
index f6f9e483b27..a4458622813 100644
--- a/builtin/ls-files.c
+++ b/builtin/ls-files.c
@@ -12,6 +12,7 @@
 #include "dir.h"
 #include "builtin.h"
 #include "tree.h"
+#include "cache-tree.h"
 #include "parse-options.h"
 #include "resolve-undo.h"
 #include "string-list.h"
@@ -420,6 +421,96 @@ static int get_common_prefix_len(const char *common_prefix)
 	return common_prefix_len;
 }
 
+static int read_one_entry_opt(struct index_state *istate,
+			      const struct object_id *oid,
+			      const char *base, int baselen,
+			      const char *pathname,
+			      unsigned mode, int stage, int opt)
+{
+	int len;
+	struct cache_entry *ce;
+
+	if (S_ISDIR(mode))
+		return READ_TREE_RECURSIVE;
+
+	len = strlen(pathname);
+	ce = make_empty_cache_entry(istate, baselen + len);
+
+	ce->ce_mode = create_ce_mode(mode);
+	ce->ce_flags = create_ce_flags(stage);
+	ce->ce_namelen = baselen + len;
+	memcpy(ce->name, base, baselen);
+	memcpy(ce->name + baselen, pathname, len+1);
+	oidcpy(&ce->oid, oid);
+	return add_index_entry(istate, ce, opt);
+}
+
+static int read_one_entry(const struct object_id *oid, struct strbuf *base,
+			  const char *pathname, unsigned mode, int stage,
+			  void *context)
+{
+	struct index_state *istate = context;
+	return read_one_entry_opt(istate, oid, base->buf, base->len, pathname,
+				  mode, stage,
+				  ADD_CACHE_OK_TO_ADD|ADD_CACHE_SKIP_DFCHECK);
+}
+
+/*
+ * This is used when the caller knows there is no existing entries at
+ * the stage that will conflict with the entry being added.
+ */
+static int read_one_entry_quick(const struct object_id *oid, struct strbuf *base,
+				const char *pathname, unsigned mode, int stage,
+				void *context)
+{
+	struct index_state *istate = context;
+	return read_one_entry_opt(istate, oid, base->buf, base->len, pathname,
+				  mode, stage,
+				  ADD_CACHE_JUST_APPEND);
+}
+
+
+static int read_tree(struct repository *r, struct tree *tree, int stage,
+		     struct pathspec *match, struct index_state *istate)
+{
+	read_tree_fn_t fn = NULL;
+	int i, err;
+
+	/*
+	 * Currently the only existing callers of this function all
+	 * call it with stage=1 and after making sure there is nothing
+	 * at that stage; we could always use read_one_entry_quick().
+	 *
+	 * But when we decide to straighten out git-read-tree not to
+	 * use unpack_trees() in some cases, this will probably start
+	 * to matter.
+	 */
+
+	/*
+	 * See if we have cache entry at the stage.  If so,
+	 * do it the original slow way, otherwise, append and then
+	 * sort at the end.
+	 */
+	for (i = 0; !fn && i < istate->cache_nr; i++) {
+		const struct cache_entry *ce = istate->cache[i];
+		if (ce_stage(ce) == stage)
+			fn = read_one_entry;
+	}
+
+	if (!fn)
+		fn = read_one_entry_quick;
+	err = read_tree_recursive(r, tree, "", 0, stage, match, fn, istate);
+	if (fn == read_one_entry || err)
+		return err;
+
+	/*
+	 * Sort the cache entry -- we need to nuke the cache tree, though.
+	 */
+	cache_tree_free(&istate->cache_tree);
+	QSORT(istate->cache, istate->cache_nr, cmp_cache_name_compare);
+	return 0;
+}
+
 /*
  * Read the tree specified with --with-tree option
  * (typically, HEAD) into stage #1 and then
diff --git a/cache.h b/cache.h
index 6fda8091f11..c2f8a8eadf6 100644
--- a/cache.h
+++ b/cache.h
@@ -803,7 +803,7 @@ static inline int index_pos_to_insert_pos(uintmax_t pos)
 #define ADD_CACHE_OK_TO_ADD 1		/* Ok to add */
 #define ADD_CACHE_OK_TO_REPLACE 2	/* Ok to replace file/directory */
 #define ADD_CACHE_SKIP_DFCHECK 4	/* Ok to skip DF conflict checks */
-#define ADD_CACHE_JUST_APPEND 8		/* Append only; tree.c::read_tree() */
+#define ADD_CACHE_JUST_APPEND 8		/* Append only */
 #define ADD_CACHE_NEW_ONLY 16		/* Do not replace existing ones */
 #define ADD_CACHE_KEEP_CACHE_TREE 32	/* Do not invalidate cache-tree */
 #define ADD_CACHE_RENORMALIZE 64        /* Pass along HASH_RENORMALIZE */
diff --git a/tree.c b/tree.c
index a52479812ce..a6c12f2745a 100644
--- a/tree.c
+++ b/tree.c
@@ -11,54 +11,6 @@
 
 const char *tree_type = "tree";
 
-static int read_one_entry_opt(struct index_state *istate,
-			      const struct object_id *oid,
-			      const char *base, int baselen,
-			      const char *pathname,
-			      unsigned mode, int stage, int opt)
-{
-	int len;
-	struct cache_entry *ce;
-
-	if (S_ISDIR(mode))
-		return READ_TREE_RECURSIVE;
-
-	len = strlen(pathname);
-	ce = make_empty_cache_entry(istate, baselen + len);
-
-	ce->ce_mode = create_ce_mode(mode);
-	ce->ce_flags = create_ce_flags(stage);
-	ce->ce_namelen = baselen + len;
-	memcpy(ce->name, base, baselen);
-	memcpy(ce->name + baselen, pathname, len+1);
-	oidcpy(&ce->oid, oid);
-	return add_index_entry(istate, ce, opt);
-}
-
-static int read_one_entry(const struct object_id *oid, struct strbuf *base,
-			  const char *pathname, unsigned mode, int stage,
-			  void *context)
-{
-	struct index_state *istate = context;
-	return read_one_entry_opt(istate, oid, base->buf, base->len, pathname,
-				  mode, stage,
-				  ADD_CACHE_OK_TO_ADD|ADD_CACHE_SKIP_DFCHECK);
-}
-
-/*
- * This is used when the caller knows there is no existing entries at
- * the stage that will conflict with the entry being added.
- */
-static int read_one_entry_quick(const struct object_id *oid, struct strbuf *base,
-				const char *pathname, unsigned mode, int stage,
-				void *context)
-{
-	struct index_state *istate = context;
-	return read_one_entry_opt(istate, oid, base->buf, base->len, pathname,
-				  mode, stage,
-				  ADD_CACHE_JUST_APPEND);
-}
-
 static int read_tree_1(struct repository *r,
 		       struct tree *tree, struct strbuf *base,
 		       int stage, const struct pathspec *pathspec,
@@ -154,47 +106,6 @@ int cmp_cache_name_compare(const void *a_, const void *b_)
 				  ce2->name, ce2->ce_namelen, ce_stage(ce2));
 }
 
-int read_tree(struct repository *r, struct tree *tree, int stage,
-	      struct pathspec *match, struct index_state *istate)
-{
-	read_tree_fn_t fn = NULL;
-	int i, err;
-
-	/*
-	 * Currently the only existing callers of this function all
-	 * call it with stage=1 and after making sure there is nothing
-	 * at that stage; we could always use read_one_entry_quick().
-	 *
-	 * But when we decide to straighten out git-read-tree not to
-	 * use unpack_trees() in some cases, this will probably start
-	 * to matter.
-	 */
-
-	/*
-	 * See if we have cache entry at the stage.  If so,
-	 * do it the original slow way, otherwise, append and then
-	 * sort at the end.
-	 */
-	for (i = 0; !fn && i < istate->cache_nr; i++) {
-		const struct cache_entry *ce = istate->cache[i];
-		if (ce_stage(ce) == stage)
-			fn = read_one_entry;
-	}
-
-	if (!fn)
-		fn = read_one_entry_quick;
-	err = read_tree_recursive(r, tree, "", 0, stage, match, fn, istate);
-	if (fn == read_one_entry || err)
-		return err;
-
-	/*
-	 * Sort the cache entry -- we need to nuke the cache tree, though.
-	 */
-	cache_tree_free(&istate->cache_tree);
-	QSORT(istate->cache, istate->cache_nr, cmp_cache_name_compare);
-	return 0;
-}
-
 struct tree *lookup_tree(struct repository *r, const struct object_id *oid)
 {
 	struct object *obj = lookup_object(r, oid);
diff --git a/tree.h b/tree.h
index 3eb0484cbf2..6b0b1dc211a 100644
--- a/tree.h
+++ b/tree.h
@@ -38,9 +38,4 @@ int read_tree_recursive(struct repository *r,
 			const char *base, int baselen,
 			int stage, const struct pathspec *pathspec,
 			read_tree_fn_t fn, void *context);
-
-int read_tree(struct repository *r, struct tree *tree,
-	      int stage, struct pathspec *pathspec,
-	      struct index_state *istate);
-
 #endif /* TREE_H */
-- 
2.31.0.rc2.211.g1d0b8788b3


^ permalink raw reply	[flat|nested] 262+ messages in thread

* [PATCH v3 3/9] ls-files: don't needlessly pass around stage variable
  2021-03-08  2:21   ` [PATCH v2 0/6] " Ævar Arnfjörð Bjarmason
                       ` (34 preceding siblings ...)
  2021-03-15 23:43     ` [PATCH v3 2/9] tree.c API: move read_tree() into builtin/ls-files.c Ævar Arnfjörð Bjarmason
@ 2021-03-15 23:43     ` Ævar Arnfjörð Bjarmason
  2021-03-15 23:43     ` [PATCH v3 4/9] ls-files: refactor away read_tree() Ævar Arnfjörð Bjarmason
                       ` (5 subsequent siblings)
  41 siblings, 0 replies; 262+ messages in thread
From: Ævar Arnfjörð Bjarmason @ 2021-03-15 23:43 UTC (permalink / raw)
  To: git
  Cc: Junio C Hamano, Elijah Newren, Derrick Stolee,
	Ævar Arnfjörð Bjarmason

Now that read_tree() has been moved to ls-files.c we can get rid of
the stage != 1 case that'll never happen.

Signed-off-by: Ævar Arnfjörð Bjarmason <avarab@gmail.com>
---
 builtin/ls-files.c | 17 ++++-------------
 1 file changed, 4 insertions(+), 13 deletions(-)

diff --git a/builtin/ls-files.c b/builtin/ls-files.c
index a4458622813..74d572a3e4a 100644
--- a/builtin/ls-files.c
+++ b/builtin/ls-files.c
@@ -470,21 +470,12 @@ static int read_one_entry_quick(const struct object_id *oid, struct strbuf *base
 }
 
 
-static int read_tree(struct repository *r, struct tree *tree, int stage,
+static int read_tree(struct repository *r, struct tree *tree,
 		     struct pathspec *match, struct index_state *istate)
 {
 	read_tree_fn_t fn = NULL;
 	int i, err;
 
-	/*
-	 * Currently the only existing callers of this function all
-	 * call it with stage=1 and after making sure there is nothing
-	 * at that stage; we could always use read_one_entry_quick().
-	 *
-	 * But when we decide to straighten out git-read-tree not to
-	 * use unpack_trees() in some cases, this will probably start
-	 * to matter.
-	 */
 
 	/*
 	 * See if we have cache entry at the stage.  If so,
@@ -493,13 +484,13 @@ static int read_tree(struct repository *r, struct tree *tree, int stage,
 	 */
 	for (i = 0; !fn && i < istate->cache_nr; i++) {
 		const struct cache_entry *ce = istate->cache[i];
-		if (ce_stage(ce) == stage)
+		if (ce_stage(ce) == 1)
 			fn = read_one_entry;
 	}
 
 	if (!fn)
 		fn = read_one_entry_quick;
-	err = read_tree_recursive(r, tree, "", 0, stage, match, fn, istate);
+	err = read_tree_recursive(r, tree, "", 0, 1, match, fn, istate);
 	if (fn == read_one_entry || err)
 		return err;
 
@@ -549,7 +540,7 @@ void overlay_tree_on_index(struct index_state *istate,
 			       PATHSPEC_PREFER_CWD, prefix, matchbuf);
 	} else
 		memset(&pathspec, 0, sizeof(pathspec));
-	if (read_tree(the_repository, tree, 1, &pathspec, istate))
+	if (read_tree(the_repository, tree, &pathspec, istate))
 		die("unable to read tree entries %s", tree_name);
 
 	for (i = 0; i < istate->cache_nr; i++) {
-- 
2.31.0.rc2.211.g1d0b8788b3


^ permalink raw reply	[flat|nested] 262+ messages in thread

* [PATCH v3 4/9] ls-files: refactor away read_tree()
  2021-03-08  2:21   ` [PATCH v2 0/6] " Ævar Arnfjörð Bjarmason
                       ` (35 preceding siblings ...)
  2021-03-15 23:43     ` [PATCH v3 3/9] ls-files: don't needlessly pass around stage variable Ævar Arnfjörð Bjarmason
@ 2021-03-15 23:43     ` Ævar Arnfjörð Bjarmason
  2021-03-15 23:43     ` [PATCH v3 5/9] tree.h API: remove support for starting at prefix != "" Ævar Arnfjörð Bjarmason
                       ` (4 subsequent siblings)
  41 siblings, 0 replies; 262+ messages in thread
From: Ævar Arnfjörð Bjarmason @ 2021-03-15 23:43 UTC (permalink / raw)
  To: git
  Cc: Junio C Hamano, Elijah Newren, Derrick Stolee,
	Ævar Arnfjörð Bjarmason

Refactor away the read_tree() function into its only user,
overlay_tree_on_index().

First, change read_one_entry_opt() to use the strbuf parameter
read_tree_recursive() passes down in place. This finishes up a partial
refactoring started in 6a0b0b6de99 (tree.c: update read_tree_recursive
callback to pass strbuf as base, 2014-11-30).

Moving the rest into overlay_tree_on_index() makes this index juggling
we're doing easier to read.

Signed-off-by: Ævar Arnfjörð Bjarmason <avarab@gmail.com>
---
 builtin/ls-files.c | 74 +++++++++++++++++++++-------------------------
 1 file changed, 33 insertions(+), 41 deletions(-)

diff --git a/builtin/ls-files.c b/builtin/ls-files.c
index 74d572a3e4a..db53e2c8e6d 100644
--- a/builtin/ls-files.c
+++ b/builtin/ls-files.c
@@ -423,7 +423,7 @@ static int get_common_prefix_len(const char *common_prefix)
 
 static int read_one_entry_opt(struct index_state *istate,
 			      const struct object_id *oid,
-			      const char *base, int baselen,
+			      struct strbuf *base,
 			      const char *pathname,
 			      unsigned mode, int stage, int opt)
 {
@@ -434,13 +434,13 @@ static int read_one_entry_opt(struct index_state *istate,
 		return READ_TREE_RECURSIVE;
 
 	len = strlen(pathname);
-	ce = make_empty_cache_entry(istate, baselen + len);
+	ce = make_empty_cache_entry(istate, base->len + len);
 
 	ce->ce_mode = create_ce_mode(mode);
 	ce->ce_flags = create_ce_flags(stage);
-	ce->ce_namelen = baselen + len;
-	memcpy(ce->name, base, baselen);
-	memcpy(ce->name + baselen, pathname, len+1);
+	ce->ce_namelen = base->len + len;
+	memcpy(ce->name, base->buf, base->len);
+	memcpy(ce->name + base->len, pathname, len+1);
 	oidcpy(&ce->oid, oid);
 	return add_index_entry(istate, ce, opt);
 }
@@ -450,7 +450,7 @@ static int read_one_entry(const struct object_id *oid, struct strbuf *base,
 			  void *context)
 {
 	struct index_state *istate = context;
-	return read_one_entry_opt(istate, oid, base->buf, base->len, pathname,
+	return read_one_entry_opt(istate, oid, base, pathname,
 				  mode, stage,
 				  ADD_CACHE_OK_TO_ADD|ADD_CACHE_SKIP_DFCHECK);
 }
@@ -464,44 +464,11 @@ static int read_one_entry_quick(const struct object_id *oid, struct strbuf *base
 				void *context)
 {
 	struct index_state *istate = context;
-	return read_one_entry_opt(istate, oid, base->buf, base->len, pathname,
+	return read_one_entry_opt(istate, oid, base, pathname,
 				  mode, stage,
 				  ADD_CACHE_JUST_APPEND);
 }
 
-
-static int read_tree(struct repository *r, struct tree *tree,
-		     struct pathspec *match, struct index_state *istate)
-{
-	read_tree_fn_t fn = NULL;
-	int i, err;
-
-
-	/*
-	 * See if we have cache entry at the stage.  If so,
-	 * do it the original slow way, otherwise, append and then
-	 * sort at the end.
-	 */
-	for (i = 0; !fn && i < istate->cache_nr; i++) {
-		const struct cache_entry *ce = istate->cache[i];
-		if (ce_stage(ce) == 1)
-			fn = read_one_entry;
-	}
-
-	if (!fn)
-		fn = read_one_entry_quick;
-	err = read_tree_recursive(r, tree, "", 0, 1, match, fn, istate);
-	if (fn == read_one_entry || err)
-		return err;
-
-	/*
-	 * Sort the cache entry -- we need to nuke the cache tree, though.
-	 */
-	cache_tree_free(&istate->cache_tree);
-	QSORT(istate->cache, istate->cache_nr, cmp_cache_name_compare);
-	return 0;
-}
-
 /*
  * Read the tree specified with --with-tree option
  * (typically, HEAD) into stage #1 and then
@@ -518,6 +485,8 @@ void overlay_tree_on_index(struct index_state *istate,
 	struct pathspec pathspec;
 	struct cache_entry *last_stage0 = NULL;
 	int i;
+	read_tree_fn_t fn = NULL;
+	int err;
 
 	if (get_oid(tree_name, &oid))
 		die("tree-ish %s not found.", tree_name);
@@ -540,9 +509,32 @@ void overlay_tree_on_index(struct index_state *istate,
 			       PATHSPEC_PREFER_CWD, prefix, matchbuf);
 	} else
 		memset(&pathspec, 0, sizeof(pathspec));
-	if (read_tree(the_repository, tree, &pathspec, istate))
+
+	/*
+	 * See if we have cache entry at the stage.  If so,
+	 * do it the original slow way, otherwise, append and then
+	 * sort at the end.
+	 */
+	for (i = 0; !fn && i < istate->cache_nr; i++) {
+		const struct cache_entry *ce = istate->cache[i];
+		if (ce_stage(ce) == 1)
+			fn = read_one_entry;
+	}
+
+	if (!fn)
+		fn = read_one_entry_quick;
+	err = read_tree_recursive(the_repository, tree, "", 0, 1, &pathspec, fn, istate);
+	if (err)
 		die("unable to read tree entries %s", tree_name);
 
+	/*
+	 * Sort the cache entry -- we need to nuke the cache tree, though.
+	 */
+	if (fn == read_one_entry_quick) {
+		cache_tree_free(&istate->cache_tree);
+		QSORT(istate->cache, istate->cache_nr, cmp_cache_name_compare);
+	}
+
 	for (i = 0; i < istate->cache_nr; i++) {
 		struct cache_entry *ce = istate->cache[i];
 		switch (ce_stage(ce)) {
-- 
2.31.0.rc2.211.g1d0b8788b3


^ permalink raw reply	[flat|nested] 262+ messages in thread

* [PATCH v3 5/9] tree.h API: remove support for starting at prefix != ""
  2021-03-08  2:21   ` [PATCH v2 0/6] " Ævar Arnfjörð Bjarmason
                       ` (36 preceding siblings ...)
  2021-03-15 23:43     ` [PATCH v3 4/9] ls-files: refactor away read_tree() Ævar Arnfjörð Bjarmason
@ 2021-03-15 23:43     ` Ævar Arnfjörð Bjarmason
  2021-03-15 23:43     ` [PATCH v3 6/9] tree.h API: remove "stage" parameter from read_tree_recursive() Ævar Arnfjörð Bjarmason
                       ` (3 subsequent siblings)
  41 siblings, 0 replies; 262+ messages in thread
From: Ævar Arnfjörð Bjarmason @ 2021-03-15 23:43 UTC (permalink / raw)
  To: git
  Cc: Junio C Hamano, Elijah Newren, Derrick Stolee,
	Ævar Arnfjörð Bjarmason

Every caller of the read_tree_recursive() function hardcoded a
starting point of "" in the tree. So let's simply remove that
parameter.

The last function to call read_tree_recursive() with a non-"" path was
read_tree_recursive() itself, but that was changed in
ffd31f661d5 (Reimplement read_tree_recursive() using
tree_entry_interesting(), 2011-03-25).

As it turns out (Murphy's law and all) we're just about to gain a new
in-tree user that would need this parameter[1]. Let's remove it anyway
as the common case is going to be to not supply it, A later commit
will bring back this functionality in different form.

1. https://lore.kernel.org/git/xmqqft106sok.fsf@gitster.g/

Signed-off-by: Ævar Arnfjörð Bjarmason <avarab@gmail.com>
---
 archive.c          | 8 ++++----
 builtin/checkout.c | 2 +-
 builtin/log.c      | 4 ++--
 builtin/ls-files.c | 2 +-
 builtin/ls-tree.c  | 2 +-
 merge-recursive.c  | 2 +-
 tree.c             | 2 --
 tree.h             | 1 -
 8 files changed, 10 insertions(+), 13 deletions(-)

diff --git a/archive.c b/archive.c
index 5919d9e5050..9394f170f7f 100644
--- a/archive.c
+++ b/archive.c
@@ -316,8 +316,8 @@ int write_archive_entries(struct archiver_args *args,
 		git_attr_set_direction(GIT_ATTR_INDEX);
 	}
 
-	err = read_tree_recursive(args->repo, args->tree, "",
-				  0, 0, &args->pathspec,
+	err = read_tree_recursive(args->repo, args->tree,
+				  0, &args->pathspec,
 				  queue_or_write_archive_entry,
 				  &context);
 	if (err == READ_TREE_RECURSIVE)
@@ -405,8 +405,8 @@ static int path_exists(struct archiver_args *args, const char *path)
 	ctx.args = args;
 	parse_pathspec(&ctx.pathspec, 0, 0, "", paths);
 	ctx.pathspec.recursive = 1;
-	ret = read_tree_recursive(args->repo, args->tree, "",
-				  0, 0, &ctx.pathspec,
+	ret = read_tree_recursive(args->repo, args->tree,
+				  0, &ctx.pathspec,
 				  reject_entry, &ctx);
 	clear_pathspec(&ctx.pathspec);
 	return ret != 0;
diff --git a/builtin/checkout.c b/builtin/checkout.c
index 2d6550bc3c8..21b742c0f07 100644
--- a/builtin/checkout.c
+++ b/builtin/checkout.c
@@ -155,7 +155,7 @@ static int update_some(const struct object_id *oid, struct strbuf *base,
 
 static int read_tree_some(struct tree *tree, const struct pathspec *pathspec)
 {
-	read_tree_recursive(the_repository, tree, "", 0, 0,
+	read_tree_recursive(the_repository, tree, 0,
 			    pathspec, update_some, NULL);
 
 	/* update the index with the given tree's info
diff --git a/builtin/log.c b/builtin/log.c
index f67b67d80ed..ffa3fb8c286 100644
--- a/builtin/log.c
+++ b/builtin/log.c
@@ -681,8 +681,8 @@ int cmd_show(int argc, const char **argv, const char *prefix)
 					diff_get_color_opt(&rev.diffopt, DIFF_COMMIT),
 					name,
 					diff_get_color_opt(&rev.diffopt, DIFF_RESET));
-			read_tree_recursive(the_repository, (struct tree *)o, "",
-					    0, 0, &match_all, show_tree_object,
+			read_tree_recursive(the_repository, (struct tree *)o,
+					    0, &match_all, show_tree_object,
 					    rev.diffopt.file);
 			rev.shown_one = 1;
 			break;
diff --git a/builtin/ls-files.c b/builtin/ls-files.c
index db53e2c8e6d..cd432ac03cd 100644
--- a/builtin/ls-files.c
+++ b/builtin/ls-files.c
@@ -523,7 +523,7 @@ void overlay_tree_on_index(struct index_state *istate,
 
 	if (!fn)
 		fn = read_one_entry_quick;
-	err = read_tree_recursive(the_repository, tree, "", 0, 1, &pathspec, fn, istate);
+	err = read_tree_recursive(the_repository, tree, 1, &pathspec, fn, istate);
 	if (err)
 		die("unable to read tree entries %s", tree_name);
 
diff --git a/builtin/ls-tree.c b/builtin/ls-tree.c
index 7cad3f24ebd..7d3fb2e6d0f 100644
--- a/builtin/ls-tree.c
+++ b/builtin/ls-tree.c
@@ -185,6 +185,6 @@ int cmd_ls_tree(int argc, const char **argv, const char *prefix)
 	tree = parse_tree_indirect(&oid);
 	if (!tree)
 		die("not a tree object");
-	return !!read_tree_recursive(the_repository, tree, "", 0, 0,
+	return !!read_tree_recursive(the_repository, tree, 0,
 				     &pathspec, show_tree, NULL);
 }
diff --git a/merge-recursive.c b/merge-recursive.c
index b052974f191..fa7602ff0f2 100644
--- a/merge-recursive.c
+++ b/merge-recursive.c
@@ -473,7 +473,7 @@ static void get_files_dirs(struct merge_options *opt, struct tree *tree)
 {
 	struct pathspec match_all;
 	memset(&match_all, 0, sizeof(match_all));
-	read_tree_recursive(opt->repo, tree, "", 0, 0,
+	read_tree_recursive(opt->repo, tree, 0,
 			    &match_all, save_files_dirs, opt);
 }
 
diff --git a/tree.c b/tree.c
index a6c12f2745a..04eb11aed31 100644
--- a/tree.c
+++ b/tree.c
@@ -83,14 +83,12 @@ static int read_tree_1(struct repository *r,
 
 int read_tree_recursive(struct repository *r,
 			struct tree *tree,
-			const char *base, int baselen,
 			int stage, const struct pathspec *pathspec,
 			read_tree_fn_t fn, void *context)
 {
 	struct strbuf sb = STRBUF_INIT;
 	int ret;
 
-	strbuf_add(&sb, base, baselen);
 	ret = read_tree_1(r, tree, &sb, stage, pathspec, fn, context);
 	strbuf_release(&sb);
 	return ret;
diff --git a/tree.h b/tree.h
index 6b0b1dc211a..5252b5139dd 100644
--- a/tree.h
+++ b/tree.h
@@ -35,7 +35,6 @@ typedef int (*read_tree_fn_t)(const struct object_id *, struct strbuf *, const c
 
 int read_tree_recursive(struct repository *r,
 			struct tree *tree,
-			const char *base, int baselen,
 			int stage, const struct pathspec *pathspec,
 			read_tree_fn_t fn, void *context);
 #endif /* TREE_H */
-- 
2.31.0.rc2.211.g1d0b8788b3


^ permalink raw reply	[flat|nested] 262+ messages in thread

* [PATCH v3 6/9] tree.h API: remove "stage" parameter from read_tree_recursive()
  2021-03-08  2:21   ` [PATCH v2 0/6] " Ævar Arnfjörð Bjarmason
                       ` (37 preceding siblings ...)
  2021-03-15 23:43     ` [PATCH v3 5/9] tree.h API: remove support for starting at prefix != "" Ævar Arnfjörð Bjarmason
@ 2021-03-15 23:43     ` Ævar Arnfjörð Bjarmason
  2021-03-15 23:43     ` [PATCH v3 7/9] tree.h API: rename read_tree_recursive() to read_tree() Ævar Arnfjörð Bjarmason
                       ` (2 subsequent siblings)
  41 siblings, 0 replies; 262+ messages in thread
From: Ævar Arnfjörð Bjarmason @ 2021-03-15 23:43 UTC (permalink / raw)
  To: git
  Cc: Junio C Hamano, Elijah Newren, Derrick Stolee,
	Ævar Arnfjörð Bjarmason

The read_tree_recursive() function took a "stage" parameter that is
passed through as-is. As it turns out nothing used this parameter in a
way that they couldn't just move to the callback function they
defined, so let's get rid of it.

If anyone needs to pass such information in the future they can use
the "void *context" parameter.

Signed-off-by: Ævar Arnfjörð Bjarmason <avarab@gmail.com>
---
 archive.c          |  9 +++++----
 builtin/checkout.c |  4 ++--
 builtin/log.c      |  4 ++--
 builtin/ls-files.c | 14 +++++++-------
 builtin/ls-tree.c  |  4 ++--
 merge-recursive.c  |  4 ++--
 tree.c             | 10 +++++-----
 tree.h             |  4 ++--
 8 files changed, 27 insertions(+), 26 deletions(-)

diff --git a/archive.c b/archive.c
index 9394f170f7f..6669a4bd147 100644
--- a/archive.c
+++ b/archive.c
@@ -231,9 +231,10 @@ static int write_directory(struct archiver_context *c)
 
 static int queue_or_write_archive_entry(const struct object_id *oid,
 		struct strbuf *base, const char *filename,
-		unsigned mode, int stage, void *context)
+		unsigned mode, void *context)
 {
 	struct archiver_context *c = context;
+	int stage = 0;
 
 	while (c->bottom &&
 	       !(base->len >= c->bottom->len &&
@@ -317,7 +318,7 @@ int write_archive_entries(struct archiver_args *args,
 	}
 
 	err = read_tree_recursive(args->repo, args->tree,
-				  0, &args->pathspec,
+				  &args->pathspec,
 				  queue_or_write_archive_entry,
 				  &context);
 	if (err == READ_TREE_RECURSIVE)
@@ -378,7 +379,7 @@ struct path_exists_context {
 
 static int reject_entry(const struct object_id *oid, struct strbuf *base,
 			const char *filename, unsigned mode,
-			int stage, void *context)
+			void *context)
 {
 	int ret = -1;
 	struct path_exists_context *ctx = context;
@@ -406,7 +407,7 @@ static int path_exists(struct archiver_args *args, const char *path)
 	parse_pathspec(&ctx.pathspec, 0, 0, "", paths);
 	ctx.pathspec.recursive = 1;
 	ret = read_tree_recursive(args->repo, args->tree,
-				  0, &ctx.pathspec,
+				  &ctx.pathspec,
 				  reject_entry, &ctx);
 	clear_pathspec(&ctx.pathspec);
 	return ret != 0;
diff --git a/builtin/checkout.c b/builtin/checkout.c
index 21b742c0f07..2c2d58a230f 100644
--- a/builtin/checkout.c
+++ b/builtin/checkout.c
@@ -114,7 +114,7 @@ static int post_checkout_hook(struct commit *old_commit, struct commit *new_comm
 }
 
 static int update_some(const struct object_id *oid, struct strbuf *base,
-		const char *pathname, unsigned mode, int stage, void *context)
+		const char *pathname, unsigned mode, void *context)
 {
 	int len;
 	struct cache_entry *ce;
@@ -155,7 +155,7 @@ static int update_some(const struct object_id *oid, struct strbuf *base,
 
 static int read_tree_some(struct tree *tree, const struct pathspec *pathspec)
 {
-	read_tree_recursive(the_repository, tree, 0,
+	read_tree_recursive(the_repository, tree,
 			    pathspec, update_some, NULL);
 
 	/* update the index with the given tree's info
diff --git a/builtin/log.c b/builtin/log.c
index ffa3fb8c286..58acb2b76ab 100644
--- a/builtin/log.c
+++ b/builtin/log.c
@@ -599,7 +599,7 @@ static int show_tag_object(const struct object_id *oid, struct rev_info *rev)
 
 static int show_tree_object(const struct object_id *oid,
 		struct strbuf *base,
-		const char *pathname, unsigned mode, int stage, void *context)
+		const char *pathname, unsigned mode, void *context)
 {
 	FILE *file = context;
 	fprintf(file, "%s%s\n", pathname, S_ISDIR(mode) ? "/" : "");
@@ -682,7 +682,7 @@ int cmd_show(int argc, const char **argv, const char *prefix)
 					name,
 					diff_get_color_opt(&rev.diffopt, DIFF_RESET));
 			read_tree_recursive(the_repository, (struct tree *)o,
-					    0, &match_all, show_tree_object,
+					    &match_all, show_tree_object,
 					    rev.diffopt.file);
 			rev.shown_one = 1;
 			break;
diff --git a/builtin/ls-files.c b/builtin/ls-files.c
index cd432ac03cd..fa9b01b6cc7 100644
--- a/builtin/ls-files.c
+++ b/builtin/ls-files.c
@@ -425,7 +425,7 @@ static int read_one_entry_opt(struct index_state *istate,
 			      const struct object_id *oid,
 			      struct strbuf *base,
 			      const char *pathname,
-			      unsigned mode, int stage, int opt)
+			      unsigned mode, int opt)
 {
 	int len;
 	struct cache_entry *ce;
@@ -437,7 +437,7 @@ static int read_one_entry_opt(struct index_state *istate,
 	ce = make_empty_cache_entry(istate, base->len + len);
 
 	ce->ce_mode = create_ce_mode(mode);
-	ce->ce_flags = create_ce_flags(stage);
+	ce->ce_flags = create_ce_flags(1);
 	ce->ce_namelen = base->len + len;
 	memcpy(ce->name, base->buf, base->len);
 	memcpy(ce->name + base->len, pathname, len+1);
@@ -446,12 +446,12 @@ static int read_one_entry_opt(struct index_state *istate,
 }
 
 static int read_one_entry(const struct object_id *oid, struct strbuf *base,
-			  const char *pathname, unsigned mode, int stage,
+			  const char *pathname, unsigned mode,
 			  void *context)
 {
 	struct index_state *istate = context;
 	return read_one_entry_opt(istate, oid, base, pathname,
-				  mode, stage,
+				  mode,
 				  ADD_CACHE_OK_TO_ADD|ADD_CACHE_SKIP_DFCHECK);
 }
 
@@ -460,12 +460,12 @@ static int read_one_entry(const struct object_id *oid, struct strbuf *base,
  * the stage that will conflict with the entry being added.
  */
 static int read_one_entry_quick(const struct object_id *oid, struct strbuf *base,
-				const char *pathname, unsigned mode, int stage,
+				const char *pathname, unsigned mode,
 				void *context)
 {
 	struct index_state *istate = context;
 	return read_one_entry_opt(istate, oid, base, pathname,
-				  mode, stage,
+				  mode,
 				  ADD_CACHE_JUST_APPEND);
 }
 
@@ -523,7 +523,7 @@ void overlay_tree_on_index(struct index_state *istate,
 
 	if (!fn)
 		fn = read_one_entry_quick;
-	err = read_tree_recursive(the_repository, tree, 1, &pathspec, fn, istate);
+	err = read_tree_recursive(the_repository, tree, &pathspec, fn, istate);
 	if (err)
 		die("unable to read tree entries %s", tree_name);
 
diff --git a/builtin/ls-tree.c b/builtin/ls-tree.c
index 7d3fb2e6d0f..dbb31217beb 100644
--- a/builtin/ls-tree.c
+++ b/builtin/ls-tree.c
@@ -62,7 +62,7 @@ static int show_recursive(const char *base, int baselen, const char *pathname)
 }
 
 static int show_tree(const struct object_id *oid, struct strbuf *base,
-		const char *pathname, unsigned mode, int stage, void *context)
+		const char *pathname, unsigned mode, void *context)
 {
 	int retval = 0;
 	int baselen;
@@ -185,6 +185,6 @@ int cmd_ls_tree(int argc, const char **argv, const char *prefix)
 	tree = parse_tree_indirect(&oid);
 	if (!tree)
 		die("not a tree object");
-	return !!read_tree_recursive(the_repository, tree, 0,
+	return !!read_tree_recursive(the_repository, tree,
 				     &pathspec, show_tree, NULL);
 }
diff --git a/merge-recursive.c b/merge-recursive.c
index fa7602ff0f2..1593f374495 100644
--- a/merge-recursive.c
+++ b/merge-recursive.c
@@ -453,7 +453,7 @@ static void unpack_trees_finish(struct merge_options *opt)
 
 static int save_files_dirs(const struct object_id *oid,
 			   struct strbuf *base, const char *path,
-			   unsigned int mode, int stage, void *context)
+			   unsigned int mode, void *context)
 {
 	struct path_hashmap_entry *entry;
 	int baselen = base->len;
@@ -473,7 +473,7 @@ static void get_files_dirs(struct merge_options *opt, struct tree *tree)
 {
 	struct pathspec match_all;
 	memset(&match_all, 0, sizeof(match_all));
-	read_tree_recursive(opt->repo, tree, 0,
+	read_tree_recursive(opt->repo, tree,
 			    &match_all, save_files_dirs, opt);
 }
 
diff --git a/tree.c b/tree.c
index 04eb11aed31..fb4985f22ca 100644
--- a/tree.c
+++ b/tree.c
@@ -13,7 +13,7 @@ const char *tree_type = "tree";
 
 static int read_tree_1(struct repository *r,
 		       struct tree *tree, struct strbuf *base,
-		       int stage, const struct pathspec *pathspec,
+		       const struct pathspec *pathspec,
 		       read_tree_fn_t fn, void *context)
 {
 	struct tree_desc desc;
@@ -38,7 +38,7 @@ static int read_tree_1(struct repository *r,
 		}
 
 		switch (fn(&entry.oid, base,
-			   entry.path, entry.mode, stage, context)) {
+			   entry.path, entry.mode, context)) {
 		case 0:
 			continue;
 		case READ_TREE_RECURSIVE:
@@ -72,7 +72,7 @@ static int read_tree_1(struct repository *r,
 		strbuf_add(base, entry.path, len);
 		strbuf_addch(base, '/');
 		retval = read_tree_1(r, lookup_tree(r, &oid),
-				     base, stage, pathspec,
+				     base, pathspec,
 				     fn, context);
 		strbuf_setlen(base, oldlen);
 		if (retval)
@@ -83,13 +83,13 @@ static int read_tree_1(struct repository *r,
 
 int read_tree_recursive(struct repository *r,
 			struct tree *tree,
-			int stage, const struct pathspec *pathspec,
+			const struct pathspec *pathspec,
 			read_tree_fn_t fn, void *context)
 {
 	struct strbuf sb = STRBUF_INIT;
 	int ret;
 
-	ret = read_tree_1(r, tree, &sb, stage, pathspec, fn, context);
+	ret = read_tree_1(r, tree, &sb, pathspec, fn, context);
 	strbuf_release(&sb);
 	return ret;
 }
diff --git a/tree.h b/tree.h
index 5252b5139dd..1309ab997e5 100644
--- a/tree.h
+++ b/tree.h
@@ -31,10 +31,10 @@ struct tree *parse_tree_indirect(const struct object_id *oid);
 int cmp_cache_name_compare(const void *a_, const void *b_);
 
 #define READ_TREE_RECURSIVE 1
-typedef int (*read_tree_fn_t)(const struct object_id *, struct strbuf *, const char *, unsigned int, int, void *);
+typedef int (*read_tree_fn_t)(const struct object_id *, struct strbuf *, const char *, unsigned int, void *);
 
 int read_tree_recursive(struct repository *r,
 			struct tree *tree,
-			int stage, const struct pathspec *pathspec,
+			const struct pathspec *pathspec,
 			read_tree_fn_t fn, void *context);
 #endif /* TREE_H */
-- 
2.31.0.rc2.211.g1d0b8788b3


^ permalink raw reply	[flat|nested] 262+ messages in thread

* [PATCH v3 7/9] tree.h API: rename read_tree_recursive() to read_tree()
  2021-03-08  2:21   ` [PATCH v2 0/6] " Ævar Arnfjörð Bjarmason
                       ` (38 preceding siblings ...)
  2021-03-15 23:43     ` [PATCH v3 6/9] tree.h API: remove "stage" parameter from read_tree_recursive() Ævar Arnfjörð Bjarmason
@ 2021-03-15 23:43     ` Ævar Arnfjörð Bjarmason
  2021-03-15 23:43     ` [PATCH v3 8/9] show tests: add test for "git show <tree>" Ævar Arnfjörð Bjarmason
  2021-03-15 23:43     ` [PATCH v3 9/9] tree.h API: expose read_tree_1() as read_tree_at() Ævar Arnfjörð Bjarmason
  41 siblings, 0 replies; 262+ messages in thread
From: Ævar Arnfjörð Bjarmason @ 2021-03-15 23:43 UTC (permalink / raw)
  To: git
  Cc: Junio C Hamano, Elijah Newren, Derrick Stolee,
	Ævar Arnfjörð Bjarmason

Rename the read_tree_recursive() function to just read_tree(). We had
another read_tree() function that I've refactored away in preceding
steps, since all in-tree users read trees recursively with a callback
we can change the name to signify that this is the norm.

Signed-off-by: Ævar Arnfjörð Bjarmason <avarab@gmail.com>
---
 archive.c          | 14 +++++++-------
 builtin/checkout.c |  6 +++---
 builtin/log.c      |  6 +++---
 builtin/ls-files.c |  2 +-
 builtin/ls-tree.c  |  4 ++--
 merge-recursive.c  |  4 ++--
 tree.c             |  8 ++++----
 tree.h             |  8 ++++----
 8 files changed, 26 insertions(+), 26 deletions(-)

diff --git a/archive.c b/archive.c
index 6669a4bd147..c19300ecb9b 100644
--- a/archive.c
+++ b/archive.c
@@ -317,10 +317,10 @@ int write_archive_entries(struct archiver_args *args,
 		git_attr_set_direction(GIT_ATTR_INDEX);
 	}
 
-	err = read_tree_recursive(args->repo, args->tree,
-				  &args->pathspec,
-				  queue_or_write_archive_entry,
-				  &context);
+	err = read_tree(args->repo, args->tree,
+			&args->pathspec,
+			queue_or_write_archive_entry,
+			&context);
 	if (err == READ_TREE_RECURSIVE)
 		err = 0;
 	while (context.bottom) {
@@ -406,9 +406,9 @@ static int path_exists(struct archiver_args *args, const char *path)
 	ctx.args = args;
 	parse_pathspec(&ctx.pathspec, 0, 0, "", paths);
 	ctx.pathspec.recursive = 1;
-	ret = read_tree_recursive(args->repo, args->tree,
-				  &ctx.pathspec,
-				  reject_entry, &ctx);
+	ret = read_tree(args->repo, args->tree,
+			&ctx.pathspec,
+			reject_entry, &ctx);
 	clear_pathspec(&ctx.pathspec);
 	return ret != 0;
 }
diff --git a/builtin/checkout.c b/builtin/checkout.c
index 2c2d58a230f..0e663905200 100644
--- a/builtin/checkout.c
+++ b/builtin/checkout.c
@@ -155,8 +155,8 @@ static int update_some(const struct object_id *oid, struct strbuf *base,
 
 static int read_tree_some(struct tree *tree, const struct pathspec *pathspec)
 {
-	read_tree_recursive(the_repository, tree,
-			    pathspec, update_some, NULL);
+	read_tree(the_repository, tree,
+		  pathspec, update_some, NULL);
 
 	/* update the index with the given tree's info
 	 * for all args, expanding wildcards, and exit
@@ -322,7 +322,7 @@ static void mark_ce_for_checkout_overlay(struct cache_entry *ce,
 	 * If it comes from the tree-ish, we already know it
 	 * matches the pathspec and could just stamp
 	 * CE_MATCHED to it from update_some(). But we still
-	 * need ps_matched and read_tree_recursive (and
+	 * need ps_matched and read_tree (and
 	 * eventually tree_entry_interesting) cannot fill
 	 * ps_matched yet. Once it can, we can avoid calling
 	 * match_pathspec() for _all_ entries when
diff --git a/builtin/log.c b/builtin/log.c
index 58acb2b76ab..980de590638 100644
--- a/builtin/log.c
+++ b/builtin/log.c
@@ -681,9 +681,9 @@ int cmd_show(int argc, const char **argv, const char *prefix)
 					diff_get_color_opt(&rev.diffopt, DIFF_COMMIT),
 					name,
 					diff_get_color_opt(&rev.diffopt, DIFF_RESET));
-			read_tree_recursive(the_repository, (struct tree *)o,
-					    &match_all, show_tree_object,
-					    rev.diffopt.file);
+			read_tree(the_repository, (struct tree *)o,
+				  &match_all, show_tree_object,
+				  rev.diffopt.file);
 			rev.shown_one = 1;
 			break;
 		case OBJ_COMMIT:
diff --git a/builtin/ls-files.c b/builtin/ls-files.c
index fa9b01b6cc7..13bcc2d8473 100644
--- a/builtin/ls-files.c
+++ b/builtin/ls-files.c
@@ -523,7 +523,7 @@ void overlay_tree_on_index(struct index_state *istate,
 
 	if (!fn)
 		fn = read_one_entry_quick;
-	err = read_tree_recursive(the_repository, tree, &pathspec, fn, istate);
+	err = read_tree(the_repository, tree, &pathspec, fn, istate);
 	if (err)
 		die("unable to read tree entries %s", tree_name);
 
diff --git a/builtin/ls-tree.c b/builtin/ls-tree.c
index dbb31217beb..3a442631c71 100644
--- a/builtin/ls-tree.c
+++ b/builtin/ls-tree.c
@@ -185,6 +185,6 @@ int cmd_ls_tree(int argc, const char **argv, const char *prefix)
 	tree = parse_tree_indirect(&oid);
 	if (!tree)
 		die("not a tree object");
-	return !!read_tree_recursive(the_repository, tree,
-				     &pathspec, show_tree, NULL);
+	return !!read_tree(the_repository, tree,
+			   &pathspec, show_tree, NULL);
 }
diff --git a/merge-recursive.c b/merge-recursive.c
index 1593f374495..3d9207455b3 100644
--- a/merge-recursive.c
+++ b/merge-recursive.c
@@ -473,8 +473,8 @@ static void get_files_dirs(struct merge_options *opt, struct tree *tree)
 {
 	struct pathspec match_all;
 	memset(&match_all, 0, sizeof(match_all));
-	read_tree_recursive(opt->repo, tree,
-			    &match_all, save_files_dirs, opt);
+	read_tree(opt->repo, tree,
+		  &match_all, save_files_dirs, opt);
 }
 
 static int get_tree_entry_if_blob(struct repository *r,
diff --git a/tree.c b/tree.c
index fb4985f22ca..f6de250d7ff 100644
--- a/tree.c
+++ b/tree.c
@@ -81,10 +81,10 @@ static int read_tree_1(struct repository *r,
 	return 0;
 }
 
-int read_tree_recursive(struct repository *r,
-			struct tree *tree,
-			const struct pathspec *pathspec,
-			read_tree_fn_t fn, void *context)
+int read_tree(struct repository *r,
+	      struct tree *tree,
+	      const struct pathspec *pathspec,
+	      read_tree_fn_t fn, void *context)
 {
 	struct strbuf sb = STRBUF_INIT;
 	int ret;
diff --git a/tree.h b/tree.h
index 1309ab997e5..4fb713774a7 100644
--- a/tree.h
+++ b/tree.h
@@ -33,8 +33,8 @@ int cmp_cache_name_compare(const void *a_, const void *b_);
 #define READ_TREE_RECURSIVE 1
 typedef int (*read_tree_fn_t)(const struct object_id *, struct strbuf *, const char *, unsigned int, void *);
 
-int read_tree_recursive(struct repository *r,
-			struct tree *tree,
-			const struct pathspec *pathspec,
-			read_tree_fn_t fn, void *context);
+int read_tree(struct repository *r,
+	      struct tree *tree,
+	      const struct pathspec *pathspec,
+	      read_tree_fn_t fn, void *context);
 #endif /* TREE_H */
-- 
2.31.0.rc2.211.g1d0b8788b3


^ permalink raw reply	[flat|nested] 262+ messages in thread

* [PATCH v3 8/9] show tests: add test for "git show <tree>"
  2021-03-08  2:21   ` [PATCH v2 0/6] " Ævar Arnfjörð Bjarmason
                       ` (39 preceding siblings ...)
  2021-03-15 23:43     ` [PATCH v3 7/9] tree.h API: rename read_tree_recursive() to read_tree() Ævar Arnfjörð Bjarmason
@ 2021-03-15 23:43     ` Ævar Arnfjörð Bjarmason
  2021-03-16  5:19       ` Elijah Newren
  2021-03-15 23:43     ` [PATCH v3 9/9] tree.h API: expose read_tree_1() as read_tree_at() Ævar Arnfjörð Bjarmason
  41 siblings, 1 reply; 262+ messages in thread
From: Ævar Arnfjörð Bjarmason @ 2021-03-15 23:43 UTC (permalink / raw)
  To: git
  Cc: Junio C Hamano, Elijah Newren, Derrick Stolee,
	Ævar Arnfjörð Bjarmason

Add missing tests for showing a tree with "git show". Let's test for
showing a tree, two trees, and that doing so doesn't recurse.

The only tests for this code added in 5d7eeee2ac6 (git-show: grok
blobs, trees and tags, too, 2006-12-14) were the tests in
t7701-repack-unpack-unreachable.sh added in ccc1297226b (repack:
modify behavior of -A option to leave unreferenced objects unpacked,
2008-05-09).

Let's add this common mode of operation to the "show" tests
themselves. It's more obvious, and the tests in
t7701-repack-unpack-unreachable.sh happily parse if we start buggily
emitting trees recursively.

Signed-off-by: Ævar Arnfjörð Bjarmason <avarab@gmail.com>
---
 t/t7007-show.sh | 39 +++++++++++++++++++++++++++++++++++++++
 1 file changed, 39 insertions(+)

diff --git a/t/t7007-show.sh b/t/t7007-show.sh
index 42d3db62468..37ce718b231 100755
--- a/t/t7007-show.sh
+++ b/t/t7007-show.sh
@@ -38,6 +38,45 @@ test_expect_success 'showing two commits' '
 	test_cmp expect actual.filtered
 '
 
+test_expect_success 'showing a tree' '
+	cat >expected <<-EOF &&
+	tree main1:
+
+	main1.t
+	EOF
+	git show main1: >actual &&
+	test_cmp expected actual
+'
+
+test_expect_success 'showing two trees' '
+	cat >expected <<-EOF &&
+	tree main1:
+
+	main1.t
+
+	tree main2:
+
+	main1.t
+	main2.t
+	EOF
+	git show main1: main2: >actual &&
+	test_cmp expected actual
+'
+
+test_expect_success 'showing a trees is not recursive' '
+	git worktree add not-recursive main1 &&
+	mkdir not-recursive/a &&
+	test_commit -C not-recursive a/file &&
+	cat >expected <<-EOF &&
+	tree a/file:
+
+	a/
+	main1.t
+	EOF
+	git -C not-recursive show a/file: >actual &&
+	test_cmp expected actual
+'
+
 test_expect_success 'showing a range walks (linear)' '
 	cat >expect <<-EOF &&
 	commit $(git rev-parse main3)
-- 
2.31.0.rc2.211.g1d0b8788b3


^ permalink raw reply	[flat|nested] 262+ messages in thread

* [PATCH v3 9/9] tree.h API: expose read_tree_1() as read_tree_at()
  2021-03-08  2:21   ` [PATCH v2 0/6] " Ævar Arnfjörð Bjarmason
                       ` (40 preceding siblings ...)
  2021-03-15 23:43     ` [PATCH v3 8/9] show tests: add test for "git show <tree>" Ævar Arnfjörð Bjarmason
@ 2021-03-15 23:43     ` Ævar Arnfjörð Bjarmason
  41 siblings, 0 replies; 262+ messages in thread
From: Ævar Arnfjörð Bjarmason @ 2021-03-15 23:43 UTC (permalink / raw)
  To: git
  Cc: Junio C Hamano, Elijah Newren, Derrick Stolee,
	Ævar Arnfjörð Bjarmason

Rename the static read_tree_1() function to read_tree_at(). This will
allow for the old read_tree_recursive() mode of operation where we
start at a given path instead of "".

See [1] for the discussion of one such future in-tree user, unlike the
old read_tree_recursive() this function takes a strbuf. Since that's
what read_tree_1() used internally this should allow us to avoid
casting and/or reallocations in the future.

1. https://lore.kernel.org/git/xmqqft106sok.fsf@gitster.g/#t
---
 tree.c | 16 ++++++++--------
 tree.h |  6 ++++++
 2 files changed, 14 insertions(+), 8 deletions(-)

diff --git a/tree.c b/tree.c
index f6de250d7ff..6a2a52967e4 100644
--- a/tree.c
+++ b/tree.c
@@ -11,10 +11,10 @@
 
 const char *tree_type = "tree";
 
-static int read_tree_1(struct repository *r,
-		       struct tree *tree, struct strbuf *base,
-		       const struct pathspec *pathspec,
-		       read_tree_fn_t fn, void *context)
+int read_tree_at(struct repository *r,
+		 struct tree *tree, struct strbuf *base,
+		 const struct pathspec *pathspec,
+		 read_tree_fn_t fn, void *context)
 {
 	struct tree_desc desc;
 	struct name_entry entry;
@@ -71,9 +71,9 @@ static int read_tree_1(struct repository *r,
 		len = tree_entry_len(&entry);
 		strbuf_add(base, entry.path, len);
 		strbuf_addch(base, '/');
-		retval = read_tree_1(r, lookup_tree(r, &oid),
-				     base, pathspec,
-				     fn, context);
+		retval = read_tree_at(r, lookup_tree(r, &oid),
+				      base, pathspec,
+				      fn, context);
 		strbuf_setlen(base, oldlen);
 		if (retval)
 			return -1;
@@ -89,7 +89,7 @@ int read_tree(struct repository *r,
 	struct strbuf sb = STRBUF_INIT;
 	int ret;
 
-	ret = read_tree_1(r, tree, &sb, pathspec, fn, context);
+	ret = read_tree_at(r, tree, &sb, pathspec, fn, context);
 	strbuf_release(&sb);
 	return ret;
 }
diff --git a/tree.h b/tree.h
index 4fb713774a7..f0b079d2e91 100644
--- a/tree.h
+++ b/tree.h
@@ -33,6 +33,12 @@ int cmp_cache_name_compare(const void *a_, const void *b_);
 #define READ_TREE_RECURSIVE 1
 typedef int (*read_tree_fn_t)(const struct object_id *, struct strbuf *, const char *, unsigned int, void *);
 
+int read_tree_at(struct repository *r,
+		 struct tree *tree,
+		 struct strbuf *at,
+		 const struct pathspec *pathspec,
+		 read_tree_fn_t fn, void *context);
+
 int read_tree(struct repository *r,
 	      struct tree *tree,
 	      const struct pathspec *pathspec,
-- 
2.31.0.rc2.211.g1d0b8788b3


^ permalink raw reply	[flat|nested] 262+ messages in thread

* [PATCH v2 00/29] tree-walk: mostly replace "mode" with "enum object_type"
  2021-03-08 15:06     ` [PATCH 00/30] tree-walk: mostly "mode" to "enum object_type" Ævar Arnfjörð Bjarmason
  2021-03-09  0:10       ` Elijah Newren
  2021-03-09 20:41       ` Elijah Newren
@ 2021-03-16  2:12       ` Ævar Arnfjörð Bjarmason
  2021-03-16  7:04         ` Elijah Newren
                           ` (33 more replies)
  2021-03-16  2:12       ` [PATCH v2 01/29] diff.c: remove redundant canon_mode() call Ævar Arnfjörð Bjarmason
                         ` (28 subsequent siblings)
  31 siblings, 34 replies; 262+ messages in thread
From: Ævar Arnfjörð Bjarmason @ 2021-03-16  2:12 UTC (permalink / raw)
  To: git
  Cc: Junio C Hamano, Elijah Newren, Kirill Smelkov,
	Nguyễn Thái Ngọc Duy,
	Ævar Arnfjörð Bjarmason

A v2 of the big tree-walk.[ch] refactoring series, goals etc. at the
v1 at:
https://lore.kernel.org/git/20210308150650.18626-1-avarab@gmail.com/

It is based on my just-re-rolled v3 read_tree_recursive() series:
https://lore.kernel.org/git/20210315234344.28427-1-avarab@gmail.com/

This version should address all the feedback on v1 for patces 1-27/30,
thanks to Elijah for very valuable comments on v1.

It's mostly small nits here and there, except:

 - I found that the change I'd made to update-index.c was buggy at the
   point it was introduced in the series, the object_type would be
   uninitialized. There were/are no tests for that, but I've moved
   things around so we don't have that bug anymore.

 - Elijah had a comment on whether we needed oid_object_info() in
   blame.c. As it turns out we don't need a "is blob?" check at all
   there. There's a new 28/29 to refactor that small part of blame.c,
   along with a test.

What this re-roll *does not* include is the final 28-30/30 part of v1
to s/mode/raw_mode/g and move canonical_mode() out of tree-walk.h.

So a follow-up series will still be needed to fix the fsck.c check for
bad modes, but I wanted to split that tricker change off from this
rather big initial refactoring.

Ævar Arnfjörð Bjarmason (29):
  diff.c: remove redundant canon_mode() call
  notes & match-trees: use name_entry's "pathlen" member
  cache.h: add a comment to object_type()
  tree-walk.h: add object_type member to name_entry
  tree-walk.c: migrate to using new "object_type" field when possible
  cache.h: have base_name_compare() take "is tree?", not "mode"
  tree-walk.h users: switch object_type(...) to new .object_type
  tree.h: format argument lists of read_tree_recursive() users
  tree.h users: format argument lists in archive.c
  archive: get rid of 'stage' parameter
  tree.h API: make read_tree_fn_t take an "enum object_type"
  tree-walk.h users: migrate "p->mode &&" pattern
  tree-walk.h users: refactor chained "mode" if/else into switch
  tree-walk.h users: migrate miscellaneous "mode" to "object_type"
  merge-tree tests: test for the mode comparison in same_entry()
  merge-ort: correct reference to test in 62fdec17a11
  fsck.c: switch on "object_type" in fsck_walk_tree()
  tree-walk.h users: use temporary variable(s) for "mode"
  tree-walk.h API: formatting changes for subsequent commit
  tree-walk.h API: rename get_tree_entry() to get_tree_entry_mode()
  tree-walk.h API users: use "tmp" for mode in shift_tree_by()
  tree-walk.h API: add get_tree_entry_type()
  tree-walk.h API: document and format tree_entry_extract()
  tree-entry.h API: rename tree_entry_extract() to
    tree_entry_extract_mode()
  tree-walk.h API: add a tree_entry_extract_all() function
  tree-walk.h API: add get_tree_entry_all()
  tree-walk.h API: add a get_tree_entry_path() function
  blame: emit a better error on 'git blame directory'
  tree-walk.h API: add a tree_entry_extract_type() function

 archive.c                       | 50 +++++++++---------
 blame.c                         |  9 ++--
 builtin/checkout.c              |  6 ++-
 builtin/fast-import.c           |  8 +--
 builtin/grep.c                  |  6 +--
 builtin/log.c                   |  7 +--
 builtin/ls-files.c              |  6 ++-
 builtin/ls-tree.c               | 14 +++---
 builtin/merge-tree.c            | 30 +++++++----
 builtin/mktree.c                |  4 +-
 builtin/pack-objects.c          |  6 +--
 builtin/reflog.c                |  3 +-
 builtin/rm.c                    |  2 +-
 builtin/update-index.c          |  6 ++-
 cache-tree.c                    |  2 +-
 cache.h                         | 11 ++--
 combine-diff.c                  |  8 +--
 delta-islands.c                 |  2 +-
 diff.c                          |  2 +-
 fsck.c                          | 23 ++++-----
 http-push.c                     |  6 ++-
 line-log.c                      |  2 +-
 list-objects.c                  | 20 +++++---
 match-trees.c                   | 52 +++++++++----------
 merge-ort.c                     | 13 ++---
 merge-recursive.c               | 33 ++++++------
 notes.c                         | 14 +++---
 object-name.c                   |  7 ++-
 pack-bitmap-write.c             |  8 +--
 read-cache.c                    | 16 +++---
 revision.c                      | 12 +++--
 t/t4300-merge-tree.sh           | 44 ++++++++++++++++
 t/t8004-blame-with-conflicts.sh | 20 ++++++++
 tree-diff.c                     | 30 +++++++----
 tree-walk.c                     | 89 ++++++++++++++++++++++++---------
 tree-walk.h                     | 63 ++++++++++++++++++++---
 tree.c                          | 19 ++++---
 tree.h                          |  5 +-
 unpack-trees.c                  | 24 +++++----
 walker.c                        | 22 ++++----
 40 files changed, 460 insertions(+), 244 deletions(-)

Range-diff:
 1:  e5df57c3440 =  1:  f9bbc30f69f diff.c: remove redundant canon_mode() call
 2:  8c2500bbf35 =  2:  187fc2c3e64 notes & match-trees: use name_entry's "pathlen" member
 3:  3d98e0c132f !  3:  311637c5583 cache.h: add a comment to object_type()
    @@ Commit message
         cache.h: add a comment to object_type()
     
         Add a comment to the object_type() function to explain what it
    -    returns, and whet the "mode" is in the "else" case.
    +    returns, and what the "mode" is in the "else" case.
     
         The object_type() function dates back to 4d1012c3709 (Fix rev-list
         when showing objects involving submodules, 2007-11-11). It's not
 4:  ce5808b317c =  4:  fecfe3d462c tree-walk.h: add object_type member to name_entry
 5:  18f26531acf =  5:  db961ab5e8d tree-walk.c: migrate to using new "object_type" field when possible
 6:  55e2640b815 !  6:  df2fc76161d cache.h: have base_name_compare() take "is tree?", not "mode"
    @@ cache.h: int repo_interpret_branch_name(struct repository *r,
      
     -int base_name_compare(const char *name1, int len1, int mode1, const char *name2, int len2, int mode2);
     -int df_name_compare(const char *name1, int len1, int mode1, const char *name2, int len2, int mode2);
    -+int base_name_compare(const char *name1, int len1, int isdir1, const char *name2, int len2, int isdir2);
    -+int df_name_compare(const char *name1, int len1, int isdir1, const char *name2, int len2, int isdir2);
    ++int base_name_compare(const char *name1, int len1, int istree1, const char *name2, int len2, int istree2);
    ++int df_name_compare(const char *name1, int len1, int istree1, const char *name2, int len2, int istree2);
      int name_compare(const char *name1, size_t len1, const char *name2, size_t len2);
      int cache_name_stage_compare(const char *name1, int len1, int stage1, const char *name2, int len2, int stage2);
      
    @@ combine-diff.c
      			  const struct diff_filespec *two)
      {
     -	if (!S_ISDIR(one->mode) && !S_ISDIR(two->mode))
    -+	int isdir_one = S_ISDIR(one->mode);
    -+	int isdir_two = S_ISDIR(two->mode);
    -+	if (!isdir_one && !isdir_two)
    ++	int istree_one = S_ISDIR(one->mode);
    ++	int istree_two = S_ISDIR(two->mode);
    ++	if (!istree_one && !istree_two)
      		return strcmp(one->path, two->path);
      
     -	return base_name_compare(one->path, strlen(one->path), one->mode,
     -				 two->path, strlen(two->path), two->mode);
    -+	return base_name_compare(one->path, strlen(one->path), isdir_one,
    -+				 two->path, strlen(two->path), isdir_two);
    ++	return base_name_compare(one->path, strlen(one->path), istree_one,
    ++				 two->path, strlen(two->path), istree_two);
      }
      
      static int filename_changed(char status)
    @@ match-trees.c: static void *fill_tree_desc_strict(struct tree_desc *desc,
      {
     -	return base_name_compare(a->path, tree_entry_len(a), a->mode,
     -				 b->path, tree_entry_len(b), b->mode);
    -+	int isdira = a->object_type == OBJ_TREE;
    -+	int isdirb = b->object_type == OBJ_TREE;
    -+	return base_name_compare(a->path, tree_entry_len(a), isdira,
    -+				 b->path, tree_entry_len(b), isdirb);
    ++	int istree_a = (a->object_type == OBJ_TREE);
    ++	int istree_b = (b->object_type == OBJ_TREE);
    ++	return base_name_compare(a->path, tree_entry_len(a), istree_a,
    ++				 b->path, tree_entry_len(b), istree_b);
      }
      
      /*
    @@ read-cache.c: int ie_modified(struct index_state *istate,
      
     -int base_name_compare(const char *name1, int len1, int mode1,
     -		      const char *name2, int len2, int mode2)
    -+int base_name_compare(const char *name1, int len1, int isdir1,
    -+		      const char *name2, int len2, int isdir2)
    ++int base_name_compare(const char *name1, int len1, int istree1,
    ++		      const char *name2, int len2, int istree2)
      {
      	unsigned char c1, c2;
      	int len = len1 < len2 ? len1 : len2;
    @@ read-cache.c: int base_name_compare(const char *name1, int len1, int mode1,
      	c1 = name1[len];
      	c2 = name2[len];
     -	if (!c1 && S_ISDIR(mode1))
    -+	if (!c1 && isdir1)
    ++	if (!c1 && istree1)
      		c1 = '/';
     -	if (!c2 && S_ISDIR(mode2))
    -+	if (!c2 && isdir2)
    ++	if (!c2 && istree2)
      		c2 = '/';
      	return (c1 < c2) ? -1 : (c1 > c2) ? 1 : 0;
      }
    @@ read-cache.c: int base_name_compare(const char *name1, int len1, int mode1,
       */
     -int df_name_compare(const char *name1, int len1, int mode1,
     -		    const char *name2, int len2, int mode2)
    -+int df_name_compare(const char *name1, int len1, int isdir1,
    -+		    const char *name2, int len2, int isdir2)
    ++int df_name_compare(const char *name1, int len1, int istree1,
    ++		    const char *name2, int len2, int istree2)
      {
      	int len = len1 < len2 ? len1 : len2, cmp;
      	unsigned char c1, c2;
    @@ read-cache.c: int df_name_compare(const char *name1, int len1, int mode1,
      		return 0;
      	c1 = name1[len];
     -	if (!c1 && S_ISDIR(mode1))
    -+	if (!c1 && isdir1)
    ++	if (!c1 && istree1)
      		c1 = '/';
      	c2 = name2[len];
     -	if (!c2 && S_ISDIR(mode2))
    -+	if (!c2 && isdir2)
    ++	if (!c2 && istree2)
      		c2 = '/';
      	if (c1 == '/' && !c2)
      		return 0;
    @@ tree-diff.c: static int tree_entry_pathcmp(struct tree_desc *t1, struct tree_des
      {
      	struct name_entry *e1, *e2;
      	int cmp;
    -+	int e1_is_tree, e2_is_tree;
    ++	int istree_e1, istree_e2;
      
      	/* empty descriptors sort after valid tree entries */
      	if (!t1->size)
    @@ tree-diff.c: static int tree_entry_pathcmp(struct tree_desc *t1, struct tree_des
      		return -1;
      
      	e1 = &t1->entry;
    -+	e1_is_tree = e1->object_type == OBJ_TREE;
    ++	istree_e1 = (e1->object_type == OBJ_TREE);
      	e2 = &t2->entry;
     -	cmp = base_name_compare(e1->path, tree_entry_len(e1), e1->mode,
     -				e2->path, tree_entry_len(e2), e2->mode);
    -+	e2_is_tree = e2->object_type == OBJ_TREE;
    -+	cmp = base_name_compare(e1->path, tree_entry_len(e1), e1_is_tree,
    -+				e2->path, tree_entry_len(e2), e2_is_tree);
    ++	istree_e2 = (e2->object_type == OBJ_TREE);
    ++	cmp = base_name_compare(e1->path, tree_entry_len(e1), istree_e1,
    ++				e2->path, tree_entry_len(e2), istree_e2);
      	return cmp;
      }
      
    @@ unpack-trees.c: static int traverse_trees_recursive(int n, unsigned long dirmask
      				      const struct traverse_info *info,
      				      const char *name, size_t namelen,
     -				      unsigned mode)
    -+				      unsigned is_tree)
    ++				      unsigned istree)
      {
      	int pathlen, ce_len;
      	const char *ce_name;
    @@ unpack-trees.c: static int do_compare_entry_piecewise(const struct cache_entry *
      	ce_name = ce->name + pathlen;
      
     -	return df_name_compare(ce_name, ce_len, S_IFREG, name, namelen, mode);
    -+	return df_name_compare(ce_name, ce_len, 0, name, namelen, is_tree);
    ++	return df_name_compare(ce_name, ce_len, 0, name, namelen, istree);
      }
      
      static int do_compare_entry(const struct cache_entry *ce,
      			    const struct traverse_info *info,
      			    const char *name, size_t namelen,
     -			    unsigned mode)
    -+			    unsigned is_tree)
    ++			    unsigned istree)
      {
      	int pathlen, ce_len;
      	const char *ce_name;
    @@ unpack-trees.c: static int do_compare_entry(const struct cache_entry *ce,
      	 */
      	if (!info->traverse_path)
     -		return do_compare_entry_piecewise(ce, info, name, namelen, mode);
    -+		return do_compare_entry_piecewise(ce, info, name, namelen, is_tree);
    ++		return do_compare_entry_piecewise(ce, info, name, namelen, istree);
      
      	cmp = strncmp(ce->name, info->traverse_path, info->pathlen);
      	if (cmp)
    @@ unpack-trees.c: static int do_compare_entry(const struct cache_entry *ce,
      	ce_name = ce->name + pathlen;
      
     -	return df_name_compare(ce_name, ce_len, S_IFREG, name, namelen, mode);
    -+	return df_name_compare(ce_name, ce_len, 0, name, namelen, is_tree);
    ++	return df_name_compare(ce_name, ce_len, 0, name, namelen, istree);
      }
      
      static int compare_entry(const struct cache_entry *ce, const struct traverse_info *info, const struct name_entry *n)
      {
     -	int cmp = do_compare_entry(ce, info, n->path, n->pathlen, n->mode);
    -+	int is_tree = n->object_type == OBJ_TREE;
    -+	int cmp = do_compare_entry(ce, info, n->path, n->pathlen, is_tree);
    ++	int istree = (n->object_type == OBJ_TREE);
    ++	int cmp = do_compare_entry(ce, info, n->path, n->pathlen, istree);
      	if (cmp)
      		return cmp;
      
 7:  abc128f6cb9 =  7:  49d5da8c086 tree-walk.h users: switch object_type(...) to new .object_type
 8:  dcf13faf3cd !  8:  c9d209d496a tree.h: format argument lists of read_tree_recursive() users
    @@ archive.c: static int check_attr_export_subst(const struct attr_check *check)
     -		void *context)
     +			       int baselen, const char *filename,
     +			       unsigned mode,
    -+			       int stage, void *context)
    ++			       int stage,
    ++			       void *context)
      {
      	static struct strbuf path = STRBUF_INIT;
      	struct archiver_context *c = context;
    @@ tree.h: struct tree *parse_tree_indirect(const struct object_id *oid);
     +			      unsigned int,
     +			      void *);
      
    - int read_tree_recursive(struct repository *r,
    - 			struct tree *tree,
    + int read_tree_at(struct repository *r,
    + 		 struct tree *tree,
 9:  b33fcf82349 !  9:  a6d2660fe14 tree.h users: format argument lists in archive.c
    @@ Commit message
         Signed-off-by: Ævar Arnfjörð Bjarmason <avarab@gmail.com>
     
      ## archive.c ##
    -@@ archive.c: static int check_attr_export_subst(const struct attr_check *check)
    - static int write_archive_entry(const struct object_id *oid, const char *base,
    - 			       int baselen, const char *filename,
    - 			       unsigned mode,
    --			       int stage, void *context)
    -+			       int stage,
    -+			       void *context)
    - {
    - 	static struct strbuf path = STRBUF_INIT;
    - 	struct archiver_context *c = context;
     @@ archive.c: static int write_archive_entry(const struct object_id *oid, const char *base,
      }
      
10:  6a20d3c058f = 10:  15f7f89acca archive: get rid of 'stage' parameter
11:  a7f7444917c ! 11:  7a71404ea3f tree.h API: make read_tree_fn_t take an "enum object_type"
    @@ merge-recursive.c: static int save_files_dirs(const struct object_id *oid,
      static void get_files_dirs(struct merge_options *opt, struct tree *tree)
     
      ## tree.c ##
    -@@ tree.c: static int read_tree_1(struct repository *r,
    +@@ tree.c: int read_tree_at(struct repository *r,
      	init_tree_desc(&desc, tree->buffer, tree->size);
      
      	while (tree_entry(&desc, &entry)) {
    @@ tree.c: static int read_tree_1(struct repository *r,
      		if (retval != all_entries_interesting) {
      			retval = tree_entry_interesting(r->index, &entry,
      							base, 0, pathspec);
    -@@ tree.c: static int read_tree_1(struct repository *r,
    +@@ tree.c: int read_tree_at(struct repository *r,
      		}
      
      		switch (fn(&entry.oid, base,
    @@ tree.c: static int read_tree_1(struct repository *r,
      		case 0:
      			continue;
      		case READ_TREE_RECURSIVE:
    -@@ tree.c: static int read_tree_1(struct repository *r,
    +@@ tree.c: int read_tree_at(struct repository *r,
      			return -1;
      		}
      
    @@ tree.c: static int read_tree_1(struct repository *r,
      			commit = lookup_commit(r, &entry.oid);
      			if (!commit)
      				die("Commit %s in submodule path %s%s not found",
    -@@ tree.c: static int read_tree_1(struct repository *r,
    +@@ tree.c: int read_tree_at(struct repository *r,
      				    base->buf, entry.path);
      
      			oidcpy(&oid, get_commit_tree_oid(commit));
    @@ tree.h: int cmp_cache_name_compare(const void *a_, const void *b_);
     +			      enum object_type, unsigned int,
      			      void *);
      
    - int read_tree_recursive(struct repository *r,
    + int read_tree_at(struct repository *r,
12:  625c643513d ! 12:  64dc9364bae tree-walk.h users: migrate "p->mode &&" pattern
    @@ Metadata
      ## Commit message ##
         tree-walk.h users: migrate "p->mode &&" pattern
     
    -    Change code that dpends on "p->mode" either being a valid mode or zero
    -    to use a p->object_type comparison to "OBJ_NONE".
    +    Change code that depends on "p->mode" either being a valid mode or
    +    zero to use a p->object_type comparison to "OBJ_NONE".
     
    -    The object_type() function in cache.h will not return OBJ_NONE, but in
    -    this these API users are implicitly relying on the memzero() that
    -    happens in setup_traverse_info().
    +    The object_type() function in cache.h will not return OBJ_NONE, but
    +    these API users are implicitly relying on the memzero() that happens
    +    in setup_traverse_info().
     
         Since OBJ_NONE is "0" we can also rely on that being zero'd out here,
         along with the rest of the structure. I think this is slightly less
13:  37b28c7feff = 13:  93ed3edbbd5 tree-walk.h users: refactor chained "mode" if/else into switch
14:  e0b8ec6e291 = 14:  7aa48aa34c3 tree-walk.h users: migrate miscellaneous "mode" to "object_type"
15:  0cd162c43d7 = 15:  3ae81621dcf merge-tree tests: test for the mode comparison in same_entry()
16:  f8ce666d4a7 = 16:  4249ad5c4de merge-ort: correct reference to test in 62fdec17a11
17:  4963902ba97 = 17:  e5e17505dde fsck.c: switch on "object_type" in fsck_walk_tree()
18:  d74e6778009 = 18:  3f0b884f1fd tree-walk.h users: use temporary variable(s) for "mode"
19:  d39db486d4e = 19:  174167613bb tree-walk.h API: formatting changes for subsequent commit
20:  69eb956b1ab = 20:  ec76db613f2 tree-walk.h API: rename get_tree_entry() to get_tree_entry_mode()
21:  cc56453e600 = 21:  11e34941729 tree-walk.h API users: use "tmp" for mode in shift_tree_by()
22:  ca9e3b3ad00 ! 22:  b31c106557f tree-walk.h API: Add get_tree_entry_type()
    @@ Metadata
     Author: Ævar Arnfjörð Bjarmason <avarab@gmail.com>
     
      ## Commit message ##
    -    tree-walk.h API: Add get_tree_entry_type()
    +    tree-walk.h API: add get_tree_entry_type()
     
         Add a get_tree_entry_type() helper function to compliment the existing
    -    get_tree_entry(). Move those users of get_tree_entry_type() who didn't
    -    care about the mode specifically, but just want to know whether the
    -    tree entry is one of OBJ_{BLOB,COMMIT,TREE} over to it.
    +    get_tree_entry(), and a static get_tree_entry_all() which it uses internally.
    +
    +    Move those users of get_tree_entry_type() who didn't care about the
    +    mode specifically, but just want to know whether the tree entry is one
    +    of OBJ_{BLOB,COMMIT,TREE} over to the new get_tree_entry_type().
    +
    +    The get_tree_entry_all() function itself will be made non-static in a
    +    subsequent commit. I'm leaving its argument list indented accordingly
    +    to reduce churn when I do so.
     
         Signed-off-by: Ævar Arnfjörð Bjarmason <avarab@gmail.com>
     
    @@ archive.c: static void parse_treeish_arg(const char **argv,
      
      		tree = parse_tree_indirect(&tree_oid);
     
    - ## blame.c ##
    -@@ blame.c: static void verify_working_tree_path(struct repository *r,
    - 	for (parents = work_tree->parents; parents; parents = parents->next) {
    - 		const struct object_id *commit_oid = &parents->item->object.oid;
    - 		struct object_id blob_oid;
    --		unsigned short mode;
    --		int ret = get_tree_entry_mode(r, commit_oid, path, &blob_oid,
    --					      &mode);
    -+		enum object_type object_type;
    -+		int ret = get_tree_entry_type(r, commit_oid, path, &blob_oid,
    -+					      &object_type);
    - 
    --		if (!ret && oid_object_info(r, &blob_oid, NULL) == OBJ_BLOB)
    -+		if (!ret && object_type == OBJ_BLOB)
    - 			return;
    - 	}
    - 
    -
      ## match-trees.c ##
     @@ match-trees.c: void shift_tree_by(struct repository *r,
      		   const char *shift_prefix)
    @@ match-trees.c: void shift_tree_by(struct repository *r,
     
      ## tree-walk.c ##
     @@ tree-walk.c: struct dir_state {
    + 	struct object_id oid;
    + };
      
    ++static int get_tree_entry_all(struct repository *r,
    ++			      const struct object_id *tree_oid,
    ++			      const char *name,
    ++			      struct object_id *oid,
    ++			      unsigned short *mode,
    ++			      enum object_type *object_type);
    ++
      static int find_tree_entry(struct repository *r, struct tree_desc *t,
      			   const char *name, struct object_id *result,
     -			   unsigned short *mode)
    @@ tree-walk.c: static int find_tree_entry(struct repository *r, struct tree_desc *
     -			const char *name,
     -			struct object_id *oid,
     -			unsigned short *mode)
    -+int get_tree_entry_all(struct repository *r,
    ++static int get_tree_entry_all(struct repository *r,
     +		       const struct object_id *tree_oid,
     +		       const char *name,
     +		       struct object_id *oid,
    @@ tree-walk.h: struct traverse_info {
     - * The third and fourth parameters are set to the entry's sha1 and
     - * mode respectively.
     + * There are variants of this function depending on what fields in the
    -+ * "struct name_entry" you'd like. You always need to pointer to an
    ++ * "struct name_entry" you'd like. You always need a pointer to an
     + * appropriate variable to fill in (NULL won't do!):
     + *
     + * get_tree_entry_mode(): unsigned int mode
     + * get_tree_entry_type(): enum object_type
    -+ * get_tree_entry_all(): unsigned int mode, enum object_type
       */
      int get_tree_entry_mode(struct repository *, const struct object_id *, const char *,
      			struct object_id *,
    @@ tree-walk.h: struct traverse_info {
     +int get_tree_entry_type(struct repository *, const struct object_id *, const char *,
     +			struct object_id *,
     +			enum object_type *);
    -+int get_tree_entry_all(struct repository *, const struct object_id *, const char *,
    -+		       struct object_id *,
    -+		       unsigned short *, enum object_type *);
      
      /**
       * Generate the full pathname of a tree entry based from the root of the
24:  5986f494aa1 ! 23:  304d5d4d1af tree-walk.h API: document and format tree_entry_extract()
    @@ tree-walk.h: struct tree_desc {
     - * `pathp` and `modep` arguments are set to the entry's pathname and mode
     - * respectively.
     + * `tree_desc's` `entry` member) and return the OID of the entry.
    -+
    ++ *
     + * There are variants of this function depending on what fields in the
    -+ * "struct name_entry" you'd like. You always need to pointer to an
    ++ * "struct name_entry" you'd like. You always need a pointer to an
     + * appropriate variable to fill in (NULL won't do!):
     + *
     + * tree_entry_extract_mode(): const char *path, unsigned int mode
25:  9b604a193b8 ! 24:  346453df356 tree-entry.h API: rename tree_entry_extract() to tree_entry_extract_mode()
    @@ tree-diff.c: static struct combine_diff_path *emit_path(struct combine_diff_path
      
      		isdir = S_ISDIR(mode);
     
    - ## tree-walk.c ##
    -@@ tree-walk.c: static int find_tree_entry(struct repository *r, struct tree_desc *t,
    - 		struct object_id oid;
    - 		int entrylen, cmp;
    - 
    --		oidcpy(&oid, tree_entry_extract(t, &entry, mode));
    -+		oidcpy(&oid, tree_entry_extract_mode(t, &entry, mode));
    - 		entrylen = tree_entry_len(&t->entry);
    - 		update_tree_entry(t);
    - 		if (entrylen > namelen)
    -
      ## tree-walk.h ##
     @@ tree-walk.h: struct tree_desc {
       *
26:  40878d04550 ! 25:  dd012b661e5 tree-walk.h API: add a tree_entry_extract_all() function
    @@ Commit message
     
         Signed-off-by: Ævar Arnfjörð Bjarmason <avarab@gmail.com>
     
    - ## builtin/update-index.c ##
    -@@ builtin/update-index.c: static struct cache_entry *read_one_ent(const char *which,
    - 					struct object_id *ent, const char *path,
    - 					int namelen, int stage)
    - {
    -+	enum object_type object_type;
    - 	unsigned short mode;
    - 	struct object_id oid;
    - 	struct cache_entry *ce;
    - 
    --	if (get_tree_entry_mode(the_repository, ent, path, &oid, &mode)) {
    -+	if (get_tree_entry_all(the_repository, ent, path, &oid,
    -+			       &mode, &object_type)) {
    - 		if (which)
    - 			error("%s: not in %s branch.", path, which);
    - 		return NULL;
    - 	}
    --	if (mode == S_IFDIR) {
    -+	if (object_type == OBJ_TREE) {
    - 		if (which)
    - 			error("%s: not a blob in %s branch.", path, which);
    - 		return NULL;
    -
      ## tree-diff.c ##
     @@ tree-diff.c: static struct combine_diff_path *emit_path(struct combine_diff_path *p,
      	assert(t || tp);
    @@ tree-diff.c: static struct combine_diff_path *emit_path(struct combine_diff_path
     +		oid = tree_entry_extract_all(t, &path, &mode, &object_type);
      		pathlen = tree_entry_len(&t->entry);
     -		isdir = S_ISDIR(mode);
    -+		isdir = object_type == OBJ_TREE;
    ++		isdir = (object_type == OBJ_TREE);
      	} else {
      		/*
      		 * a path was removed - take path from imin parent. Also take
    @@ tree-walk.c: static int find_tree_entry(struct repository *r, struct tree_desc *
      		struct object_id oid;
      		int entrylen, cmp;
      
    --		oidcpy(&oid, tree_entry_extract_mode(t, &entry, mode));
    +-		oidcpy(&oid, tree_entry_extract(t, &entry, mode));
     +		oidcpy(&oid, tree_entry_extract_all(t, &entry, mode, object_type));
    -+
      		entrylen = tree_entry_len(&t->entry);
      		update_tree_entry(t);
      		if (entrylen > namelen)
 -:  ----------- > 26:  b6ee8410e38 tree-walk.h API: add get_tree_entry_all()
23:  6b864e066d9 ! 27:  5c98afd9e7a tree-walk.h API: add a get_tree_entry_path() function
    @@ tree-walk.c: int get_tree_entry_all(struct repository *r,
     
      ## tree-walk.h ##
     @@ tree-walk.h: struct traverse_info {
    -  * "struct name_entry" you'd like. You always need to pointer to an
    +  * "struct name_entry" you'd like. You always need a pointer to an
       * appropriate variable to fill in (NULL won't do!):
       *
     + * get_tree_entry_path(): <no extra argument, just get the common 'path'>
 -:  ----------- > 28:  3e7e0f7eb85 blame: emit a better error on 'git blame directory'
27:  e4a6fae1ae0 = 29:  ac1ccf13570 tree-walk.h API: add a tree_entry_extract_type() function
28:  766b4460a95 <  -:  ----------- tree-walk.h API users: rename "struct name_entry"'s "mode" to "raw_mode"
29:  4bdf94ae5c1 <  -:  ----------- tree.h API users: rename read_tree_fn_t's "mode" to "raw_mode"
30:  9d049fdbd00 <  -:  ----------- tree-walk.h API: move canon_mode() back out of decode_tree_entry()
-- 
2.31.0.rc2.211.g1d0b8788b3


^ permalink raw reply	[flat|nested] 262+ messages in thread

* [PATCH v2 01/29] diff.c: remove redundant canon_mode() call
  2021-03-08 15:06     ` [PATCH 00/30] tree-walk: mostly "mode" to "enum object_type" Ævar Arnfjörð Bjarmason
                         ` (2 preceding siblings ...)
  2021-03-16  2:12       ` [PATCH v2 00/29] tree-walk: mostly replace "mode" with " Ævar Arnfjörð Bjarmason
@ 2021-03-16  2:12       ` Ævar Arnfjörð Bjarmason
  2021-03-16  2:12       ` [PATCH v2 02/29] notes & match-trees: use name_entry's "pathlen" member Ævar Arnfjörð Bjarmason
                         ` (27 subsequent siblings)
  31 siblings, 0 replies; 262+ messages in thread
From: Ævar Arnfjörð Bjarmason @ 2021-03-16  2:12 UTC (permalink / raw)
  To: git
  Cc: Junio C Hamano, Elijah Newren, Kirill Smelkov,
	Nguyễn Thái Ngọc Duy,
	Ævar Arnfjörð Bjarmason

Remove a call to canon_mode() from fill_filespec(). This has been
redundant since the tree-walk.c API supplies it pre-canonicalized
since 7146e66f086 (tree-walk: finally switch over tree descriptors to
contain a pre-parsed entry, 2014-02-06).

This call to the predecessor of canon_mode() was added back in
4130b995719 ([PATCH] Diff updates to express type changes,
2005-05-26).

This was the only such call in the codebase. The rest are all either
one of these sorts of forms:

    canon_mode(st.st_mode); /* a stat(2) struct */
    canon_mode(S_IFREG | 0644) /* A compile-time literal */

Signed-off-by: Ævar Arnfjörð Bjarmason <avarab@gmail.com>
---
 diff.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/diff.c b/diff.c
index 6956f5e335c..bf46e6a4d8c 100644
--- a/diff.c
+++ b/diff.c
@@ -3846,7 +3846,7 @@ void fill_filespec(struct diff_filespec *spec, const struct object_id *oid,
 		   int oid_valid, unsigned short mode)
 {
 	if (mode) {
-		spec->mode = canon_mode(mode);
+		spec->mode = mode;
 		oidcpy(&spec->oid, oid);
 		spec->oid_valid = oid_valid;
 	}
-- 
2.31.0.rc2.211.g1d0b8788b3


^ permalink raw reply	[flat|nested] 262+ messages in thread

* [PATCH v2 02/29] notes & match-trees: use name_entry's "pathlen" member
  2021-03-08 15:06     ` [PATCH 00/30] tree-walk: mostly "mode" to "enum object_type" Ævar Arnfjörð Bjarmason
                         ` (3 preceding siblings ...)
  2021-03-16  2:12       ` [PATCH v2 01/29] diff.c: remove redundant canon_mode() call Ævar Arnfjörð Bjarmason
@ 2021-03-16  2:12       ` Ævar Arnfjörð Bjarmason
  2021-03-16  2:12       ` [PATCH v2 03/29] cache.h: add a comment to object_type() Ævar Arnfjörð Bjarmason
                         ` (26 subsequent siblings)
  31 siblings, 0 replies; 262+ messages in thread
From: Ævar Arnfjörð Bjarmason @ 2021-03-16  2:12 UTC (permalink / raw)
  To: git
  Cc: Junio C Hamano, Elijah Newren, Kirill Smelkov,
	Nguyễn Thái Ngọc Duy,
	Ævar Arnfjörð Bjarmason

Change code that was doing a strlen() on the "path" from a name_entry
struct to instead use the pathlen given to us by decode_tree_entry().

Signed-off-by: Ævar Arnfjörð Bjarmason <avarab@gmail.com>
---
 match-trees.c | 7 +++----
 notes.c       | 4 ++--
 2 files changed, 5 insertions(+), 6 deletions(-)

diff --git a/match-trees.c b/match-trees.c
index f6c194c1cca..1011357ad0c 100644
--- a/match-trees.c
+++ b/match-trees.c
@@ -197,9 +197,10 @@ static int splice_tree(const struct object_id *oid1, const char *prefix,
 	while (desc.size) {
 		const char *name;
 		unsigned short mode;
+		int len = tree_entry_len(&desc.entry);
 
 		tree_entry_extract(&desc, &name, &mode);
-		if (strlen(name) == toplen &&
+		if (len == toplen &&
 		    !memcmp(name, prefix, toplen)) {
 			if (!S_ISDIR(mode))
 				die("entry %s in tree %s is not a tree", name,
@@ -214,9 +215,7 @@ static int splice_tree(const struct object_id *oid1, const char *prefix,
 			 *   - to discard the "const"; this is OK because we
 			 *     know it points into our non-const "buf"
 			 */
-			rewrite_here = (unsigned char *)(desc.entry.path +
-							 strlen(desc.entry.path) +
-							 1);
+			rewrite_here = (unsigned char *)(name + len + 1);
 			break;
 		}
 		update_tree_entry(&desc);
diff --git a/notes.c b/notes.c
index d5ac081e76d..0a5b4fa1dbb 100644
--- a/notes.c
+++ b/notes.c
@@ -413,7 +413,7 @@ static void load_subtree(struct notes_tree *t, struct leaf_node *subtree,
 	while (tree_entry(&desc, &entry)) {
 		unsigned char type;
 		struct leaf_node *l;
-		size_t path_len = strlen(entry.path);
+		int path_len = entry.pathlen;
 
 		if (path_len == 2 * (hashsz - prefix_len)) {
 			/* This is potentially the remainder of the SHA-1 */
@@ -483,7 +483,7 @@ static void load_subtree(struct notes_tree *t, struct leaf_node *subtree,
 				strbuf_addch(&non_note_path, *q++);
 				strbuf_addch(&non_note_path, '/');
 			}
-			strbuf_addstr(&non_note_path, entry.path);
+			strbuf_add(&non_note_path, entry.path, path_len);
 			add_non_note(t, strbuf_detach(&non_note_path, NULL),
 				     entry.mode, entry.oid.hash);
 		}
-- 
2.31.0.rc2.211.g1d0b8788b3


^ permalink raw reply	[flat|nested] 262+ messages in thread

* [PATCH v2 03/29] cache.h: add a comment to object_type()
  2021-03-08 15:06     ` [PATCH 00/30] tree-walk: mostly "mode" to "enum object_type" Ævar Arnfjörð Bjarmason
                         ` (4 preceding siblings ...)
  2021-03-16  2:12       ` [PATCH v2 02/29] notes & match-trees: use name_entry's "pathlen" member Ævar Arnfjörð Bjarmason
@ 2021-03-16  2:12       ` Ævar Arnfjörð Bjarmason
  2021-03-16  2:12       ` [PATCH v2 04/29] tree-walk.h: add object_type member to name_entry Ævar Arnfjörð Bjarmason
                         ` (25 subsequent siblings)
  31 siblings, 0 replies; 262+ messages in thread
From: Ævar Arnfjörð Bjarmason @ 2021-03-16  2:12 UTC (permalink / raw)
  To: git
  Cc: Junio C Hamano, Elijah Newren, Kirill Smelkov,
	Nguyễn Thái Ngọc Duy,
	Ævar Arnfjörð Bjarmason

Add a comment to the object_type() function to explain what it
returns, and what the "mode" is in the "else" case.

The object_type() function dates back to 4d1012c3709 (Fix rev-list
when showing objects involving submodules, 2007-11-11). It's not
immediately obvious to someone looking at its history and how it's
come to be used.

Despite what Linus noted in 4d1012c3709 (Fix rev-list when showing
objects involving submodules, 2007-11-11) about wanting to move away
from users of object_type() relying on S_ISLNK(mode) being true here
we do currently rely on that. If this is changed to a condition to
only return OBJ_BLOB on S_ISREG(mode) then t4008, t4023 and t7415 will
have failing tests.

Signed-off-by: Ævar Arnfjörð Bjarmason <avarab@gmail.com>
---
 cache.h | 7 ++++++-
 1 file changed, 6 insertions(+), 1 deletion(-)

diff --git a/cache.h b/cache.h
index c2f8a8eadf6..ae0c0bef5c2 100644
--- a/cache.h
+++ b/cache.h
@@ -451,11 +451,16 @@ enum object_type {
 	OBJ_MAX
 };
 
+/*
+ * object_type() returns an object of a type that'll appear in a tree,
+ * so no OBJ_TAG is possible. This is mostly (and dates back to)
+ * consumers of the tree-walk.h API's "mode" field.
+ */
 static inline enum object_type object_type(unsigned int mode)
 {
 	return S_ISDIR(mode) ? OBJ_TREE :
 		S_ISGITLINK(mode) ? OBJ_COMMIT :
-		OBJ_BLOB;
+		OBJ_BLOB; /* S_ISREG(mode) || S_ISLNK(mode) */
 }
 
 /* Double-check local_repo_env below if you add to this list. */
-- 
2.31.0.rc2.211.g1d0b8788b3


^ permalink raw reply	[flat|nested] 262+ messages in thread

* [PATCH v2 04/29] tree-walk.h: add object_type member to name_entry
  2021-03-08 15:06     ` [PATCH 00/30] tree-walk: mostly "mode" to "enum object_type" Ævar Arnfjörð Bjarmason
                         ` (5 preceding siblings ...)
  2021-03-16  2:12       ` [PATCH v2 03/29] cache.h: add a comment to object_type() Ævar Arnfjörð Bjarmason
@ 2021-03-16  2:12       ` Ævar Arnfjörð Bjarmason
  2021-03-16  2:12       ` [PATCH v2 05/29] tree-walk.c: migrate to using new "object_type" field when possible Ævar Arnfjörð Bjarmason
                         ` (24 subsequent siblings)
  31 siblings, 0 replies; 262+ messages in thread
From: Ævar Arnfjörð Bjarmason @ 2021-03-16  2:12 UTC (permalink / raw)
  To: git
  Cc: Junio C Hamano, Elijah Newren, Kirill Smelkov,
	Nguyễn Thái Ngọc Duy,
	Ævar Arnfjörð Bjarmason

Most users of the tree walking API don't care what the specific mode
of an object in a tree is (e.g. if it's executable), they care if it's
one of OBJ_{TREE,BLOB,COMMIT}.

Let's add an "object_type" enum to the "name_entry" struct to help
such callers.

Ideally we'd have some subset of "enum object_type" here with just
those three entries, so we could rely on the C compiler to
exhaustively check our "switch" statements, but I don't know how to
create such a enum subset without re-labeling OBJ_{TREE,BLOB,COMMIT}
to e.g. "NE_OBJ_*" (an enum is just an int under the hood, so you can
use such a struct with "OBJ_*", but the compiler will complain...).

Signed-off-by: Ævar Arnfjörð Bjarmason <avarab@gmail.com>
---
 tree-walk.c | 4 +++-
 tree-walk.h | 2 ++
 2 files changed, 5 insertions(+), 1 deletion(-)

diff --git a/tree-walk.c b/tree-walk.c
index 2d6226d5f18..b210967b73b 100644
--- a/tree-walk.c
+++ b/tree-walk.c
@@ -47,7 +47,9 @@ static int decode_tree_entry(struct tree_desc *desc, const char *buf, unsigned l
 
 	/* Initialize the descriptor entry */
 	desc->entry.path = path;
-	desc->entry.mode = canon_mode(mode);
+	mode = canon_mode(mode);
+	desc->entry.mode = mode;
+	desc->entry.object_type = object_type(mode);
 	desc->entry.pathlen = len - 1;
 	hashcpy(desc->entry.oid.hash, (const unsigned char *)path + len);
 
diff --git a/tree-walk.h b/tree-walk.h
index a5058469e9b..9f3825d2773 100644
--- a/tree-walk.h
+++ b/tree-walk.h
@@ -17,6 +17,8 @@ struct name_entry {
 	const char *path;
 	int pathlen;
 	unsigned int mode;
+	/* simple 'mode': Only OBJ_{BLOB,TREE,COMMIT} */
+	enum object_type object_type;
 };
 
 /**
-- 
2.31.0.rc2.211.g1d0b8788b3


^ permalink raw reply	[flat|nested] 262+ messages in thread

* [PATCH v2 05/29] tree-walk.c: migrate to using new "object_type" field when possible
  2021-03-08 15:06     ` [PATCH 00/30] tree-walk: mostly "mode" to "enum object_type" Ævar Arnfjörð Bjarmason
                         ` (6 preceding siblings ...)
  2021-03-16  2:12       ` [PATCH v2 04/29] tree-walk.h: add object_type member to name_entry Ævar Arnfjörð Bjarmason
@ 2021-03-16  2:12       ` Ævar Arnfjörð Bjarmason
  2021-03-16  2:12       ` [PATCH v2 06/29] cache.h: have base_name_compare() take "is tree?", not "mode" Ævar Arnfjörð Bjarmason
                         ` (23 subsequent siblings)
  31 siblings, 0 replies; 262+ messages in thread
From: Ævar Arnfjörð Bjarmason @ 2021-03-16  2:12 UTC (permalink / raw)
  To: git
  Cc: Junio C Hamano, Elijah Newren, Kirill Smelkov,
	Nguyễn Thái Ngọc Duy,
	Ævar Arnfjörð Bjarmason

Signed-off-by: Ævar Arnfjörð Bjarmason <avarab@gmail.com>
---
 tree-walk.c | 24 +++++++++++++-----------
 1 file changed, 13 insertions(+), 11 deletions(-)

diff --git a/tree-walk.c b/tree-walk.c
index b210967b73b..6e9161901d8 100644
--- a/tree-walk.c
+++ b/tree-walk.c
@@ -521,7 +521,7 @@ int traverse_trees(struct index_state *istate,
 			if (!entry[i].path)
 				continue;
 			mask |= 1ul << i;
-			if (S_ISDIR(entry[i].mode))
+			if (entry[i].object_type == OBJ_TREE)
 				dirmask |= 1ul << i;
 			e = &entry[i];
 		}
@@ -892,8 +892,8 @@ static int match_entry(const struct pathspec_item *item,
 		 * nothing else (to handle 'submod/' and 'submod'
 		 * uniformly).
 		 */
-		if (!S_ISDIR(entry->mode) &&
-		    (!S_ISGITLINK(entry->mode) || matchlen > pathlen + 1))
+		if (entry->object_type != OBJ_TREE &&
+		    (entry->object_type != OBJ_COMMIT || matchlen > pathlen + 1))
 			return 0;
 	}
 
@@ -1038,7 +1038,7 @@ static enum interesting do_match(struct index_state *istate,
 		    ps->max_depth == -1)
 			return all_entries_interesting;
 		return within_depth(base->buf + base_offset, baselen,
-				    !!S_ISDIR(entry->mode),
+				    entry->object_type == OBJ_TREE,
 				    ps->max_depth) ?
 			entry_interesting : entry_not_interesting;
 	}
@@ -1071,7 +1071,7 @@ static enum interesting do_match(struct index_state *istate,
 
 			if (within_depth(base_str + matchlen + 1,
 					 baselen - matchlen - 1,
-					 !!S_ISDIR(entry->mode),
+					 entry->object_type == OBJ_TREE,
 					 ps->max_depth))
 				goto interesting;
 			else
@@ -1094,7 +1094,8 @@ static enum interesting do_match(struct index_state *istate,
 				 * Match all directories. We'll try to
 				 * match files later on.
 				 */
-				if (ps->recursive && S_ISDIR(entry->mode))
+				if (ps->recursive &&
+				    entry->object_type == OBJ_TREE)
 					return entry_interesting;
 
 				/*
@@ -1105,7 +1106,7 @@ static enum interesting do_match(struct index_state *istate,
 				 * be performed in the submodule itself.
 				 */
 				if (ps->recurse_submodules &&
-				    S_ISGITLINK(entry->mode) &&
+				    entry->object_type == OBJ_COMMIT &&
 				    !ps_strncmp(item, match + baselen,
 						entry->path,
 						item->nowildcard_len - baselen))
@@ -1154,7 +1155,8 @@ static enum interesting do_match(struct index_state *istate,
 		 * character.  More accurate matching can then
 		 * be performed in the submodule itself.
 		 */
-		if (ps->recurse_submodules && S_ISGITLINK(entry->mode) &&
+		if (ps->recurse_submodules &&
+		    entry->object_type == OBJ_COMMIT &&
 		    !ps_strncmp(item, match, base->buf + base_offset,
 				item->nowildcard_len)) {
 			strbuf_setlen(base, base_offset + baselen);
@@ -1170,7 +1172,7 @@ static enum interesting do_match(struct index_state *istate,
 		 * in future, see
 		 * https://lore.kernel.org/git/7vmxo5l2g4.fsf@alter.siamese.dyndns.org/
 		 */
-		if (ps->recursive && S_ISDIR(entry->mode))
+		if (ps->recursive && entry->object_type == OBJ_TREE)
 			return entry_interesting;
 		continue;
 interesting:
@@ -1193,7 +1195,7 @@ static enum interesting do_match(struct index_state *istate,
 			 * can probably return all_entries_interesting or
 			 * all_entries_not_interesting here if matched.
 			 */
-			if (S_ISDIR(entry->mode))
+			if (entry->object_type == OBJ_TREE)
 				return entry_interesting;
 
 			strbuf_add(base, entry->path, pathlen);
@@ -1269,7 +1271,7 @@ enum interesting tree_entry_interesting(struct index_state *istate,
 		return positive;
 
 	/* #15, #19 */
-	if (S_ISDIR(entry->mode) &&
+	if (entry->object_type == OBJ_TREE &&
 	    positive >= entry_interesting &&
 	    negative == entry_interesting)
 		return entry_interesting;
-- 
2.31.0.rc2.211.g1d0b8788b3


^ permalink raw reply	[flat|nested] 262+ messages in thread

* [PATCH v2 06/29] cache.h: have base_name_compare() take "is tree?", not "mode"
  2021-03-08 15:06     ` [PATCH 00/30] tree-walk: mostly "mode" to "enum object_type" Ævar Arnfjörð Bjarmason
                         ` (7 preceding siblings ...)
  2021-03-16  2:12       ` [PATCH v2 05/29] tree-walk.c: migrate to using new "object_type" field when possible Ævar Arnfjörð Bjarmason
@ 2021-03-16  2:12       ` Ævar Arnfjörð Bjarmason
  2021-03-16  5:49         ` Elijah Newren
  2021-03-16  2:12       ` [PATCH v2 07/29] tree-walk.h users: switch object_type(...) to new .object_type Ævar Arnfjörð Bjarmason
                         ` (22 subsequent siblings)
  31 siblings, 1 reply; 262+ messages in thread
From: Ævar Arnfjörð Bjarmason @ 2021-03-16  2:12 UTC (permalink / raw)
  To: git
  Cc: Junio C Hamano, Elijah Newren, Kirill Smelkov,
	Nguyễn Thái Ngọc Duy,
	Ævar Arnfjörð Bjarmason

Change the base_name_compare() API and the related df_name_compare()
function to take a boolean argument indicating whether the entry is a
tree or not, instead of having them call S_ISDIR(mode) on their own.

This makes use of the new "object_type" field in the "name_entry".

The API being modified here was originally added way back in
958ba6c96eb (Introduce "base_name_compare()" helper function,
2005-05-20).

Signed-off-by: Ævar Arnfjörð Bjarmason <avarab@gmail.com>
---
 builtin/fast-import.c |  8 ++++----
 builtin/mktree.c      |  4 ++--
 cache.h               |  4 ++--
 combine-diff.c        |  8 +++++---
 match-trees.c         |  6 ++++--
 merge-ort.c           |  4 ++--
 merge-recursive.c     |  6 +++---
 read-cache.c          | 16 ++++++++--------
 tree-diff.c           |  7 +++++--
 unpack-trees.c        | 15 ++++++++-------
 10 files changed, 43 insertions(+), 35 deletions(-)

diff --git a/builtin/fast-import.c b/builtin/fast-import.c
index dd4d09ceceb..ce4613c1595 100644
--- a/builtin/fast-import.c
+++ b/builtin/fast-import.c
@@ -1288,8 +1288,8 @@ static int tecmp0 (const void *_a, const void *_b)
 	struct tree_entry *a = *((struct tree_entry**)_a);
 	struct tree_entry *b = *((struct tree_entry**)_b);
 	return base_name_compare(
-		a->name->str_dat, a->name->str_len, a->versions[0].mode,
-		b->name->str_dat, b->name->str_len, b->versions[0].mode);
+		a->name->str_dat, a->name->str_len, 1,
+		b->name->str_dat, b->name->str_len, 1);
 }
 
 static int tecmp1 (const void *_a, const void *_b)
@@ -1297,8 +1297,8 @@ static int tecmp1 (const void *_a, const void *_b)
 	struct tree_entry *a = *((struct tree_entry**)_a);
 	struct tree_entry *b = *((struct tree_entry**)_b);
 	return base_name_compare(
-		a->name->str_dat, a->name->str_len, a->versions[1].mode,
-		b->name->str_dat, b->name->str_len, b->versions[1].mode);
+		a->name->str_dat, a->name->str_len, 1,
+		b->name->str_dat, b->name->str_len, 1);
 }
 
 static void mktree(struct tree_content *t, int v, struct strbuf *b)
diff --git a/builtin/mktree.c b/builtin/mktree.c
index 891991b00d6..2c1973229ac 100644
--- a/builtin/mktree.c
+++ b/builtin/mktree.c
@@ -37,8 +37,8 @@ static int ent_compare(const void *a_, const void *b_)
 {
 	struct treeent *a = *(struct treeent **)a_;
 	struct treeent *b = *(struct treeent **)b_;
-	return base_name_compare(a->name, a->len, a->mode,
-				 b->name, b->len, b->mode);
+	return base_name_compare(a->name, a->len, S_ISDIR(a->mode),
+				 b->name, b->len, S_ISDIR(b->mode));
 }
 
 static void write_tree(struct object_id *oid)
diff --git a/cache.h b/cache.h
index ae0c0bef5c2..e38b1e1688c 100644
--- a/cache.h
+++ b/cache.h
@@ -1506,8 +1506,8 @@ int repo_interpret_branch_name(struct repository *r,
 
 int validate_headref(const char *ref);
 
-int base_name_compare(const char *name1, int len1, int mode1, const char *name2, int len2, int mode2);
-int df_name_compare(const char *name1, int len1, int mode1, const char *name2, int len2, int mode2);
+int base_name_compare(const char *name1, int len1, int istree1, const char *name2, int len2, int istree2);
+int df_name_compare(const char *name1, int len1, int istree1, const char *name2, int len2, int istree2);
 int name_compare(const char *name1, size_t len1, const char *name2, size_t len2);
 int cache_name_stage_compare(const char *name1, int len1, int stage1, const char *name2, int len2, int stage2);
 
diff --git a/combine-diff.c b/combine-diff.c
index 9228aebc16b..ad7058a6f5d 100644
--- a/combine-diff.c
+++ b/combine-diff.c
@@ -16,11 +16,13 @@
 static int compare_paths(const struct combine_diff_path *one,
 			  const struct diff_filespec *two)
 {
-	if (!S_ISDIR(one->mode) && !S_ISDIR(two->mode))
+	int istree_one = S_ISDIR(one->mode);
+	int istree_two = S_ISDIR(two->mode);
+	if (!istree_one && !istree_two)
 		return strcmp(one->path, two->path);
 
-	return base_name_compare(one->path, strlen(one->path), one->mode,
-				 two->path, strlen(two->path), two->mode);
+	return base_name_compare(one->path, strlen(one->path), istree_one,
+				 two->path, strlen(two->path), istree_two);
 }
 
 static int filename_changed(char status)
diff --git a/match-trees.c b/match-trees.c
index 1011357ad0c..a28c19a62a5 100644
--- a/match-trees.c
+++ b/match-trees.c
@@ -67,8 +67,10 @@ static void *fill_tree_desc_strict(struct tree_desc *desc,
 static int base_name_entries_compare(const struct name_entry *a,
 				     const struct name_entry *b)
 {
-	return base_name_compare(a->path, tree_entry_len(a), a->mode,
-				 b->path, tree_entry_len(b), b->mode);
+	int istree_a = (a->object_type == OBJ_TREE);
+	int istree_b = (b->object_type == OBJ_TREE);
+	return base_name_compare(a->path, tree_entry_len(a), istree_a,
+				 b->path, tree_entry_len(b), istree_b);
 }
 
 /*
diff --git a/merge-ort.c b/merge-ort.c
index 603d30c5217..4075d13aaab 100644
--- a/merge-ort.c
+++ b/merge-ort.c
@@ -2390,8 +2390,8 @@ static int tree_entry_order(const void *a_, const void *b_)
 
 	const struct merged_info *ami = a->util;
 	const struct merged_info *bmi = b->util;
-	return base_name_compare(a->string, strlen(a->string), ami->result.mode,
-				 b->string, strlen(b->string), bmi->result.mode);
+	return base_name_compare(a->string, strlen(a->string), S_ISDIR(ami->result.mode),
+				 b->string, strlen(b->string), S_ISDIR(bmi->result.mode));
 }
 
 static void write_tree(struct object_id *result_oid,
diff --git a/merge-recursive.c b/merge-recursive.c
index 3d9207455b3..1c9b08695a3 100644
--- a/merge-recursive.c
+++ b/merge-recursive.c
@@ -554,12 +554,12 @@ static int string_list_df_name_compare(const char *one, const char *two)
 	 *
 	 * To achieve this, we sort with df_name_compare and provide
 	 * the mode S_IFDIR so that D/F conflicts will sort correctly.
-	 * We use the mode S_IFDIR for everything else for simplicity,
+	 * We say we have a directory for everything else for simplicity,
 	 * since in other cases any changes in their order due to
 	 * sorting cause no problems for us.
 	 */
-	int cmp = df_name_compare(one, onelen, S_IFDIR,
-				  two, twolen, S_IFDIR);
+	int cmp = df_name_compare(one, onelen, 1, two, twolen, 1);
+
 	/*
 	 * Now that 'foo' and 'foo/bar' compare equal, we have to make sure
 	 * that 'foo' comes before 'foo/bar'.
diff --git a/read-cache.c b/read-cache.c
index 1e9a50c6c73..4257fbd8a08 100644
--- a/read-cache.c
+++ b/read-cache.c
@@ -462,8 +462,8 @@ int ie_modified(struct index_state *istate,
 	return 0;
 }
 
-int base_name_compare(const char *name1, int len1, int mode1,
-		      const char *name2, int len2, int mode2)
+int base_name_compare(const char *name1, int len1, int istree1,
+		      const char *name2, int len2, int istree2)
 {
 	unsigned char c1, c2;
 	int len = len1 < len2 ? len1 : len2;
@@ -474,9 +474,9 @@ int base_name_compare(const char *name1, int len1, int mode1,
 		return cmp;
 	c1 = name1[len];
 	c2 = name2[len];
-	if (!c1 && S_ISDIR(mode1))
+	if (!c1 && istree1)
 		c1 = '/';
-	if (!c2 && S_ISDIR(mode2))
+	if (!c2 && istree2)
 		c2 = '/';
 	return (c1 < c2) ? -1 : (c1 > c2) ? 1 : 0;
 }
@@ -491,8 +491,8 @@ int base_name_compare(const char *name1, int len1, int mode1,
  * This is used by routines that want to traverse the git namespace
  * but then handle conflicting entries together when possible.
  */
-int df_name_compare(const char *name1, int len1, int mode1,
-		    const char *name2, int len2, int mode2)
+int df_name_compare(const char *name1, int len1, int istree1,
+		    const char *name2, int len2, int istree2)
 {
 	int len = len1 < len2 ? len1 : len2, cmp;
 	unsigned char c1, c2;
@@ -504,10 +504,10 @@ int df_name_compare(const char *name1, int len1, int mode1,
 	if (len1 == len2)
 		return 0;
 	c1 = name1[len];
-	if (!c1 && S_ISDIR(mode1))
+	if (!c1 && istree1)
 		c1 = '/';
 	c2 = name2[len];
-	if (!c2 && S_ISDIR(mode2))
+	if (!c2 && istree2)
 		c2 = '/';
 	if (c1 == '/' && !c2)
 		return 0;
diff --git a/tree-diff.c b/tree-diff.c
index 7cebbb327e2..6ec180331fb 100644
--- a/tree-diff.c
+++ b/tree-diff.c
@@ -50,6 +50,7 @@ static int tree_entry_pathcmp(struct tree_desc *t1, struct tree_desc *t2)
 {
 	struct name_entry *e1, *e2;
 	int cmp;
+	int istree_e1, istree_e2;
 
 	/* empty descriptors sort after valid tree entries */
 	if (!t1->size)
@@ -58,9 +59,11 @@ static int tree_entry_pathcmp(struct tree_desc *t1, struct tree_desc *t2)
 		return -1;
 
 	e1 = &t1->entry;
+	istree_e1 = (e1->object_type == OBJ_TREE);
 	e2 = &t2->entry;
-	cmp = base_name_compare(e1->path, tree_entry_len(e1), e1->mode,
-				e2->path, tree_entry_len(e2), e2->mode);
+	istree_e2 = (e2->object_type == OBJ_TREE);
+	cmp = base_name_compare(e1->path, tree_entry_len(e1), istree_e1,
+				e2->path, tree_entry_len(e2), istree_e2);
 	return cmp;
 }
 
diff --git a/unpack-trees.c b/unpack-trees.c
index eb8fcda31ba..d9d573df986 100644
--- a/unpack-trees.c
+++ b/unpack-trees.c
@@ -925,7 +925,7 @@ static int traverse_trees_recursive(int n, unsigned long dirmask,
 static int do_compare_entry_piecewise(const struct cache_entry *ce,
 				      const struct traverse_info *info,
 				      const char *name, size_t namelen,
-				      unsigned mode)
+				      unsigned istree)
 {
 	int pathlen, ce_len;
 	const char *ce_name;
@@ -933,7 +933,7 @@ static int do_compare_entry_piecewise(const struct cache_entry *ce,
 	if (info->prev) {
 		int cmp = do_compare_entry_piecewise(ce, info->prev,
 						     info->name, info->namelen,
-						     info->mode);
+						     S_ISDIR(info->mode));
 		if (cmp)
 			return cmp;
 	}
@@ -947,13 +947,13 @@ static int do_compare_entry_piecewise(const struct cache_entry *ce,
 	ce_len -= pathlen;
 	ce_name = ce->name + pathlen;
 
-	return df_name_compare(ce_name, ce_len, S_IFREG, name, namelen, mode);
+	return df_name_compare(ce_name, ce_len, 0, name, namelen, istree);
 }
 
 static int do_compare_entry(const struct cache_entry *ce,
 			    const struct traverse_info *info,
 			    const char *name, size_t namelen,
-			    unsigned mode)
+			    unsigned istree)
 {
 	int pathlen, ce_len;
 	const char *ce_name;
@@ -965,7 +965,7 @@ static int do_compare_entry(const struct cache_entry *ce,
 	 * it is quicker to use the precomputed version.
 	 */
 	if (!info->traverse_path)
-		return do_compare_entry_piecewise(ce, info, name, namelen, mode);
+		return do_compare_entry_piecewise(ce, info, name, namelen, istree);
 
 	cmp = strncmp(ce->name, info->traverse_path, info->pathlen);
 	if (cmp)
@@ -980,12 +980,13 @@ static int do_compare_entry(const struct cache_entry *ce,
 	ce_len -= pathlen;
 	ce_name = ce->name + pathlen;
 
-	return df_name_compare(ce_name, ce_len, S_IFREG, name, namelen, mode);
+	return df_name_compare(ce_name, ce_len, 0, name, namelen, istree);
 }
 
 static int compare_entry(const struct cache_entry *ce, const struct traverse_info *info, const struct name_entry *n)
 {
-	int cmp = do_compare_entry(ce, info, n->path, n->pathlen, n->mode);
+	int istree = (n->object_type == OBJ_TREE);
+	int cmp = do_compare_entry(ce, info, n->path, n->pathlen, istree);
 	if (cmp)
 		return cmp;
 
-- 
2.31.0.rc2.211.g1d0b8788b3


^ permalink raw reply	[flat|nested] 262+ messages in thread

* [PATCH v2 07/29] tree-walk.h users: switch object_type(...) to new .object_type
  2021-03-08 15:06     ` [PATCH 00/30] tree-walk: mostly "mode" to "enum object_type" Ævar Arnfjörð Bjarmason
                         ` (8 preceding siblings ...)
  2021-03-16  2:12       ` [PATCH v2 06/29] cache.h: have base_name_compare() take "is tree?", not "mode" Ævar Arnfjörð Bjarmason
@ 2021-03-16  2:12       ` Ævar Arnfjörð Bjarmason
  2021-03-16  2:12       ` [PATCH v2 08/29] tree.h: format argument lists of read_tree_recursive() users Ævar Arnfjörð Bjarmason
                         ` (21 subsequent siblings)
  31 siblings, 0 replies; 262+ messages in thread
From: Ævar Arnfjörð Bjarmason @ 2021-03-16  2:12 UTC (permalink / raw)
  To: git
  Cc: Junio C Hamano, Elijah Newren, Kirill Smelkov,
	Nguyễn Thái Ngọc Duy,
	Ævar Arnfjörð Bjarmason

Change uses of object_type(entry.mode) to use the new
entry.object_type field.

Signed-off-by: Ævar Arnfjörð Bjarmason <avarab@gmail.com>
---
 builtin/pack-objects.c |  2 +-
 http-push.c            |  6 ++++--
 pack-bitmap-write.c    |  8 +++++---
 revision.c             | 12 ++++++++----
 4 files changed, 18 insertions(+), 10 deletions(-)

diff --git a/builtin/pack-objects.c b/builtin/pack-objects.c
index 6d62aaf59a0..d3ba1d4a4a6 100644
--- a/builtin/pack-objects.c
+++ b/builtin/pack-objects.c
@@ -1534,7 +1534,7 @@ static void add_pbase_object(struct tree_desc *tree,
 			return;
 		if (name[cmplen] != '/') {
 			add_object_entry(&entry.oid,
-					 object_type(entry.mode),
+					 entry.object_type,
 					 fullname, 1);
 			return;
 		}
diff --git a/http-push.c b/http-push.c
index 6a4a43e07f2..234b79a5dba 100644
--- a/http-push.c
+++ b/http-push.c
@@ -1314,7 +1314,7 @@ static struct object_list **process_tree(struct tree *tree,
 	init_tree_desc(&desc, tree->buffer, tree->size);
 
 	while (tree_entry(&desc, &entry))
-		switch (object_type(entry.mode)) {
+		switch (entry.object_type) {
 		case OBJ_TREE:
 			p = process_tree(lookup_tree(the_repository, &entry.oid),
 					 p);
@@ -1323,9 +1323,11 @@ static struct object_list **process_tree(struct tree *tree,
 			p = process_blob(lookup_blob(the_repository, &entry.oid),
 					 p);
 			break;
-		default:
+		case OBJ_COMMIT:
 			/* Subproject commit - not in this repository */
 			break;
+		default:
+			BUG("unreachable");
 		}
 
 	free_tree_buffer(tree);
diff --git a/pack-bitmap-write.c b/pack-bitmap-write.c
index 88d9e696a54..ac32bf2242c 100644
--- a/pack-bitmap-write.c
+++ b/pack-bitmap-write.c
@@ -353,7 +353,7 @@ static void fill_bitmap_tree(struct bitmap *bitmap,
 	init_tree_desc(&desc, tree->buffer, tree->size);
 
 	while (tree_entry(&desc, &entry)) {
-		switch (object_type(entry.mode)) {
+		switch (entry.object_type) {
 		case OBJ_TREE:
 			fill_bitmap_tree(bitmap,
 					 lookup_tree(the_repository, &entry.oid));
@@ -361,9 +361,11 @@ static void fill_bitmap_tree(struct bitmap *bitmap,
 		case OBJ_BLOB:
 			bitmap_set(bitmap, find_object_pos(&entry.oid));
 			break;
-		default:
-			/* Gitlink, etc; not reachable */
+		case OBJ_COMMIT:
+			/* submodule commit - not in this repository */
 			break;
+		default:
+			BUG("unreachable");
 		}
 	}
 
diff --git a/revision.c b/revision.c
index b78733f5089..1db4e4e90a2 100644
--- a/revision.c
+++ b/revision.c
@@ -72,16 +72,18 @@ static void mark_tree_contents_uninteresting(struct repository *r,
 
 	init_tree_desc(&desc, tree->buffer, tree->size);
 	while (tree_entry(&desc, &entry)) {
-		switch (object_type(entry.mode)) {
+		switch (entry.object_type) {
 		case OBJ_TREE:
 			mark_tree_uninteresting(r, lookup_tree(r, &entry.oid));
 			break;
 		case OBJ_BLOB:
 			mark_blob_uninteresting(lookup_blob(r, &entry.oid));
 			break;
-		default:
+		case OBJ_COMMIT:
 			/* Subproject commit - not in this repository */
 			break;
+		default:
+			BUG("unreachable");
 		}
 	}
 
@@ -179,7 +181,7 @@ static void add_children_by_path(struct repository *r,
 
 	init_tree_desc(&desc, tree->buffer, tree->size);
 	while (tree_entry(&desc, &entry)) {
-		switch (object_type(entry.mode)) {
+		switch (entry.object_type) {
 		case OBJ_TREE:
 			paths_and_oids_insert(map, entry.path, &entry.oid);
 
@@ -196,9 +198,11 @@ static void add_children_by_path(struct repository *r,
 					child->object.flags |= UNINTERESTING;
 			}
 			break;
-		default:
+		case OBJ_COMMIT:
 			/* Subproject commit - not in this repository */
 			break;
+		default:
+			BUG("unreachable");
 		}
 	}
 
-- 
2.31.0.rc2.211.g1d0b8788b3


^ permalink raw reply	[flat|nested] 262+ messages in thread

* [PATCH v2 08/29] tree.h: format argument lists of read_tree_recursive() users
  2021-03-08 15:06     ` [PATCH 00/30] tree-walk: mostly "mode" to "enum object_type" Ævar Arnfjörð Bjarmason
                         ` (9 preceding siblings ...)
  2021-03-16  2:12       ` [PATCH v2 07/29] tree-walk.h users: switch object_type(...) to new .object_type Ævar Arnfjörð Bjarmason
@ 2021-03-16  2:12       ` Ævar Arnfjörð Bjarmason
  2021-03-16  2:12       ` [PATCH v2 09/29] tree.h users: format argument lists in archive.c Ævar Arnfjörð Bjarmason
                         ` (20 subsequent siblings)
  31 siblings, 0 replies; 262+ messages in thread
From: Ævar Arnfjörð Bjarmason @ 2021-03-16  2:12 UTC (permalink / raw)
  To: git
  Cc: Junio C Hamano, Elijah Newren, Kirill Smelkov,
	Nguyễn Thái Ngọc Duy,
	Ævar Arnfjörð Bjarmason

In preparation for adding a new argument to read_tree_fn_t re-indent
and format the argument list of read_tree_recursive() callbacks, and
the relevant functions they call.

This is a whitespace-only change to make reading subsequent commits
easier. I'll be adding a new argument on the "mode" line, so leave
space on it.

Signed-off-by: Ævar Arnfjörð Bjarmason <avarab@gmail.com>
---
 archive.c          | 14 +++++++++-----
 builtin/checkout.c |  4 +++-
 builtin/log.c      |  5 +++--
 builtin/ls-tree.c  |  4 +++-
 merge-recursive.c  |  3 ++-
 tree.h             |  5 ++++-
 6 files changed, 24 insertions(+), 11 deletions(-)

diff --git a/archive.c b/archive.c
index c19300ecb9b..77d1238df98 100644
--- a/archive.c
+++ b/archive.c
@@ -138,8 +138,10 @@ static int check_attr_export_subst(const struct attr_check *check)
 }
 
 static int write_archive_entry(const struct object_id *oid, const char *base,
-		int baselen, const char *filename, unsigned mode, int stage,
-		void *context)
+			       int baselen, const char *filename,
+			       unsigned mode,
+			       int stage,
+			       void *context)
 {
 	static struct strbuf path = STRBUF_INIT;
 	struct archiver_context *c = context;
@@ -230,8 +232,9 @@ static int write_directory(struct archiver_context *c)
 }
 
 static int queue_or_write_archive_entry(const struct object_id *oid,
-		struct strbuf *base, const char *filename,
-		unsigned mode, void *context)
+					struct strbuf *base, const char *filename,
+					unsigned mode,
+					void *context)
 {
 	struct archiver_context *c = context;
 	int stage = 0;
@@ -378,7 +381,8 @@ struct path_exists_context {
 };
 
 static int reject_entry(const struct object_id *oid, struct strbuf *base,
-			const char *filename, unsigned mode,
+			const char *filename,
+			unsigned mode,
 			void *context)
 {
 	int ret = -1;
diff --git a/builtin/checkout.c b/builtin/checkout.c
index 0e663905200..0887352db2a 100644
--- a/builtin/checkout.c
+++ b/builtin/checkout.c
@@ -114,7 +114,9 @@ static int post_checkout_hook(struct commit *old_commit, struct commit *new_comm
 }
 
 static int update_some(const struct object_id *oid, struct strbuf *base,
-		const char *pathname, unsigned mode, void *context)
+		       const char *pathname,
+		       unsigned mode,
+		       void *context)
 {
 	int len;
 	struct cache_entry *ce;
diff --git a/builtin/log.c b/builtin/log.c
index 980de590638..b7b76856a9f 100644
--- a/builtin/log.c
+++ b/builtin/log.c
@@ -598,8 +598,9 @@ static int show_tag_object(const struct object_id *oid, struct rev_info *rev)
 }
 
 static int show_tree_object(const struct object_id *oid,
-		struct strbuf *base,
-		const char *pathname, unsigned mode, void *context)
+			    struct strbuf *base, const char *pathname,
+			    unsigned mode,
+			    void *context)
 {
 	FILE *file = context;
 	fprintf(file, "%s%s\n", pathname, S_ISDIR(mode) ? "/" : "");
diff --git a/builtin/ls-tree.c b/builtin/ls-tree.c
index 3a442631c71..8d5c3fd0582 100644
--- a/builtin/ls-tree.c
+++ b/builtin/ls-tree.c
@@ -62,7 +62,9 @@ static int show_recursive(const char *base, int baselen, const char *pathname)
 }
 
 static int show_tree(const struct object_id *oid, struct strbuf *base,
-		const char *pathname, unsigned mode, void *context)
+		     const char *pathname,
+		     unsigned mode,
+		     void *context)
 {
 	int retval = 0;
 	int baselen;
diff --git a/merge-recursive.c b/merge-recursive.c
index 1c9b08695a3..689a3e00070 100644
--- a/merge-recursive.c
+++ b/merge-recursive.c
@@ -453,7 +453,8 @@ static void unpack_trees_finish(struct merge_options *opt)
 
 static int save_files_dirs(const struct object_id *oid,
 			   struct strbuf *base, const char *path,
-			   unsigned int mode, void *context)
+			   unsigned int mode,
+			   void *context)
 {
 	struct path_hashmap_entry *entry;
 	int baselen = base->len;
diff --git a/tree.h b/tree.h
index f0b079d2e91..c1a936fdc49 100644
--- a/tree.h
+++ b/tree.h
@@ -31,7 +31,10 @@ struct tree *parse_tree_indirect(const struct object_id *oid);
 int cmp_cache_name_compare(const void *a_, const void *b_);
 
 #define READ_TREE_RECURSIVE 1
-typedef int (*read_tree_fn_t)(const struct object_id *, struct strbuf *, const char *, unsigned int, void *);
+typedef int (*read_tree_fn_t)(const struct object_id *, struct strbuf *,
+			      const char *,
+			      unsigned int,
+			      void *);
 
 int read_tree_at(struct repository *r,
 		 struct tree *tree,
-- 
2.31.0.rc2.211.g1d0b8788b3


^ permalink raw reply	[flat|nested] 262+ messages in thread

* [PATCH v2 09/29] tree.h users: format argument lists in archive.c
  2021-03-08 15:06     ` [PATCH 00/30] tree-walk: mostly "mode" to "enum object_type" Ævar Arnfjörð Bjarmason
                         ` (10 preceding siblings ...)
  2021-03-16  2:12       ` [PATCH v2 08/29] tree.h: format argument lists of read_tree_recursive() users Ævar Arnfjörð Bjarmason
@ 2021-03-16  2:12       ` Ævar Arnfjörð Bjarmason
  2021-03-16  2:12       ` [PATCH v2 10/29] archive: get rid of 'stage' parameter Ævar Arnfjörð Bjarmason
                         ` (19 subsequent siblings)
  31 siblings, 0 replies; 262+ messages in thread
From: Ævar Arnfjörð Bjarmason @ 2021-03-16  2:12 UTC (permalink / raw)
  To: git
  Cc: Junio C Hamano, Elijah Newren, Kirill Smelkov,
	Nguyễn Thái Ngọc Duy,
	Ævar Arnfjörð Bjarmason

Re-indent and re-flow the argument lists archive.c has downstream of
its read_tree_recursive() call to make subsequent commits easier to
read, as I only expect to be modifying the "stage" and "mode" lines.

Signed-off-by: Ævar Arnfjörð Bjarmason <avarab@gmail.com>
---
 archive.c | 22 +++++++++++++++-------
 1 file changed, 15 insertions(+), 7 deletions(-)

diff --git a/archive.c b/archive.c
index 77d1238df98..8ff97751c23 100644
--- a/archive.c
+++ b/archive.c
@@ -198,8 +198,10 @@ static int write_archive_entry(const struct object_id *oid, const char *base,
 }
 
 static void queue_directory(const unsigned char *sha1,
-		struct strbuf *base, const char *filename,
-		unsigned mode, int stage, struct archiver_context *c)
+			    struct strbuf *base, const char *filename,
+			    unsigned mode,
+			    int stage,
+			    struct archiver_context *c)
 {
 	struct directory *d;
 	size_t len = st_add4(base->len, 1, strlen(filename), 1);
@@ -225,8 +227,10 @@ static int write_directory(struct archiver_context *c)
 	ret =
 		write_directory(c) ||
 		write_archive_entry(&d->oid, d->path, d->baselen,
-				    d->path + d->baselen, d->mode,
-				    d->stage, c) != READ_TREE_RECURSIVE;
+				    d->path + d->baselen,
+				    d->mode,
+				    d->stage,
+				    c) != READ_TREE_RECURSIVE;
 	free(d);
 	return ret ? -1 : 0;
 }
@@ -260,14 +264,18 @@ static int queue_or_write_archive_entry(const struct object_id *oid,
 		if (check_attr_export_ignore(check))
 			return 0;
 		queue_directory(oid->hash, base, filename,
-				mode, stage, c);
+				mode,
+				stage,
+				c);
 		return READ_TREE_RECURSIVE;
 	}
 
 	if (write_directory(c))
 		return -1;
-	return write_archive_entry(oid, base->buf, base->len, filename, mode,
-				   stage, context);
+	return write_archive_entry(oid, base->buf, base->len, filename,
+				   mode,
+				   stage,
+				   context);
 }
 
 struct extra_file_info {
-- 
2.31.0.rc2.211.g1d0b8788b3


^ permalink raw reply	[flat|nested] 262+ messages in thread

* [PATCH v2 10/29] archive: get rid of 'stage' parameter
  2021-03-08 15:06     ` [PATCH 00/30] tree-walk: mostly "mode" to "enum object_type" Ævar Arnfjörð Bjarmason
                         ` (11 preceding siblings ...)
  2021-03-16  2:12       ` [PATCH v2 09/29] tree.h users: format argument lists in archive.c Ævar Arnfjörð Bjarmason
@ 2021-03-16  2:12       ` Ævar Arnfjörð Bjarmason
  2021-03-16  2:12       ` [PATCH v2 11/29] tree.h API: make read_tree_fn_t take an "enum object_type" Ævar Arnfjörð Bjarmason
                         ` (18 subsequent siblings)
  31 siblings, 0 replies; 262+ messages in thread
From: Ævar Arnfjörð Bjarmason @ 2021-03-16  2:12 UTC (permalink / raw)
  To: git
  Cc: Junio C Hamano, Elijah Newren, Kirill Smelkov,
	Nguyễn Thái Ngọc Duy,
	Ævar Arnfjörð Bjarmason

Stop passing the "stage" parameter around in archive.c. This parameter
existed because the read_tree_recursive() function used to provide it,
but no longer does. See my in-flight commit to remove it. (tree.h API:
remove "stage" parameter from read_tree_recursive(), 2021-03-06).

As can be seen in 562e25abea9 (archive: centralize archive entry
writing, 2008-07-14) and ed22b4173bd (archive: support filtering paths
with glob, 2014-09-21) it was never used by this code. We simply added
it as a boilerplate, and then later added it to our own "directory
"struct.

Signed-off-by: Ævar Arnfjörð Bjarmason <avarab@gmail.com>
---
 archive.c | 8 --------
 1 file changed, 8 deletions(-)

diff --git a/archive.c b/archive.c
index 8ff97751c23..529623167c9 100644
--- a/archive.c
+++ b/archive.c
@@ -107,7 +107,6 @@ struct directory {
 	struct object_id oid;
 	int baselen, len;
 	unsigned mode;
-	int stage;
 	char path[FLEX_ARRAY];
 };
 
@@ -140,7 +139,6 @@ static int check_attr_export_subst(const struct attr_check *check)
 static int write_archive_entry(const struct object_id *oid, const char *base,
 			       int baselen, const char *filename,
 			       unsigned mode,
-			       int stage,
 			       void *context)
 {
 	static struct strbuf path = STRBUF_INIT;
@@ -200,7 +198,6 @@ static int write_archive_entry(const struct object_id *oid, const char *base,
 static void queue_directory(const unsigned char *sha1,
 			    struct strbuf *base, const char *filename,
 			    unsigned mode,
-			    int stage,
 			    struct archiver_context *c)
 {
 	struct directory *d;
@@ -209,7 +206,6 @@ static void queue_directory(const unsigned char *sha1,
 	d->up	   = c->bottom;
 	d->baselen = base->len;
 	d->mode	   = mode;
-	d->stage   = stage;
 	c->bottom  = d;
 	d->len = xsnprintf(d->path, len, "%.*s%s/", (int)base->len, base->buf, filename);
 	hashcpy(d->oid.hash, sha1);
@@ -229,7 +225,6 @@ static int write_directory(struct archiver_context *c)
 		write_archive_entry(&d->oid, d->path, d->baselen,
 				    d->path + d->baselen,
 				    d->mode,
-				    d->stage,
 				    c) != READ_TREE_RECURSIVE;
 	free(d);
 	return ret ? -1 : 0;
@@ -241,7 +236,6 @@ static int queue_or_write_archive_entry(const struct object_id *oid,
 					void *context)
 {
 	struct archiver_context *c = context;
-	int stage = 0;
 
 	while (c->bottom &&
 	       !(base->len >= c->bottom->len &&
@@ -265,7 +259,6 @@ static int queue_or_write_archive_entry(const struct object_id *oid,
 			return 0;
 		queue_directory(oid->hash, base, filename,
 				mode,
-				stage,
 				c);
 		return READ_TREE_RECURSIVE;
 	}
@@ -274,7 +267,6 @@ static int queue_or_write_archive_entry(const struct object_id *oid,
 		return -1;
 	return write_archive_entry(oid, base->buf, base->len, filename,
 				   mode,
-				   stage,
 				   context);
 }
 
-- 
2.31.0.rc2.211.g1d0b8788b3


^ permalink raw reply	[flat|nested] 262+ messages in thread

* [PATCH v2 11/29] tree.h API: make read_tree_fn_t take an "enum object_type"
  2021-03-08 15:06     ` [PATCH 00/30] tree-walk: mostly "mode" to "enum object_type" Ævar Arnfjörð Bjarmason
                         ` (12 preceding siblings ...)
  2021-03-16  2:12       ` [PATCH v2 10/29] archive: get rid of 'stage' parameter Ævar Arnfjörð Bjarmason
@ 2021-03-16  2:12       ` Ævar Arnfjörð Bjarmason
  2021-03-16  2:12       ` [PATCH v2 12/29] tree-walk.h users: migrate "p->mode &&" pattern Ævar Arnfjörð Bjarmason
                         ` (17 subsequent siblings)
  31 siblings, 0 replies; 262+ messages in thread
From: Ævar Arnfjörð Bjarmason @ 2021-03-16  2:12 UTC (permalink / raw)
  To: git
  Cc: Junio C Hamano, Elijah Newren, Kirill Smelkov,
	Nguyễn Thái Ngọc Duy,
	Ævar Arnfjörð Bjarmason

Most of the users of the read_tree_fn_t callback do not care about the
"mode" per-se, they just care what type it resolves to.

Amend this callback mechanism added in 3c5e8468a93 (ls-tree: major
rewrite to do pathspec, 2005-11-26) to pass the object_type, and use
it whenever possible.

In the archive.c code we could go much deeper with this refactoring,
after getting the "mode" that code will pass it around itself and into
archive-{tar,zip}.c. As far as I can tell we could drop the mode
early, and just pass "enum_object_type type, int is_executable". That
would be slightly redundant space-wise, but would assure us that we're
not writing out raw modes found in trees, but are normalizing them.

But that particular refactoring would be larger than what I'm trying
to accomplish here, so let's leave it for now.

Signed-off-by: Ævar Arnfjörð Bjarmason <avarab@gmail.com>
---
 archive.c          |  8 ++++----
 builtin/checkout.c |  4 ++--
 builtin/log.c      |  4 ++--
 builtin/ls-files.c |  6 ++++--
 builtin/ls-tree.c  | 12 +++++-------
 merge-recursive.c  |  6 ++++--
 tree.c             | 19 ++++++++++++-------
 tree.h             |  2 +-
 8 files changed, 34 insertions(+), 27 deletions(-)

diff --git a/archive.c b/archive.c
index 529623167c9..254e15c8d03 100644
--- a/archive.c
+++ b/archive.c
@@ -232,7 +232,7 @@ static int write_directory(struct archiver_context *c)
 
 static int queue_or_write_archive_entry(const struct object_id *oid,
 					struct strbuf *base, const char *filename,
-					unsigned mode,
+					enum object_type object_type, unsigned mode,
 					void *context)
 {
 	struct archiver_context *c = context;
@@ -245,7 +245,7 @@ static int queue_or_write_archive_entry(const struct object_id *oid,
 		c->bottom = next;
 	}
 
-	if (S_ISDIR(mode)) {
+	if (object_type == OBJ_TREE) {
 		size_t baselen = base->len;
 		const struct attr_check *check;
 
@@ -382,13 +382,13 @@ struct path_exists_context {
 
 static int reject_entry(const struct object_id *oid, struct strbuf *base,
 			const char *filename,
-			unsigned mode,
+			enum object_type object_type, unsigned mode,
 			void *context)
 {
 	int ret = -1;
 	struct path_exists_context *ctx = context;
 
-	if (S_ISDIR(mode)) {
+	if (object_type == OBJ_TREE) {
 		struct strbuf sb = STRBUF_INIT;
 		strbuf_addbuf(&sb, base);
 		strbuf_addstr(&sb, filename);
diff --git a/builtin/checkout.c b/builtin/checkout.c
index 0887352db2a..95b2b0edf22 100644
--- a/builtin/checkout.c
+++ b/builtin/checkout.c
@@ -115,14 +115,14 @@ static int post_checkout_hook(struct commit *old_commit, struct commit *new_comm
 
 static int update_some(const struct object_id *oid, struct strbuf *base,
 		       const char *pathname,
-		       unsigned mode,
+		       enum object_type object_type, unsigned mode,
 		       void *context)
 {
 	int len;
 	struct cache_entry *ce;
 	int pos;
 
-	if (S_ISDIR(mode))
+	if (object_type == OBJ_TREE)
 		return READ_TREE_RECURSIVE;
 
 	len = base->len + strlen(pathname);
diff --git a/builtin/log.c b/builtin/log.c
index b7b76856a9f..c25f75472ff 100644
--- a/builtin/log.c
+++ b/builtin/log.c
@@ -599,11 +599,11 @@ static int show_tag_object(const struct object_id *oid, struct rev_info *rev)
 
 static int show_tree_object(const struct object_id *oid,
 			    struct strbuf *base, const char *pathname,
-			    unsigned mode,
+			    enum object_type object_type, unsigned mode,
 			    void *context)
 {
 	FILE *file = context;
-	fprintf(file, "%s%s\n", pathname, S_ISDIR(mode) ? "/" : "");
+	fprintf(file, "%s%s\n", pathname, object_type == OBJ_TREE ? "/" : "");
 	return 0;
 }
 
diff --git a/builtin/ls-files.c b/builtin/ls-files.c
index 13bcc2d8473..b954d08ae41 100644
--- a/builtin/ls-files.c
+++ b/builtin/ls-files.c
@@ -446,7 +446,8 @@ static int read_one_entry_opt(struct index_state *istate,
 }
 
 static int read_one_entry(const struct object_id *oid, struct strbuf *base,
-			  const char *pathname, unsigned mode,
+			  const char *pathname,
+			  enum object_type object_type, unsigned mode,
 			  void *context)
 {
 	struct index_state *istate = context;
@@ -460,7 +461,8 @@ static int read_one_entry(const struct object_id *oid, struct strbuf *base,
  * the stage that will conflict with the entry being added.
  */
 static int read_one_entry_quick(const struct object_id *oid, struct strbuf *base,
-				const char *pathname, unsigned mode,
+				const char *pathname,
+				enum object_type object_type, unsigned mode,
 				void *context)
 {
 	struct index_state *istate = context;
diff --git a/builtin/ls-tree.c b/builtin/ls-tree.c
index 8d5c3fd0582..7176d2ae065 100644
--- a/builtin/ls-tree.c
+++ b/builtin/ls-tree.c
@@ -63,14 +63,13 @@ static int show_recursive(const char *base, int baselen, const char *pathname)
 
 static int show_tree(const struct object_id *oid, struct strbuf *base,
 		     const char *pathname,
-		     unsigned mode,
+		     enum object_type object_type, unsigned mode,
 		     void *context)
 {
 	int retval = 0;
 	int baselen;
-	const char *type = blob_type;
 
-	if (S_ISGITLINK(mode)) {
+	if (object_type == OBJ_COMMIT) {
 		/*
 		 * Maybe we want to have some recursive version here?
 		 *
@@ -80,22 +79,21 @@ static int show_tree(const struct object_id *oid, struct strbuf *base,
 			retval = READ_TREE_RECURSIVE;
 		 *
 		 */
-		type = commit_type;
-	} else if (S_ISDIR(mode)) {
+	} else if (object_type == OBJ_TREE) {
 		if (show_recursive(base->buf, base->len, pathname)) {
 			retval = READ_TREE_RECURSIVE;
 			if (!(ls_options & LS_SHOW_TREES))
 				return retval;
 		}
-		type = tree_type;
 	}
 	else if (ls_options & LS_TREE_ONLY)
 		return 0;
 
 	if (!(ls_options & LS_NAME_ONLY)) {
+		const char *type = type_name(object_type);
 		if (ls_options & LS_SHOW_SIZE) {
 			char size_text[24];
-			if (!strcmp(type, blob_type)) {
+			if (object_type == OBJ_BLOB) {
 				unsigned long size;
 				if (oid_object_info(the_repository, oid, &size) == OBJ_BAD)
 					xsnprintf(size_text, sizeof(size_text),
diff --git a/merge-recursive.c b/merge-recursive.c
index 689a3e00070..df4b369902f 100644
--- a/merge-recursive.c
+++ b/merge-recursive.c
@@ -453,7 +453,7 @@ static void unpack_trees_finish(struct merge_options *opt)
 
 static int save_files_dirs(const struct object_id *oid,
 			   struct strbuf *base, const char *path,
-			   unsigned int mode,
+			   enum object_type object_type, unsigned int mode,
 			   void *context)
 {
 	struct path_hashmap_entry *entry;
@@ -467,7 +467,9 @@ static int save_files_dirs(const struct object_id *oid,
 	hashmap_add(&opt->priv->current_file_dir_set, &entry->e);
 
 	strbuf_setlen(base, baselen);
-	return (S_ISDIR(mode) ? READ_TREE_RECURSIVE : 0);
+	if (object_type != OBJ_TREE)
+		return 0;
+	return READ_TREE_RECURSIVE;
 }
 
 static void get_files_dirs(struct merge_options *opt, struct tree *tree)
diff --git a/tree.c b/tree.c
index 6a2a52967e4..c840bf2ea24 100644
--- a/tree.c
+++ b/tree.c
@@ -28,6 +28,8 @@ int read_tree_at(struct repository *r,
 	init_tree_desc(&desc, tree->buffer, tree->size);
 
 	while (tree_entry(&desc, &entry)) {
+		struct commit *commit;
+
 		if (retval != all_entries_interesting) {
 			retval = tree_entry_interesting(r->index, &entry,
 							base, 0, pathspec);
@@ -38,7 +40,7 @@ int read_tree_at(struct repository *r,
 		}
 
 		switch (fn(&entry.oid, base,
-			   entry.path, entry.mode, context)) {
+			   entry.path, entry.object_type, entry.mode, context)) {
 		case 0:
 			continue;
 		case READ_TREE_RECURSIVE:
@@ -47,11 +49,11 @@ int read_tree_at(struct repository *r,
 			return -1;
 		}
 
-		if (S_ISDIR(entry.mode))
+		switch (entry.object_type) {
+		case OBJ_TREE:
 			oidcpy(&oid, &entry.oid);
-		else if (S_ISGITLINK(entry.mode)) {
-			struct commit *commit;
-
+			break;
+		case OBJ_COMMIT:
 			commit = lookup_commit(r, &entry.oid);
 			if (!commit)
 				die("Commit %s in submodule path %s%s not found",
@@ -64,9 +66,12 @@ int read_tree_at(struct repository *r,
 				    base->buf, entry.path);
 
 			oidcpy(&oid, get_commit_tree_oid(commit));
-		}
-		else
+			break;
+		case OBJ_BLOB:
 			continue;
+		default:
+			BUG("unreachable");
+		}
 
 		len = tree_entry_len(&entry);
 		strbuf_add(base, entry.path, len);
diff --git a/tree.h b/tree.h
index c1a936fdc49..12edb316f0c 100644
--- a/tree.h
+++ b/tree.h
@@ -33,7 +33,7 @@ int cmp_cache_name_compare(const void *a_, const void *b_);
 #define READ_TREE_RECURSIVE 1
 typedef int (*read_tree_fn_t)(const struct object_id *, struct strbuf *,
 			      const char *,
-			      unsigned int,
+			      enum object_type, unsigned int,
 			      void *);
 
 int read_tree_at(struct repository *r,
-- 
2.31.0.rc2.211.g1d0b8788b3


^ permalink raw reply	[flat|nested] 262+ messages in thread

* [PATCH v2 12/29] tree-walk.h users: migrate "p->mode &&" pattern
  2021-03-08 15:06     ` [PATCH 00/30] tree-walk: mostly "mode" to "enum object_type" Ævar Arnfjörð Bjarmason
                         ` (13 preceding siblings ...)
  2021-03-16  2:12       ` [PATCH v2 11/29] tree.h API: make read_tree_fn_t take an "enum object_type" Ævar Arnfjörð Bjarmason
@ 2021-03-16  2:12       ` Ævar Arnfjörð Bjarmason
  2021-03-16  2:12       ` [PATCH v2 13/29] tree-walk.h users: refactor chained "mode" if/else into switch Ævar Arnfjörð Bjarmason
                         ` (16 subsequent siblings)
  31 siblings, 0 replies; 262+ messages in thread
From: Ævar Arnfjörð Bjarmason @ 2021-03-16  2:12 UTC (permalink / raw)
  To: git
  Cc: Junio C Hamano, Elijah Newren, Kirill Smelkov,
	Nguyễn Thái Ngọc Duy,
	Ævar Arnfjörð Bjarmason

Change code that depends on "p->mode" either being a valid mode or
zero to use a p->object_type comparison to "OBJ_NONE".

The object_type() function in cache.h will not return OBJ_NONE, but
these API users are implicitly relying on the memzero() that happens
in setup_traverse_info().

Since OBJ_NONE is "0" we can also rely on that being zero'd out here,
along with the rest of the structure. I think this is slightly less
clever than "mode not set", and helps to get rid of more uses of
"mode".

Signed-off-by: Ævar Arnfjörð Bjarmason <avarab@gmail.com>
---
 builtin/merge-tree.c | 9 +++++----
 merge-ort.c          | 2 +-
 unpack-trees.c       | 4 ++--
 3 files changed, 8 insertions(+), 7 deletions(-)

diff --git a/builtin/merge-tree.c b/builtin/merge-tree.c
index de8520778d2..2de34c2d485 100644
--- a/builtin/merge-tree.c
+++ b/builtin/merge-tree.c
@@ -214,7 +214,7 @@ static void unresolved_directory(const struct traverse_info *info,
 	void *buf0, *buf1, *buf2;
 
 	for (p = n; p < n + 3; p++) {
-		if (p->mode && S_ISDIR(p->mode))
+		if (p->object_type == OBJ_TREE)
 			break;
 	}
 	if (n + 3 <= p)
@@ -222,7 +222,7 @@ static void unresolved_directory(const struct traverse_info *info,
 
 	newbase = traverse_path(info, p);
 
-#define ENTRY_OID(e) (((e)->mode && S_ISDIR((e)->mode)) ? &(e)->oid : NULL)
+#define ENTRY_OID(e) (((e)->object_type == OBJ_TREE) ? &(e)->oid : NULL)
 	buf0 = fill_tree_descriptor(r, t + 0, ENTRY_OID(n + 0));
 	buf1 = fill_tree_descriptor(r, t + 1, ENTRY_OID(n + 1));
 	buf2 = fill_tree_descriptor(r, t + 2, ENTRY_OID(n + 2));
@@ -242,7 +242,7 @@ static struct merge_list *link_entry(unsigned stage, const struct traverse_info
 	const char *path;
 	struct merge_list *link;
 
-	if (!n->mode)
+	if (n->object_type == OBJ_NONE)
 		return entry;
 	if (entry)
 		path = entry->path;
@@ -265,7 +265,8 @@ static void unresolved(const struct traverse_info *info, struct name_entry n[3])
 		 * Treat missing entries as directories so that we return
 		 * after unresolved_directory has handled this.
 		 */
-		if (!n[i].mode || S_ISDIR(n[i].mode))
+		if (n[i].object_type == OBJ_NONE ||
+		    n[i].object_type == OBJ_TREE)
 			dirmask |= (1 << i);
 	}
 
diff --git a/merge-ort.c b/merge-ort.c
index 4075d13aaab..4375027914c 100644
--- a/merge-ort.c
+++ b/merge-ort.c
@@ -668,7 +668,7 @@ static int collect_merge_info_callback(int n,
 	 * setup_path_info() for tracking.
 	 */
 	p = names;
-	while (!p->mode)
+	while (p->object_type == OBJ_NONE)
 		p++;
 	len = traverse_path_len(info, p->pathlen);
 
diff --git a/unpack-trees.c b/unpack-trees.c
index d9d573df986..802de46228b 100644
--- a/unpack-trees.c
+++ b/unpack-trees.c
@@ -862,7 +862,7 @@ static int traverse_trees_recursive(int n, unsigned long dirmask,
 	}
 
 	p = names;
-	while (!p->mode)
+	while (p->object_type == OBJ_NONE)
 		p++;
 
 	newinfo = *info;
@@ -1242,7 +1242,7 @@ static int unpack_callback(int n, unsigned long mask, unsigned long dirmask, str
 	const struct name_entry *p = names;
 
 	/* Find first entry with a real name (we could use "mask" too) */
-	while (!p->mode)
+	while (p->object_type == OBJ_NONE)
 		p++;
 
 	if (o->debug_unpack)
-- 
2.31.0.rc2.211.g1d0b8788b3


^ permalink raw reply	[flat|nested] 262+ messages in thread

* [PATCH v2 13/29] tree-walk.h users: refactor chained "mode" if/else into switch
  2021-03-08 15:06     ` [PATCH 00/30] tree-walk: mostly "mode" to "enum object_type" Ævar Arnfjörð Bjarmason
                         ` (14 preceding siblings ...)
  2021-03-16  2:12       ` [PATCH v2 12/29] tree-walk.h users: migrate "p->mode &&" pattern Ævar Arnfjörð Bjarmason
@ 2021-03-16  2:12       ` Ævar Arnfjörð Bjarmason
  2021-03-16  2:12       ` [PATCH v2 14/29] tree-walk.h users: migrate miscellaneous "mode" to "object_type" Ævar Arnfjörð Bjarmason
                         ` (15 subsequent siblings)
  31 siblings, 0 replies; 262+ messages in thread
From: Ævar Arnfjörð Bjarmason @ 2021-03-16  2:12 UTC (permalink / raw)
  To: git
  Cc: Junio C Hamano, Elijah Newren, Kirill Smelkov,
	Nguyễn Thái Ngọc Duy,
	Ævar Arnfjörð Bjarmason

Refactor a couple of "switch" statements that previously relied on
"entry.mode" to switch on "entry.object_type" instead.

This is more obvious, and allows us to explicitly handle all the OBJ_*
cases, not just have a wildcard "else". That doesn't matter for the
behavior of this code, but for its readability and maintainability.

Signed-off-by: Ævar Arnfjörð Bjarmason <avarab@gmail.com>
---
 list-objects.c | 20 ++++++++++++++------
 walker.c       | 22 +++++++++++++---------
 2 files changed, 27 insertions(+), 15 deletions(-)

diff --git a/list-objects.c b/list-objects.c
index e19589baa04..37434ba89d3 100644
--- a/list-objects.c
+++ b/list-objects.c
@@ -111,6 +111,9 @@ static void process_tree_contents(struct traversal_context *ctx,
 	init_tree_desc(&desc, tree->buffer, tree->size);
 
 	while (tree_entry(&desc, &entry)) {
+		struct tree *t;
+		struct blob *b;
+
 		if (match != all_entries_interesting) {
 			match = tree_entry_interesting(ctx->revs->repo->index,
 						       &entry, base, 0,
@@ -121,8 +124,9 @@ static void process_tree_contents(struct traversal_context *ctx,
 				continue;
 		}
 
-		if (S_ISDIR(entry.mode)) {
-			struct tree *t = lookup_tree(ctx->revs->repo, &entry.oid);
+		switch (entry.object_type) {
+		case OBJ_TREE:
+			t = lookup_tree(ctx->revs->repo, &entry.oid);
 			if (!t) {
 				die(_("entry '%s' in tree %s has tree mode, "
 				      "but is not a tree"),
@@ -130,12 +134,13 @@ static void process_tree_contents(struct traversal_context *ctx,
 			}
 			t->object.flags |= NOT_USER_GIVEN;
 			process_tree(ctx, t, base, entry.path);
-		}
-		else if (S_ISGITLINK(entry.mode))
+			break;
+		case OBJ_COMMIT:
 			process_gitlink(ctx, entry.oid.hash,
 					base, entry.path);
-		else {
-			struct blob *b = lookup_blob(ctx->revs->repo, &entry.oid);
+			break;
+		case OBJ_BLOB:
+			b = lookup_blob(ctx->revs->repo, &entry.oid);
 			if (!b) {
 				die(_("entry '%s' in tree %s has blob mode, "
 				      "but is not a blob"),
@@ -143,6 +148,9 @@ static void process_tree_contents(struct traversal_context *ctx,
 			}
 			b->object.flags |= NOT_USER_GIVEN;
 			process_blob(ctx, b, base, entry.path);
+			break;
+		default:
+			BUG("unreachable");
 		}
 	}
 }
diff --git a/walker.c b/walker.c
index 4984bf8b3d6..7ba757244e6 100644
--- a/walker.c
+++ b/walker.c
@@ -45,21 +45,25 @@ static int process_tree(struct walker *walker, struct tree *tree)
 	init_tree_desc(&desc, tree->buffer, tree->size);
 	while (tree_entry(&desc, &entry)) {
 		struct object *obj = NULL;
+		struct tree *tree;
+		struct blob *blob;
 
-		/* submodule commits are not stored in the superproject */
-		if (S_ISGITLINK(entry.mode))
+		switch (entry.object_type) {
+		case OBJ_COMMIT:
+			/* submodule commits are not stored in the superproject */
 			continue;
-		if (S_ISDIR(entry.mode)) {
-			struct tree *tree = lookup_tree(the_repository,
-							&entry.oid);
+		case OBJ_TREE:
+			tree = lookup_tree(the_repository, &entry.oid);
 			if (tree)
 				obj = &tree->object;
-		}
-		else {
-			struct blob *blob = lookup_blob(the_repository,
-							&entry.oid);
+			break;
+		case OBJ_BLOB:
+			blob = lookup_blob(the_repository, &entry.oid);
 			if (blob)
 				obj = &blob->object;
+			break;
+		default:
+			BUG("unreachable");
 		}
 		if (!obj || process(walker, obj))
 			return -1;
-- 
2.31.0.rc2.211.g1d0b8788b3


^ permalink raw reply	[flat|nested] 262+ messages in thread

* [PATCH v2 14/29] tree-walk.h users: migrate miscellaneous "mode" to "object_type"
  2021-03-08 15:06     ` [PATCH 00/30] tree-walk: mostly "mode" to "enum object_type" Ævar Arnfjörð Bjarmason
                         ` (15 preceding siblings ...)
  2021-03-16  2:12       ` [PATCH v2 13/29] tree-walk.h users: refactor chained "mode" if/else into switch Ævar Arnfjörð Bjarmason
@ 2021-03-16  2:12       ` Ævar Arnfjörð Bjarmason
  2021-03-16  2:12       ` [PATCH v2 15/29] merge-tree tests: test for the mode comparison in same_entry() Ævar Arnfjörð Bjarmason
                         ` (14 subsequent siblings)
  31 siblings, 0 replies; 262+ messages in thread
From: Ævar Arnfjörð Bjarmason @ 2021-03-16  2:12 UTC (permalink / raw)
  To: git
  Cc: Junio C Hamano, Elijah Newren, Kirill Smelkov,
	Nguyễn Thái Ngọc Duy,
	Ævar Arnfjörð Bjarmason

Refactor more users of the "entry.mode" field to use the new
"entry.object_type" field.

Signed-off-by: Ævar Arnfjörð Bjarmason <avarab@gmail.com>
---
 builtin/grep.c         | 6 +++---
 builtin/merge-tree.c   | 9 +++++----
 builtin/pack-objects.c | 4 ++--
 builtin/reflog.c       | 3 ++-
 cache-tree.c           | 2 +-
 delta-islands.c        | 2 +-
 notes.c                | 4 ++--
 unpack-trees.c         | 2 +-
 8 files changed, 17 insertions(+), 15 deletions(-)

diff --git a/builtin/grep.c b/builtin/grep.c
index 4e91a253ac3..5a317cdd2f4 100644
--- a/builtin/grep.c
+++ b/builtin/grep.c
@@ -587,10 +587,10 @@ static int grep_tree(struct grep_opt *opt, const struct pathspec *pathspec,
 
 		strbuf_add(base, entry.path, te_len);
 
-		if (S_ISREG(entry.mode)) {
+		if (entry.object_type == OBJ_BLOB) {
 			hit |= grep_oid(opt, &entry.oid, base->buf, tn_len,
 					 check_attr ? base->buf + tn_len : NULL);
-		} else if (S_ISDIR(entry.mode)) {
+		} else if (entry.object_type == OBJ_TREE) {
 			enum object_type type;
 			struct tree_desc sub;
 			void *data;
@@ -606,7 +606,7 @@ static int grep_tree(struct grep_opt *opt, const struct pathspec *pathspec,
 			hit |= grep_tree(opt, pathspec, &sub, base, tn_len,
 					 check_attr);
 			free(data);
-		} else if (recurse_submodules && S_ISGITLINK(entry.mode)) {
+		} else if (recurse_submodules && entry.object_type == OBJ_COMMIT) {
 			hit |= grep_submodule(opt, pathspec, &entry.oid,
 					      base->buf, base->buf + tn_len,
 					      1); /* ignored */
diff --git a/builtin/merge-tree.c b/builtin/merge-tree.c
index 2de34c2d485..12cb317c1ba 100644
--- a/builtin/merge-tree.c
+++ b/builtin/merge-tree.c
@@ -275,11 +275,11 @@ static void unresolved(const struct traverse_info *info, struct name_entry n[3])
 	if (dirmask == mask)
 		return;
 
-	if (n[2].mode && !S_ISDIR(n[2].mode))
+	if (n[2].object_type != OBJ_TREE)
 		entry = link_entry(3, info, n + 2, entry);
-	if (n[1].mode && !S_ISDIR(n[1].mode))
+	if (n[1].object_type != OBJ_TREE)
 		entry = link_entry(2, info, n + 1, entry);
-	if (n[0].mode && !S_ISDIR(n[0].mode))
+	if (n[0].object_type != OBJ_TREE)
 		entry = link_entry(1, info, n + 0, entry);
 
 	add_merge_entry(entry);
@@ -324,7 +324,8 @@ static int threeway_callback(int n, unsigned long mask, unsigned long dirmask, s
 	}
 
 	if (same_entry(entry+0, entry+1)) {
-		if (!is_null_oid(&entry[2].oid) && !S_ISDIR(entry[2].mode)) {
+		if (!is_null_oid(&entry[2].oid) &&
+		    entry[2].object_type != OBJ_TREE) {
 			/* We did not touch, they modified -- take theirs */
 			resolve(info, entry+1, entry+2);
 			return mask;
diff --git a/builtin/pack-objects.c b/builtin/pack-objects.c
index d3ba1d4a4a6..f92722c12d4 100644
--- a/builtin/pack-objects.c
+++ b/builtin/pack-objects.c
@@ -1524,7 +1524,7 @@ static void add_pbase_object(struct tree_desc *tree,
 	int cmp;
 
 	while (tree_entry(tree,&entry)) {
-		if (S_ISGITLINK(entry.mode))
+		if (entry.object_type == OBJ_COMMIT)
 			continue;
 		cmp = tree_entry_len(&entry) != cmplen ? 1 :
 		      memcmp(name, entry.path, cmplen);
@@ -1538,7 +1538,7 @@ static void add_pbase_object(struct tree_desc *tree,
 					 fullname, 1);
 			return;
 		}
-		if (S_ISDIR(entry.mode)) {
+		if (entry.object_type == OBJ_TREE) {
 			struct tree_desc sub;
 			struct pbase_tree_cache *tree;
 			const char *down = name+cmplen+1;
diff --git a/builtin/reflog.c b/builtin/reflog.c
index 09541d1c804..bcbca82aa90 100644
--- a/builtin/reflog.c
+++ b/builtin/reflog.c
@@ -95,7 +95,8 @@ static int tree_is_complete(const struct object_id *oid)
 	complete = 1;
 	while (tree_entry(&desc, &entry)) {
 		if (!has_object_file(&entry.oid) ||
-		    (S_ISDIR(entry.mode) && !tree_is_complete(&entry.oid))) {
+		    (entry.object_type == OBJ_TREE &&
+		     !tree_is_complete(&entry.oid))) {
 			tree->object.flags |= INCOMPLETE;
 			complete = 0;
 		}
diff --git a/cache-tree.c b/cache-tree.c
index 2fb483d3c08..fbe93dd2a5f 100644
--- a/cache-tree.c
+++ b/cache-tree.c
@@ -726,7 +726,7 @@ static void prime_cache_tree_rec(struct repository *r,
 	init_tree_desc(&desc, tree->buffer, tree->size);
 	cnt = 0;
 	while (tree_entry(&desc, &entry)) {
-		if (!S_ISDIR(entry.mode))
+		if (entry.object_type != OBJ_TREE)
 			cnt++;
 		else {
 			struct cache_tree_sub *sub;
diff --git a/delta-islands.c b/delta-islands.c
index aa98b2e5414..e7cf93acbe3 100644
--- a/delta-islands.c
+++ b/delta-islands.c
@@ -293,7 +293,7 @@ void resolve_tree_islands(struct repository *r,
 		while (tree_entry(&desc, &entry)) {
 			struct object *obj;
 
-			if (S_ISGITLINK(entry.mode))
+			if (entry.object_type == OBJ_COMMIT)
 				continue;
 
 			obj = lookup_object(r, &entry.oid);
diff --git a/notes.c b/notes.c
index 0a5b4fa1dbb..d631dc5623e 100644
--- a/notes.c
+++ b/notes.c
@@ -418,7 +418,7 @@ static void load_subtree(struct notes_tree *t, struct leaf_node *subtree,
 		if (path_len == 2 * (hashsz - prefix_len)) {
 			/* This is potentially the remainder of the SHA-1 */
 
-			if (!S_ISREG(entry.mode))
+			if (entry.object_type != OBJ_BLOB)
 				/* notes must be blobs */
 				goto handle_non_note;
 
@@ -431,7 +431,7 @@ static void load_subtree(struct notes_tree *t, struct leaf_node *subtree,
 			/* This is potentially an internal node */
 			size_t len = prefix_len;
 
-			if (!S_ISDIR(entry.mode))
+			if (entry.object_type != OBJ_TREE)
 				/* internal nodes must be trees */
 				goto handle_non_note;
 
diff --git a/unpack-trees.c b/unpack-trees.c
index 802de46228b..33de78e32c8 100644
--- a/unpack-trees.c
+++ b/unpack-trees.c
@@ -1300,7 +1300,7 @@ static int unpack_callback(int n, unsigned long mask, unsigned long dirmask, str
 	if (dirmask) {
 		/* special case: "diff-index --cached" looking at a tree */
 		if (o->diff_index_cached &&
-		    n == 1 && dirmask == 1 && S_ISDIR(names->mode)) {
+		    n == 1 && dirmask == 1 && names->object_type == OBJ_TREE) {
 			int matches;
 			matches = cache_tree_matches_traversal(o->src_index->cache_tree,
 							       names, info);
-- 
2.31.0.rc2.211.g1d0b8788b3


^ permalink raw reply	[flat|nested] 262+ messages in thread

* [PATCH v2 15/29] merge-tree tests: test for the mode comparison in same_entry()
  2021-03-08 15:06     ` [PATCH 00/30] tree-walk: mostly "mode" to "enum object_type" Ævar Arnfjörð Bjarmason
                         ` (16 preceding siblings ...)
  2021-03-16  2:12       ` [PATCH v2 14/29] tree-walk.h users: migrate miscellaneous "mode" to "object_type" Ævar Arnfjörð Bjarmason
@ 2021-03-16  2:12       ` Ævar Arnfjörð Bjarmason
  2021-03-16  2:12       ` [PATCH v2 16/29] merge-ort: correct reference to test in 62fdec17a11 Ævar Arnfjörð Bjarmason
                         ` (13 subsequent siblings)
  31 siblings, 0 replies; 262+ messages in thread
From: Ævar Arnfjörð Bjarmason @ 2021-03-16  2:12 UTC (permalink / raw)
  To: git
  Cc: Junio C Hamano, Elijah Newren, Kirill Smelkov,
	Nguyễn Thái Ngọc Duy,
	Ævar Arnfjörð Bjarmason

Add a test to stress the "a->mode == b->mode" comparison in
merge-tree.c's same_entry().

That code was initially added by Linus in 33deb63a36f (Add
"merge-tree" helper program. Maybe it's retarded, maybe it's helpful.,
2005-04-14), and then again in its current form in
492e0759bfe (Handling large files with GIT, 2006-02-14).

However, nothing was testing that we handled this case
correctly. Simply removing the mode comparison left all tests passing,
but as seen here it's important that we don't think a path with the
same content but different modes is the same_entry().

The rest of this series will touch code that's relevant to this, but
won't change its behavior. This test is just something I came up with
in testing whether the mode test in same_entry() was needed at all.

Signed-off-by: Ævar Arnfjörð Bjarmason <avarab@gmail.com>
---
 t/t4300-merge-tree.sh | 44 +++++++++++++++++++++++++++++++++++++++++++
 1 file changed, 44 insertions(+)

diff --git a/t/t4300-merge-tree.sh b/t/t4300-merge-tree.sh
index e59601e5fe9..f783d784d02 100755
--- a/t/t4300-merge-tree.sh
+++ b/t/t4300-merge-tree.sh
@@ -40,6 +40,25 @@ test_expect_success 'file add A, B (same)' '
 	test_must_be_empty actual
 '
 
+test_expect_success 'file add A, B (different mode)' '
+	git reset --hard initial &&
+	test_commit "add-a-b-same-diff-mode-A" "ONE" "AAA" &&
+	git reset --hard initial &&
+	echo AAA >ONE &&
+	test_chmod +x ONE &&
+	test_tick &&
+	git commit -m"add-a-b-same-diff-mode-B" &&
+	git tag "add-a-b-same-diff-mode-B" HEAD &&
+	git merge-tree initial add-a-b-same-diff-mode-A add-a-b-same-diff-mode-B >actual &&
+	cat >expected <<EXPECTED &&
+added in both
+  our    100644 $(git rev-parse add-a-b-same-diff-mode-A:ONE) ONE
+  their  100755 $(git rev-parse add-a-b-same-diff-mode-B:ONE) ONE
+EXPECTED
+
+	test_cmp expected actual
+'
+
 test_expect_success 'file add A, B (different)' '
 	git reset --hard initial &&
 	test_commit "add-a-b-diff-A" "ONE" "AAA" &&
@@ -61,6 +80,31 @@ EXPECTED
 	test_cmp expected actual
 '
 
+test_expect_success 'file add A, B (different and different mode)' '
+	git reset --hard initial &&
+	test_commit "add-a-b-diff-diff-mode-A" "ONE" "AAA" &&
+	git reset --hard initial &&
+	echo BBB >ONE &&
+	test_chmod +x ONE &&
+	test_tick &&
+	git commit -m"add-a-b-diff-diff-mode-B" &&
+	git tag "add-a-b-diff-diff-mode-B" &&
+	git merge-tree initial add-a-b-diff-diff-mode-A add-a-b-diff-diff-mode-B >actual &&
+	cat >expected <<EXPECTED &&
+added in both
+  our    100644 $(git rev-parse add-a-b-diff-diff-mode-A:ONE) ONE
+  their  100755 $(git rev-parse add-a-b-diff-diff-mode-B:ONE) ONE
+@@ -1 +1,5 @@
++<<<<<<< .our
+ AAA
++=======
++BBB
++>>>>>>> .their
+EXPECTED
+
+	test_cmp expected actual
+'
+
 test_expect_success 'file change A, !B' '
 	git reset --hard initial &&
 	test_commit "change-a-not-b" "initial-file" "BBB" &&
-- 
2.31.0.rc2.211.g1d0b8788b3


^ permalink raw reply	[flat|nested] 262+ messages in thread

* [PATCH v2 16/29] merge-ort: correct reference to test in 62fdec17a11
  2021-03-08 15:06     ` [PATCH 00/30] tree-walk: mostly "mode" to "enum object_type" Ævar Arnfjörð Bjarmason
                         ` (17 preceding siblings ...)
  2021-03-16  2:12       ` [PATCH v2 15/29] merge-tree tests: test for the mode comparison in same_entry() Ævar Arnfjörð Bjarmason
@ 2021-03-16  2:12       ` Ævar Arnfjörð Bjarmason
  2021-03-16  2:13       ` [PATCH v2 17/29] fsck.c: switch on "object_type" in fsck_walk_tree() Ævar Arnfjörð Bjarmason
                         ` (12 subsequent siblings)
  31 siblings, 0 replies; 262+ messages in thread
From: Ævar Arnfjörð Bjarmason @ 2021-03-16  2:12 UTC (permalink / raw)
  To: git
  Cc: Junio C Hamano, Elijah Newren, Kirill Smelkov,
	Nguyễn Thái Ngọc Duy,
	Ævar Arnfjörð Bjarmason

Fix a comment added in 62fdec17a11 (merge-ort: flesh out
implementation of handle_content_merge(), 2021-01-01).

The test being referred to here was moved from t6036 in
919df319555 (Collect merge-related tests to t64xx, 2020-08-10).

It has also had the plural of "mode" in the name ever since being
introduced in 5d1daf30cce (t6036: add a failed conflict detection
case: regular files, different modes, 2018-06-30).

Signed-off-by: Ævar Arnfjörð Bjarmason <avarab@gmail.com>
---
 merge-ort.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/merge-ort.c b/merge-ort.c
index 4375027914c..e54be179bd5 100644
--- a/merge-ort.c
+++ b/merge-ort.c
@@ -1079,7 +1079,7 @@ static int handle_content_merge(struct merge_options *opt,
 		/*
 		 * FIXME: If opt->priv->call_depth && !clean, then we really
 		 * should not make result->mode match either a->mode or
-		 * b->mode; that causes t6036 "check conflicting mode for
+		 * b->mode; that causes t6416 "check conflicting modes for
 		 * regular file" to fail.  It would be best to use some other
 		 * mode, but we'll confuse all kinds of stuff if we use one
 		 * where S_ISREG(result->mode) isn't true, and if we use
-- 
2.31.0.rc2.211.g1d0b8788b3


^ permalink raw reply	[flat|nested] 262+ messages in thread

* [PATCH v2 17/29] fsck.c: switch on "object_type" in fsck_walk_tree()
  2021-03-08 15:06     ` [PATCH 00/30] tree-walk: mostly "mode" to "enum object_type" Ævar Arnfjörð Bjarmason
                         ` (18 preceding siblings ...)
  2021-03-16  2:12       ` [PATCH v2 16/29] merge-ort: correct reference to test in 62fdec17a11 Ævar Arnfjörð Bjarmason
@ 2021-03-16  2:13       ` Ævar Arnfjörð Bjarmason
  2021-03-16  2:13       ` [PATCH v2 18/29] tree-walk.h users: use temporary variable(s) for "mode" Ævar Arnfjörð Bjarmason
                         ` (11 subsequent siblings)
  31 siblings, 0 replies; 262+ messages in thread
From: Ævar Arnfjörð Bjarmason @ 2021-03-16  2:13 UTC (permalink / raw)
  To: git
  Cc: Junio C Hamano, Elijah Newren, Kirill Smelkov,
	Nguyễn Thái Ngọc Duy,
	Ævar Arnfjörð Bjarmason

Since 7146e66f086 (tree-walk: finally switch over tree descriptors to
contain a pre-parsed entry, 2014-02-06) the "mode" is validated such
that we'll never reach the "else" clause here.

Good for us that fsck_tree() has its own FSCK_MSG_BAD_FILEMODE check
which we can use, added way back in 64071805eda (git-fsck-cache: be
stricter about "tree" objects, 2005-07-27).

Except it really doesn't due to a regression in 7146e66f086. A
follow-up commit will address that, but for now we can simply rewrite
this code like the rest of the s/entry.mode/entry.object_type/g
changes I'm making.

Signed-off-by: Ævar Arnfjörð Bjarmason <avarab@gmail.com>
---
 fsck.c | 21 +++++++++------------
 1 file changed, 9 insertions(+), 12 deletions(-)

diff --git a/fsck.c b/fsck.c
index e3030f3b358..7c74c49d329 100644
--- a/fsck.c
+++ b/fsck.c
@@ -396,28 +396,25 @@ static int fsck_walk_tree(struct tree *tree, void *data, struct fsck_options *op
 		struct object *obj;
 		int result;
 
-		if (S_ISGITLINK(entry.mode))
+		switch (entry.object_type) {
+		case OBJ_COMMIT:
 			continue;
-
-		if (S_ISDIR(entry.mode)) {
+		case OBJ_TREE:
 			obj = (struct object *)lookup_tree(the_repository, &entry.oid);
 			if (name && obj)
 				fsck_put_object_name(options, &entry.oid, "%s%s/",
 						     name, entry.path);
-			result = options->walk(obj, OBJ_TREE, data, options);
-		}
-		else if (S_ISREG(entry.mode) || S_ISLNK(entry.mode)) {
+			break;
+		case OBJ_BLOB:
 			obj = (struct object *)lookup_blob(the_repository, &entry.oid);
 			if (name && obj)
 				fsck_put_object_name(options, &entry.oid, "%s%s",
 						     name, entry.path);
-			result = options->walk(obj, OBJ_BLOB, data, options);
-		}
-		else {
-			result = error("in tree %s: entry %s has bad mode %.6o",
-				       fsck_describe_object(options, &tree->object.oid),
-				       entry.path, entry.mode);
+			break;
+		default:
+			BUG("unreachable");
 		}
+		result = options->walk(obj, entry.object_type, data, options);
 		if (result < 0)
 			return result;
 		if (!res)
-- 
2.31.0.rc2.211.g1d0b8788b3


^ permalink raw reply	[flat|nested] 262+ messages in thread

* [PATCH v2 18/29] tree-walk.h users: use temporary variable(s) for "mode"
  2021-03-08 15:06     ` [PATCH 00/30] tree-walk: mostly "mode" to "enum object_type" Ævar Arnfjörð Bjarmason
                         ` (19 preceding siblings ...)
  2021-03-16  2:13       ` [PATCH v2 17/29] fsck.c: switch on "object_type" in fsck_walk_tree() Ævar Arnfjörð Bjarmason
@ 2021-03-16  2:13       ` Ævar Arnfjörð Bjarmason
  2021-03-16  2:13       ` [PATCH v2 19/29] tree-walk.h API: formatting changes for subsequent commit Ævar Arnfjörð Bjarmason
                         ` (10 subsequent siblings)
  31 siblings, 0 replies; 262+ messages in thread
From: Ævar Arnfjörð Bjarmason @ 2021-03-16  2:13 UTC (permalink / raw)
  To: git
  Cc: Junio C Hamano, Elijah Newren, Kirill Smelkov,
	Nguyễn Thái Ngọc Duy,
	Ævar Arnfjörð Bjarmason

In preparation for an eventual rename of the "mode" field, add
temporary variable(s) in those places where it's used more than once.

This will make a subsequent commits easier to read., since we're only
going to need to modify the line on which the assignment happens.

Signed-off-by: Ævar Arnfjörð Bjarmason <avarab@gmail.com>
---
 builtin/merge-tree.c | 12 +++++++++---
 match-trees.c        | 13 +++++++------
 merge-ort.c          |  5 +++--
 notes.c              |  3 ++-
 tree-diff.c          | 13 ++++++++-----
 unpack-trees.c       |  3 ++-
 6 files changed, 31 insertions(+), 18 deletions(-)

diff --git a/builtin/merge-tree.c b/builtin/merge-tree.c
index 12cb317c1ba..eec5b906561 100644
--- a/builtin/merge-tree.c
+++ b/builtin/merge-tree.c
@@ -190,14 +190,17 @@ static void resolve(const struct traverse_info *info, struct name_entry *ours, s
 {
 	struct merge_list *orig, *final;
 	const char *path;
+	unsigned int orig_mode, final_mode;
 
 	/* If it's already ours, don't bother showing it */
 	if (!ours)
 		return;
 
 	path = traverse_path(info, result);
-	orig = create_entry(2, ours->mode, &ours->oid, path);
-	final = create_entry(0, result->mode, &result->oid, path);
+	orig_mode = ours->mode;
+	orig = create_entry(2, orig_mode, &ours->oid, path);
+	final_mode = result->mode;
+	final = create_entry(0, final_mode, &result->oid, path);
 
 	final->link = orig;
 
@@ -241,6 +244,7 @@ static struct merge_list *link_entry(unsigned stage, const struct traverse_info
 {
 	const char *path;
 	struct merge_list *link;
+	unsigned int link_mode;
 
 	if (n->object_type == OBJ_NONE)
 		return entry;
@@ -248,7 +252,9 @@ static struct merge_list *link_entry(unsigned stage, const struct traverse_info
 		path = entry->path;
 	else
 		path = traverse_path(info, n);
-	link = create_entry(stage, n->mode, &n->oid, path);
+	link_mode = n->mode;
+	link = create_entry(stage, link_mode, &n->oid, path);
+
 	link->link = entry;
 	return link;
 }
diff --git a/match-trees.c b/match-trees.c
index a28c19a62a5..f3e192ca74d 100644
--- a/match-trees.c
+++ b/match-trees.c
@@ -86,6 +86,8 @@ static int score_trees(const struct object_id *hash1, const struct object_id *ha
 
 	for (;;) {
 		int cmp;
+		unsigned int one_mode = one.entry.mode;
+		unsigned int two_mode = two.entry.mode;
 
 		if (one.size && two.size)
 			cmp = base_name_entries_compare(&one.entry, &two.entry);
@@ -100,22 +102,21 @@ static int score_trees(const struct object_id *hash1, const struct object_id *ha
 
 		if (cmp < 0) {
 			/* path1 does not appear in two */
-			score += score_missing(one.entry.mode);
+			score += score_missing(one_mode);
 			update_tree_entry(&one);
 		} else if (cmp > 0) {
 			/* path2 does not appear in one */
-			score += score_missing(two.entry.mode);
+			score += score_missing(two_mode);
 			update_tree_entry(&two);
 		} else {
+
 			/* path appears in both */
 			if (!oideq(&one.entry.oid, &two.entry.oid)) {
 				/* they are different */
-				score += score_differs(one.entry.mode,
-						       two.entry.mode);
+				score += score_differs(one_mode, two_mode);
 			} else {
 				/* same subtree or blob */
-				score += score_matches(one.entry.mode,
-						       two.entry.mode);
+				score += score_matches(one_mode, two_mode);
 			}
 			update_tree_entry(&one);
 			update_tree_entry(&two);
diff --git a/merge-ort.c b/merge-ort.c
index e54be179bd5..cad10436504 100644
--- a/merge-ort.c
+++ b/merge-ort.c
@@ -544,11 +544,12 @@ static void add_pair(struct merge_options *opt,
 	struct diff_filespec *one, *two;
 	struct rename_info *renames = &opt->priv->renames;
 	int names_idx = is_add ? side : 0;
+	const struct object_id *oid = &names[names_idx].oid;
+	unsigned int mode = names[names_idx].mode;
 
 	one = alloc_filespec(pathname);
 	two = alloc_filespec(pathname);
-	fill_filespec(is_add ? two : one,
-		      &names[names_idx].oid, 1, names[names_idx].mode);
+	fill_filespec(is_add ? two : one, oid, 1, mode);
 	diff_queue(&renames->pairs[side], one, two);
 }
 
diff --git a/notes.c b/notes.c
index d631dc5623e..688d03ee9cd 100644
--- a/notes.c
+++ b/notes.c
@@ -478,6 +478,7 @@ static void load_subtree(struct notes_tree *t, struct leaf_node *subtree,
 			struct strbuf non_note_path = STRBUF_INIT;
 			const char *q = oid_to_hex(&subtree->key_oid);
 			size_t i;
+			unsigned int mode = entry.mode;
 			for (i = 0; i < prefix_len; i++) {
 				strbuf_addch(&non_note_path, *q++);
 				strbuf_addch(&non_note_path, *q++);
@@ -485,7 +486,7 @@ static void load_subtree(struct notes_tree *t, struct leaf_node *subtree,
 			}
 			strbuf_add(&non_note_path, entry.path, path_len);
 			add_non_note(t, strbuf_detach(&non_note_path, NULL),
-				     entry.mode, entry.oid.hash);
+				     mode, entry.oid.hash);
 		}
 	}
 	free(buf);
diff --git a/tree-diff.c b/tree-diff.c
index 6ec180331fb..088ed52d6a3 100644
--- a/tree-diff.c
+++ b/tree-diff.c
@@ -466,17 +466,19 @@ static struct combine_diff_path *ll_diff_tree_paths(
 		tp[0].entry.mode &= ~S_IFXMIN_NEQ;
 
 		for (i = 1; i < nparent; ++i) {
+			unsigned int mode = tp[i].entry.mode;
 			cmp = tree_entry_pathcmp(&tp[i], &tp[imin]);
 			if (cmp < 0) {
 				imin = i;
-				tp[i].entry.mode &= ~S_IFXMIN_NEQ;
+				mode &= ~S_IFXMIN_NEQ;
 			}
 			else if (cmp == 0) {
-				tp[i].entry.mode &= ~S_IFXMIN_NEQ;
+				mode &= ~S_IFXMIN_NEQ;
 			}
 			else {
-				tp[i].entry.mode |= S_IFXMIN_NEQ;
+				mode |= S_IFXMIN_NEQ;
 			}
+			tp[i].entry.mode = mode;
 		}
 
 		/* fixup markings for entries before imin */
@@ -493,13 +495,14 @@ static struct combine_diff_path *ll_diff_tree_paths(
 			/* are either pi > p[imin] or diff(t,pi) != ø ? */
 			if (!opt->flags.find_copies_harder) {
 				for (i = 0; i < nparent; ++i) {
+					unsigned int mode = tp[i].entry.mode;
 					/* p[i] > p[imin] */
-					if (tp[i].entry.mode & S_IFXMIN_NEQ)
+					if (mode & S_IFXMIN_NEQ)
 						continue;
 
 					/* diff(t,pi) != ø */
 					if (!oideq(&t.entry.oid, &tp[i].entry.oid) ||
-					    (t.entry.mode != tp[i].entry.mode))
+					    (t.entry.mode != mode))
 						continue;
 
 					goto skip_emit_t_tp;
diff --git a/unpack-trees.c b/unpack-trees.c
index 33de78e32c8..2319b114ba0 100644
--- a/unpack-trees.c
+++ b/unpack-trees.c
@@ -1023,8 +1023,9 @@ static struct cache_entry *create_ce_entry(const struct traverse_info *info,
 		is_transient ?
 		make_empty_transient_cache_entry(len) :
 		make_empty_cache_entry(istate, len);
+	unsigned int mode = n->mode;
 
-	ce->ce_mode = create_ce_mode(n->mode);
+	ce->ce_mode = create_ce_mode(mode);
 	ce->ce_flags = create_ce_flags(stage);
 	ce->ce_namelen = len;
 	oidcpy(&ce->oid, &n->oid);
-- 
2.31.0.rc2.211.g1d0b8788b3


^ permalink raw reply	[flat|nested] 262+ messages in thread

* [PATCH v2 19/29] tree-walk.h API: formatting changes for subsequent commit
  2021-03-08 15:06     ` [PATCH 00/30] tree-walk: mostly "mode" to "enum object_type" Ævar Arnfjörð Bjarmason
                         ` (20 preceding siblings ...)
  2021-03-16  2:13       ` [PATCH v2 18/29] tree-walk.h users: use temporary variable(s) for "mode" Ævar Arnfjörð Bjarmason
@ 2021-03-16  2:13       ` Ævar Arnfjörð Bjarmason
  2021-03-16  2:13       ` [PATCH v2 20/29] tree-walk.h API: rename get_tree_entry() to get_tree_entry_mode() Ævar Arnfjörð Bjarmason
                         ` (9 subsequent siblings)
  31 siblings, 0 replies; 262+ messages in thread
From: Ævar Arnfjörð Bjarmason @ 2021-03-16  2:13 UTC (permalink / raw)
  To: git
  Cc: Junio C Hamano, Elijah Newren, Kirill Smelkov,
	Nguyễn Thái Ngọc Duy,
	Ævar Arnfjörð Bjarmason

Do formatting (mainly whitespace) changes of code around the
get_tree_entry() function to make a subsequent change where we'll add
a sister function easier to read.

Signed-off-by: Ævar Arnfjörð Bjarmason <avarab@gmail.com>
---
 blame.c     |  5 +++--
 tree-walk.c |  9 ++++++---
 tree-walk.h | 12 ++++++++----
 3 files changed, 17 insertions(+), 9 deletions(-)

diff --git a/blame.c b/blame.c
index a5044fcfaa6..83babc41d08 100644
--- a/blame.c
+++ b/blame.c
@@ -102,9 +102,10 @@ static void verify_working_tree_path(struct repository *r,
 		const struct object_id *commit_oid = &parents->item->object.oid;
 		struct object_id blob_oid;
 		unsigned short mode;
+		int ret = get_tree_entry(r, commit_oid, path, &blob_oid,
+					 &mode);
 
-		if (!get_tree_entry(r, commit_oid, path, &blob_oid, &mode) &&
-		    oid_object_info(r, &blob_oid, NULL) == OBJ_BLOB)
+		if (!ret && oid_object_info(r, &blob_oid, NULL) == OBJ_BLOB)
 			return;
 	}
 
diff --git a/tree-walk.c b/tree-walk.c
index 6e9161901d8..e88187e3714 100644
--- a/tree-walk.c
+++ b/tree-walk.c
@@ -591,7 +591,8 @@ static int find_tree_entry(struct repository *r, struct tree_desc *t,
 			oidcpy(result, &oid);
 			return 0;
 		}
-		return get_tree_entry(r, &oid, name + entrylen, result, mode);
+		return get_tree_entry(r, &oid, name + entrylen, result,
+				      mode);
 	}
 	return -1;
 }
@@ -622,7 +623,8 @@ int get_tree_entry(struct repository *r,
 	} else {
 		struct tree_desc t;
 		init_tree_desc(&t, tree, size);
-		retval = find_tree_entry(r, &t, name, oid, mode);
+		retval = find_tree_entry(r, &t, name, oid,
+					 mode);
 	}
 	free(tree);
 	return retval;
@@ -748,7 +750,8 @@ enum get_oid_result get_tree_entry_follow_symlinks(struct repository *r,
 
 		/* Look up the first (or only) path component in the tree. */
 		find_result = find_tree_entry(r, &t, namebuf.buf,
-					      &current_tree_oid, mode);
+					      &current_tree_oid,
+					      mode);
 		if (find_result) {
 			goto done;
 		}
diff --git a/tree-walk.h b/tree-walk.h
index 9f3825d2773..478a659ee2b 100644
--- a/tree-walk.h
+++ b/tree-walk.h
@@ -169,10 +169,14 @@ struct traverse_info {
 
 /**
  * Find an entry in a tree given a pathname and the sha1 of a tree to
- * search. Returns 0 if the entry is found and -1 otherwise. The third
- * and fourth parameters are set to the entry's sha1 and mode respectively.
- */
-int get_tree_entry(struct repository *, const struct object_id *, const char *, struct object_id *, unsigned short *);
+ * search. Returns 0 if the entry is found and -1 otherwise.
+ *
+ * The third and fourth parameters are set to the entry's sha1 and
+ * mode respectively.
+ */
+int get_tree_entry(struct repository *, const struct object_id *, const char *,
+		   struct object_id *,
+		   unsigned short *);
 
 /**
  * Generate the full pathname of a tree entry based from the root of the
-- 
2.31.0.rc2.211.g1d0b8788b3


^ permalink raw reply	[flat|nested] 262+ messages in thread

* [PATCH v2 20/29] tree-walk.h API: rename get_tree_entry() to get_tree_entry_mode()
  2021-03-08 15:06     ` [PATCH 00/30] tree-walk: mostly "mode" to "enum object_type" Ævar Arnfjörð Bjarmason
                         ` (21 preceding siblings ...)
  2021-03-16  2:13       ` [PATCH v2 19/29] tree-walk.h API: formatting changes for subsequent commit Ævar Arnfjörð Bjarmason
@ 2021-03-16  2:13       ` Ævar Arnfjörð Bjarmason
  2021-03-16  2:13       ` [PATCH v2 21/29] tree-walk.h API users: use "tmp" for mode in shift_tree_by() Ævar Arnfjörð Bjarmason
                         ` (8 subsequent siblings)
  31 siblings, 0 replies; 262+ messages in thread
From: Ævar Arnfjörð Bjarmason @ 2021-03-16  2:13 UTC (permalink / raw)
  To: git
  Cc: Junio C Hamano, Elijah Newren, Kirill Smelkov,
	Nguyễn Thái Ngọc Duy,
	Ævar Arnfjörð Bjarmason

Rename the get_tree_entry() function to get_tree_entry_mode(). This
change is only a search-replacement of the name and indentation of the
argument lists.

A subsequent commits will add get_tree_entry_type() and
get_tree_entry_all() functions. Those changes will be much easier to
read if we do this rename first.

Signed-off-by: Ævar Arnfjörð Bjarmason <avarab@gmail.com>
---
 archive.c              |  8 ++++----
 blame.c                |  6 +++---
 builtin/rm.c           |  2 +-
 builtin/update-index.c |  2 +-
 line-log.c             |  2 +-
 match-trees.c          |  6 +++---
 merge-recursive.c      | 18 +++++++++---------
 notes.c                |  2 +-
 object-name.c          |  6 +++---
 tree-walk.c            | 14 +++++++-------
 tree-walk.h            |  6 +++---
 11 files changed, 36 insertions(+), 36 deletions(-)

diff --git a/archive.c b/archive.c
index 254e15c8d03..ab031079580 100644
--- a/archive.c
+++ b/archive.c
@@ -482,10 +482,10 @@ static void parse_treeish_arg(const char **argv,
 		unsigned short mode;
 		int err;
 
-		err = get_tree_entry(ar_args->repo,
-				     &tree->object.oid,
-				     prefix, &tree_oid,
-				     &mode);
+		err = get_tree_entry_mode(ar_args->repo,
+					  &tree->object.oid,
+					  prefix, &tree_oid,
+					  &mode);
 		if (err || !S_ISDIR(mode))
 			die(_("current working directory is untracked"));
 
diff --git a/blame.c b/blame.c
index 83babc41d08..9e0543e13d4 100644
--- a/blame.c
+++ b/blame.c
@@ -102,8 +102,8 @@ static void verify_working_tree_path(struct repository *r,
 		const struct object_id *commit_oid = &parents->item->object.oid;
 		struct object_id blob_oid;
 		unsigned short mode;
-		int ret = get_tree_entry(r, commit_oid, path, &blob_oid,
-					 &mode);
+		int ret = get_tree_entry_mode(r, commit_oid, path, &blob_oid,
+					      &mode);
 
 		if (!ret && oid_object_info(r, &blob_oid, NULL) == OBJ_BLOB)
 			return;
@@ -1239,7 +1239,7 @@ static int fill_blob_sha1_and_mode(struct repository *r,
 {
 	if (!is_null_oid(&origin->blob_oid))
 		return 0;
-	if (get_tree_entry(r, &origin->commit->object.oid, origin->path, &origin->blob_oid, &origin->mode))
+	if (get_tree_entry_mode(r, &origin->commit->object.oid, origin->path, &origin->blob_oid, &origin->mode))
 		goto error_out;
 	if (oid_object_info(r, &origin->blob_oid, NULL) != OBJ_BLOB)
 		goto error_out;
diff --git a/builtin/rm.c b/builtin/rm.c
index 4858631e0f0..4617388b29a 100644
--- a/builtin/rm.c
+++ b/builtin/rm.c
@@ -179,7 +179,7 @@ static int check_local_mod(struct object_id *head, int index_only)
 		 * way as changed from the HEAD.
 		 */
 		if (no_head
-		     || get_tree_entry(the_repository, head, name, &oid, &mode)
+		     || get_tree_entry_mode(the_repository, head, name, &oid, &mode)
 		     || ce->ce_mode != create_ce_mode(mode)
 		     || !oideq(&ce->oid, &oid))
 			staged_changes = 1;
diff --git a/builtin/update-index.c b/builtin/update-index.c
index 79087bccea4..070510d6a88 100644
--- a/builtin/update-index.c
+++ b/builtin/update-index.c
@@ -603,7 +603,7 @@ static struct cache_entry *read_one_ent(const char *which,
 	struct object_id oid;
 	struct cache_entry *ce;
 
-	if (get_tree_entry(the_repository, ent, path, &oid, &mode)) {
+	if (get_tree_entry_mode(the_repository, ent, path, &oid, &mode)) {
 		if (which)
 			error("%s: not in %s branch.", path, which);
 		return NULL;
diff --git a/line-log.c b/line-log.c
index 75c8b1acfff..4790dda4607 100644
--- a/line-log.c
+++ b/line-log.c
@@ -503,7 +503,7 @@ static void fill_blob_sha1(struct repository *r, struct commit *commit,
 	unsigned short mode;
 	struct object_id oid;
 
-	if (get_tree_entry(r, &commit->object.oid, spec->path, &oid, &mode))
+	if (get_tree_entry_mode(r, &commit->object.oid, spec->path, &oid, &mode))
 		die("There is no path %s in the commit", spec->path);
 	fill_filespec(spec, &oid, 1, mode);
 
diff --git a/match-trees.c b/match-trees.c
index f3e192ca74d..0faacd8f4ae 100644
--- a/match-trees.c
+++ b/match-trees.c
@@ -293,7 +293,7 @@ void shift_tree(struct repository *r,
 		if (!*del_prefix)
 			return;
 
-		if (get_tree_entry(r, hash2, del_prefix, shifted, &mode))
+		if (get_tree_entry_mode(r, hash2, del_prefix, shifted, &mode))
 			die("cannot find path %s in tree %s",
 			    del_prefix, oid_to_hex(hash2));
 		return;
@@ -321,12 +321,12 @@ void shift_tree_by(struct repository *r,
 	unsigned candidate = 0;
 
 	/* Can hash2 be a tree at shift_prefix in tree hash1? */
-	if (!get_tree_entry(r, hash1, shift_prefix, &sub1, &mode1) &&
+	if (!get_tree_entry_mode(r, hash1, shift_prefix, &sub1, &mode1) &&
 	    S_ISDIR(mode1))
 		candidate |= 1;
 
 	/* Can hash1 be a tree at shift_prefix in tree hash2? */
-	if (!get_tree_entry(r, hash2, shift_prefix, &sub2, &mode2) &&
+	if (!get_tree_entry_mode(r, hash2, shift_prefix, &sub2, &mode2) &&
 	    S_ISDIR(mode2))
 		candidate |= 2;
 
diff --git a/merge-recursive.c b/merge-recursive.c
index df4b369902f..bbbb68e15bc 100644
--- a/merge-recursive.c
+++ b/merge-recursive.c
@@ -487,7 +487,7 @@ static int get_tree_entry_if_blob(struct repository *r,
 {
 	int ret;
 
-	ret = get_tree_entry(r, tree, path, &dfs->oid, &dfs->mode);
+	ret = get_tree_entry_mode(r, tree, path, &dfs->oid, &dfs->mode);
 	if (S_ISDIR(dfs->mode)) {
 		oidcpy(&dfs->oid, &null_oid);
 		dfs->mode = 0;
@@ -1886,9 +1886,9 @@ static int tree_has_path(struct repository *r, struct tree *tree,
 	struct object_id hashy;
 	unsigned short mode_o;
 
-	return !get_tree_entry(r,
-			       &tree->object.oid, path,
-			       &hashy, &mode_o);
+	return !get_tree_entry_mode(r,
+				    &tree->object.oid, path,
+				    &hashy, &mode_o);
 }
 
 /*
@@ -2541,11 +2541,11 @@ static void apply_directory_rename_modifications(struct merge_options *opt,
 	 * the various handle_rename_*() functions update the index
 	 * explicitly rather than relying on unpack_trees() to have done it.
 	 */
-	get_tree_entry(opt->repo,
-		       &tree->object.oid,
-		       pair->two->path,
-		       &re->dst_entry->stages[stage].oid,
-		       &re->dst_entry->stages[stage].mode);
+	get_tree_entry_mode(opt->repo,
+			    &tree->object.oid,
+			    pair->two->path,
+			    &re->dst_entry->stages[stage].oid,
+			    &re->dst_entry->stages[stage].mode);
 
 	/*
 	 * Record the original change status (or 'type' of change).  If it
diff --git a/notes.c b/notes.c
index 688d03ee9cd..ef138606146 100644
--- a/notes.c
+++ b/notes.c
@@ -1021,7 +1021,7 @@ void init_notes(struct notes_tree *t, const char *notes_ref,
 		return;
 	if (flags & NOTES_INIT_WRITABLE && read_ref(notes_ref, &object_oid))
 		die("Cannot use notes ref %s", notes_ref);
-	if (get_tree_entry(the_repository, &object_oid, "", &oid, &mode))
+	if (get_tree_entry_mode(the_repository, &object_oid, "", &oid, &mode))
 		die("Failed to read notes tree referenced by %s (%s)",
 		    notes_ref, oid_to_hex(&object_oid));
 
diff --git a/object-name.c b/object-name.c
index 64202de60b1..7e3b2d6d739 100644
--- a/object-name.c
+++ b/object-name.c
@@ -1704,7 +1704,7 @@ static void diagnose_invalid_oid_path(struct repository *r,
 	if (is_missing_file_error(errno)) {
 		char *fullname = xstrfmt("%s%s", prefix, filename);
 
-		if (!get_tree_entry(r, tree_oid, fullname, &oid, &mode)) {
+		if (!get_tree_entry_mode(r, tree_oid, fullname, &oid, &mode)) {
 			die(_("path '%s' exists, but not '%s'\n"
 			    "hint: Did you mean '%.*s:%s' aka '%.*s:./%s'?"),
 			    fullname,
@@ -1903,8 +1903,8 @@ static enum get_oid_result get_oid_with_context_1(struct repository *repo,
 					filename, oid, &oc->symlink_path,
 					&oc->mode);
 			} else {
-				ret = get_tree_entry(repo, &tree_oid, filename, oid,
-						     &oc->mode);
+				ret = get_tree_entry_mode(repo, &tree_oid, filename, oid,
+							  &oc->mode);
 				if (ret && only_to_die) {
 					diagnose_invalid_oid_path(repo, prefix,
 								   filename,
diff --git a/tree-walk.c b/tree-walk.c
index e88187e3714..7819ff3e0ec 100644
--- a/tree-walk.c
+++ b/tree-walk.c
@@ -591,17 +591,17 @@ static int find_tree_entry(struct repository *r, struct tree_desc *t,
 			oidcpy(result, &oid);
 			return 0;
 		}
-		return get_tree_entry(r, &oid, name + entrylen, result,
-				      mode);
+		return get_tree_entry_mode(r, &oid, name + entrylen, result,
+					   mode);
 	}
 	return -1;
 }
 
-int get_tree_entry(struct repository *r,
-		   const struct object_id *tree_oid,
-		   const char *name,
-		   struct object_id *oid,
-		   unsigned short *mode)
+int get_tree_entry_mode(struct repository *r,
+			const struct object_id *tree_oid,
+			const char *name,
+			struct object_id *oid,
+			unsigned short *mode)
 {
 	int retval;
 	void *tree;
diff --git a/tree-walk.h b/tree-walk.h
index 478a659ee2b..eb9b9de6ccc 100644
--- a/tree-walk.h
+++ b/tree-walk.h
@@ -174,9 +174,9 @@ struct traverse_info {
  * The third and fourth parameters are set to the entry's sha1 and
  * mode respectively.
  */
-int get_tree_entry(struct repository *, const struct object_id *, const char *,
-		   struct object_id *,
-		   unsigned short *);
+int get_tree_entry_mode(struct repository *, const struct object_id *, const char *,
+			struct object_id *,
+			unsigned short *);
 
 /**
  * Generate the full pathname of a tree entry based from the root of the
-- 
2.31.0.rc2.211.g1d0b8788b3


^ permalink raw reply	[flat|nested] 262+ messages in thread

* [PATCH v2 21/29] tree-walk.h API users: use "tmp" for mode in shift_tree_by()
  2021-03-08 15:06     ` [PATCH 00/30] tree-walk: mostly "mode" to "enum object_type" Ævar Arnfjörð Bjarmason
                         ` (22 preceding siblings ...)
  2021-03-16  2:13       ` [PATCH v2 20/29] tree-walk.h API: rename get_tree_entry() to get_tree_entry_mode() Ævar Arnfjörð Bjarmason
@ 2021-03-16  2:13       ` Ævar Arnfjörð Bjarmason
  2021-03-16  6:34         ` Elijah Newren
  2021-03-16  2:13       ` [PATCH v2 22/29] tree-walk.h API: add get_tree_entry_type() Ævar Arnfjörð Bjarmason
                         ` (7 subsequent siblings)
  31 siblings, 1 reply; 262+ messages in thread
From: Ævar Arnfjörð Bjarmason @ 2021-03-16  2:13 UTC (permalink / raw)
  To: git
  Cc: Junio C Hamano, Elijah Newren, Kirill Smelkov,
	Nguyễn Thái Ngọc Duy,
	Ævar Arnfjörð Bjarmason

Refactor code added in 85e51b783c3 (Make "subtree" part more
orthogonal to the rest of merge-recursive., 2008-06-30) to make it
obvious that we don't care about the "mode" here outside of the if
statement it appears in.

That's opposed to the sub1 & sub2 variables, where we use the two
object ids later in this function.

Signed-off-by: Ævar Arnfjörð Bjarmason <avarab@gmail.com>
---
 match-trees.c | 10 +++++-----
 1 file changed, 5 insertions(+), 5 deletions(-)

diff --git a/match-trees.c b/match-trees.c
index 0faacd8f4ae..e84f993a460 100644
--- a/match-trees.c
+++ b/match-trees.c
@@ -317,17 +317,17 @@ void shift_tree_by(struct repository *r,
 		   const char *shift_prefix)
 {
 	struct object_id sub1, sub2;
-	unsigned short mode1, mode2;
+	unsigned short tmp;
 	unsigned candidate = 0;
 
 	/* Can hash2 be a tree at shift_prefix in tree hash1? */
-	if (!get_tree_entry_mode(r, hash1, shift_prefix, &sub1, &mode1) &&
-	    S_ISDIR(mode1))
+	if (!get_tree_entry_mode(r, hash1, shift_prefix, &sub1, &tmp) &&
+	    S_ISDIR(tmp))
 		candidate |= 1;
 
 	/* Can hash1 be a tree at shift_prefix in tree hash2? */
-	if (!get_tree_entry_mode(r, hash2, shift_prefix, &sub2, &mode2) &&
-	    S_ISDIR(mode2))
+	if (!get_tree_entry_mode(r, hash2, shift_prefix, &sub2, &tmp) &&
+	    S_ISDIR(tmp))
 		candidate |= 2;
 
 	if (candidate == 3) {
-- 
2.31.0.rc2.211.g1d0b8788b3


^ permalink raw reply	[flat|nested] 262+ messages in thread

* [PATCH v2 22/29] tree-walk.h API: add get_tree_entry_type()
  2021-03-08 15:06     ` [PATCH 00/30] tree-walk: mostly "mode" to "enum object_type" Ævar Arnfjörð Bjarmason
                         ` (23 preceding siblings ...)
  2021-03-16  2:13       ` [PATCH v2 21/29] tree-walk.h API users: use "tmp" for mode in shift_tree_by() Ævar Arnfjörð Bjarmason
@ 2021-03-16  2:13       ` Ævar Arnfjörð Bjarmason
  2021-03-16  2:13       ` [PATCH v2 23/29] tree-walk.h API: document and format tree_entry_extract() Ævar Arnfjörð Bjarmason
                         ` (6 subsequent siblings)
  31 siblings, 0 replies; 262+ messages in thread
From: Ævar Arnfjörð Bjarmason @ 2021-03-16  2:13 UTC (permalink / raw)
  To: git
  Cc: Junio C Hamano, Elijah Newren, Kirill Smelkov,
	Nguyễn Thái Ngọc Duy,
	Ævar Arnfjörð Bjarmason

Add a get_tree_entry_type() helper function to compliment the existing
get_tree_entry(), and a static get_tree_entry_all() which it uses internally.

Move those users of get_tree_entry_type() who didn't care about the
mode specifically, but just want to know whether the tree entry is one
of OBJ_{BLOB,COMMIT,TREE} over to the new get_tree_entry_type().

The get_tree_entry_all() function itself will be made non-static in a
subsequent commit. I'm leaving its argument list indented accordingly
to reduce churn when I do so.

Signed-off-by: Ævar Arnfjörð Bjarmason <avarab@gmail.com>
---
 archive.c     |  8 ++++----
 match-trees.c | 10 +++++-----
 tree-walk.c   | 54 ++++++++++++++++++++++++++++++++++++++++-----------
 tree-walk.h   | 11 +++++++++--
 4 files changed, 61 insertions(+), 22 deletions(-)

diff --git a/archive.c b/archive.c
index ab031079580..d6aef83b692 100644
--- a/archive.c
+++ b/archive.c
@@ -479,14 +479,14 @@ static void parse_treeish_arg(const char **argv,
 
 	if (prefix) {
 		struct object_id tree_oid;
-		unsigned short mode;
+		enum object_type object_type;
 		int err;
 
-		err = get_tree_entry_mode(ar_args->repo,
+		err = get_tree_entry_type(ar_args->repo,
 					  &tree->object.oid,
 					  prefix, &tree_oid,
-					  &mode);
-		if (err || !S_ISDIR(mode))
+					  &object_type);
+		if (err || object_type != OBJ_TREE)
 			die(_("current working directory is untracked"));
 
 		tree = parse_tree_indirect(&tree_oid);
diff --git a/match-trees.c b/match-trees.c
index e84f993a460..3177558313e 100644
--- a/match-trees.c
+++ b/match-trees.c
@@ -317,17 +317,17 @@ void shift_tree_by(struct repository *r,
 		   const char *shift_prefix)
 {
 	struct object_id sub1, sub2;
-	unsigned short tmp;
+	enum object_type tmp;
 	unsigned candidate = 0;
 
 	/* Can hash2 be a tree at shift_prefix in tree hash1? */
-	if (!get_tree_entry_mode(r, hash1, shift_prefix, &sub1, &tmp) &&
-	    S_ISDIR(tmp))
+	if (!get_tree_entry_type(r, hash1, shift_prefix, &sub1, &tmp) &&
+	    tmp == OBJ_TREE)
 		candidate |= 1;
 
 	/* Can hash1 be a tree at shift_prefix in tree hash2? */
-	if (!get_tree_entry_mode(r, hash2, shift_prefix, &sub2, &tmp) &&
-	    S_ISDIR(tmp))
+	if (!get_tree_entry_type(r, hash2, shift_prefix, &sub2, &tmp) &&
+	    tmp == OBJ_TREE)
 		candidate |= 2;
 
 	if (candidate == 3) {
diff --git a/tree-walk.c b/tree-walk.c
index 7819ff3e0ec..46ce1ba8069 100644
--- a/tree-walk.c
+++ b/tree-walk.c
@@ -559,9 +559,17 @@ struct dir_state {
 	struct object_id oid;
 };
 
+static int get_tree_entry_all(struct repository *r,
+			      const struct object_id *tree_oid,
+			      const char *name,
+			      struct object_id *oid,
+			      unsigned short *mode,
+			      enum object_type *object_type);
+
 static int find_tree_entry(struct repository *r, struct tree_desc *t,
 			   const char *name, struct object_id *result,
-			   unsigned short *mode)
+			   unsigned short *mode,
+			   enum object_type *object_type)
 {
 	int namelen = strlen(name);
 	while (t->size) {
@@ -585,23 +593,24 @@ static int find_tree_entry(struct repository *r, struct tree_desc *t,
 		}
 		if (name[entrylen] != '/')
 			continue;
-		if (!S_ISDIR(*mode))
+		if (*object_type != OBJ_TREE)
 			break;
 		if (++entrylen == namelen) {
 			oidcpy(result, &oid);
 			return 0;
 		}
-		return get_tree_entry_mode(r, &oid, name + entrylen, result,
-					   mode);
+		return get_tree_entry_all(r, &oid, name + entrylen, result,
+					  mode, object_type);
 	}
 	return -1;
 }
 
-int get_tree_entry_mode(struct repository *r,
-			const struct object_id *tree_oid,
-			const char *name,
-			struct object_id *oid,
-			unsigned short *mode)
+static int get_tree_entry_all(struct repository *r,
+		       const struct object_id *tree_oid,
+		       const char *name,
+		       struct object_id *oid,
+		       unsigned short *mode,
+		       enum object_type *object_type)
 {
 	int retval;
 	void *tree;
@@ -624,12 +633,34 @@ int get_tree_entry_mode(struct repository *r,
 		struct tree_desc t;
 		init_tree_desc(&t, tree, size);
 		retval = find_tree_entry(r, &t, name, oid,
-					 mode);
+					 mode, object_type);
 	}
 	free(tree);
 	return retval;
 }
 
+int get_tree_entry_mode(struct repository *r,
+			const struct object_id *tree_oid,
+			const char *name,
+			struct object_id *oid,
+			unsigned short *mode)
+{
+	enum object_type object_type;
+	return get_tree_entry_all(r, tree_oid, name, oid,
+				  mode, &object_type);
+}
+
+int get_tree_entry_type(struct repository *r,
+			const struct object_id *tree_oid,
+			const char *name,
+			struct object_id *oid,
+			enum object_type *object_type)
+{
+	unsigned short mode;
+	return get_tree_entry_all(r, tree_oid, name, oid,
+				  &mode, object_type);
+}
+
 /*
  * This is Linux's built-in max for the number of symlinks to follow.
  * That limit, of course, does not affect git, but it's a reasonable
@@ -674,6 +705,7 @@ enum get_oid_result get_tree_entry_follow_symlinks(struct repository *r,
 		int find_result;
 		char *first_slash;
 		char *remainder = NULL;
+		enum object_type object_type;
 
 		if (!t.buffer) {
 			void *tree;
@@ -751,7 +783,7 @@ enum get_oid_result get_tree_entry_follow_symlinks(struct repository *r,
 		/* Look up the first (or only) path component in the tree. */
 		find_result = find_tree_entry(r, &t, namebuf.buf,
 					      &current_tree_oid,
-					      mode);
+					      mode, &object_type);
 		if (find_result) {
 			goto done;
 		}
diff --git a/tree-walk.h b/tree-walk.h
index eb9b9de6ccc..f569960c6fb 100644
--- a/tree-walk.h
+++ b/tree-walk.h
@@ -171,12 +171,19 @@ struct traverse_info {
  * Find an entry in a tree given a pathname and the sha1 of a tree to
  * search. Returns 0 if the entry is found and -1 otherwise.
  *
- * The third and fourth parameters are set to the entry's sha1 and
- * mode respectively.
+ * There are variants of this function depending on what fields in the
+ * "struct name_entry" you'd like. You always need a pointer to an
+ * appropriate variable to fill in (NULL won't do!):
+ *
+ * get_tree_entry_mode(): unsigned int mode
+ * get_tree_entry_type(): enum object_type
  */
 int get_tree_entry_mode(struct repository *, const struct object_id *, const char *,
 			struct object_id *,
 			unsigned short *);
+int get_tree_entry_type(struct repository *, const struct object_id *, const char *,
+			struct object_id *,
+			enum object_type *);
 
 /**
  * Generate the full pathname of a tree entry based from the root of the
-- 
2.31.0.rc2.211.g1d0b8788b3


^ permalink raw reply	[flat|nested] 262+ messages in thread

* [PATCH v2 23/29] tree-walk.h API: document and format tree_entry_extract()
  2021-03-08 15:06     ` [PATCH 00/30] tree-walk: mostly "mode" to "enum object_type" Ævar Arnfjörð Bjarmason
                         ` (24 preceding siblings ...)
  2021-03-16  2:13       ` [PATCH v2 22/29] tree-walk.h API: add get_tree_entry_type() Ævar Arnfjörð Bjarmason
@ 2021-03-16  2:13       ` Ævar Arnfjörð Bjarmason
  2021-03-16  2:13       ` [PATCH v2 24/29] tree-entry.h API: rename tree_entry_extract() to tree_entry_extract_mode() Ævar Arnfjörð Bjarmason
                         ` (5 subsequent siblings)
  31 siblings, 0 replies; 262+ messages in thread
From: Ævar Arnfjörð Bjarmason @ 2021-03-16  2:13 UTC (permalink / raw)
  To: git
  Cc: Junio C Hamano, Elijah Newren, Kirill Smelkov,
	Nguyễn Thái Ngọc Duy,
	Ævar Arnfjörð Bjarmason

Document and format the argument list of the tree_entry_extract()
function in preparation for adding a sister function.

Signed-off-by: Ævar Arnfjörð Bjarmason <avarab@gmail.com>
---
 tree-walk.h | 14 ++++++++++----
 1 file changed, 10 insertions(+), 4 deletions(-)

diff --git a/tree-walk.h b/tree-walk.h
index f569960c6fb..f51485250fb 100644
--- a/tree-walk.h
+++ b/tree-walk.h
@@ -40,11 +40,17 @@ struct tree_desc {
 
 /**
  * Decode the entry currently being visited (the one pointed to by
- * `tree_desc's` `entry` member) and return the sha1 of the entry. The
- * `pathp` and `modep` arguments are set to the entry's pathname and mode
- * respectively.
+ * `tree_desc's` `entry` member) and return the OID of the entry.
+ *
+ * There are variants of this function depending on what fields in the
+ * "struct name_entry" you'd like. You always need a pointer to an
+ * appropriate variable to fill in (NULL won't do!):
+ *
+ * tree_entry_extract_mode(): const char *path, unsigned int mode
  */
-static inline const struct object_id *tree_entry_extract(struct tree_desc *desc, const char **pathp, unsigned short *modep)
+static inline const struct object_id *tree_entry_extract(struct tree_desc *desc,
+							 const char **pathp,
+							 unsigned short *modep)
 {
 	*pathp = desc->entry.path;
 	*modep = desc->entry.mode;
-- 
2.31.0.rc2.211.g1d0b8788b3


^ permalink raw reply	[flat|nested] 262+ messages in thread

* [PATCH v2 24/29] tree-entry.h API: rename tree_entry_extract() to tree_entry_extract_mode()
  2021-03-08 15:06     ` [PATCH 00/30] tree-walk: mostly "mode" to "enum object_type" Ævar Arnfjörð Bjarmason
                         ` (25 preceding siblings ...)
  2021-03-16  2:13       ` [PATCH v2 23/29] tree-walk.h API: document and format tree_entry_extract() Ævar Arnfjörð Bjarmason
@ 2021-03-16  2:13       ` Ævar Arnfjörð Bjarmason
  2021-03-16  2:13       ` [PATCH v2 25/29] tree-walk.h API: add a tree_entry_extract_all() function Ævar Arnfjörð Bjarmason
                         ` (4 subsequent siblings)
  31 siblings, 0 replies; 262+ messages in thread
From: Ævar Arnfjörð Bjarmason @ 2021-03-16  2:13 UTC (permalink / raw)
  To: git
  Cc: Junio C Hamano, Elijah Newren, Kirill Smelkov,
	Nguyễn Thái Ngọc Duy,
	Ævar Arnfjörð Bjarmason

As with the recent split of the get_tree_entry() function, rename the
tree_entry_extract() function to *_mode() in preparation for adding
other variants of it.

Signed-off-by: Ævar Arnfjörð Bjarmason <avarab@gmail.com>
---
 fsck.c        | 2 +-
 match-trees.c | 4 ++--
 tree-diff.c   | 4 ++--
 tree-walk.h   | 6 +++---
 4 files changed, 8 insertions(+), 8 deletions(-)

diff --git a/fsck.c b/fsck.c
index 7c74c49d329..11678ba5826 100644
--- a/fsck.c
+++ b/fsck.c
@@ -670,7 +670,7 @@ static int fsck_tree(const struct object_id *oid,
 		const char *name, *backslash;
 		const struct object_id *oid;
 
-		oid = tree_entry_extract(&desc, &name, &mode);
+		oid = tree_entry_extract_mode(&desc, &name, &mode);
 
 		has_null_sha1 |= is_null_oid(oid);
 		has_full_path |= !!strchr(name, '/');
diff --git a/match-trees.c b/match-trees.c
index 3177558313e..2afa4968109 100644
--- a/match-trees.c
+++ b/match-trees.c
@@ -146,7 +146,7 @@ static void match_trees(const struct object_id *hash1,
 		unsigned short mode;
 		int score;
 
-		elem = tree_entry_extract(&one, &path, &mode);
+		elem = tree_entry_extract_mode(&one, &path, &mode);
 		if (!S_ISDIR(mode))
 			goto next;
 		score = score_trees(elem, hash2);
@@ -202,7 +202,7 @@ static int splice_tree(const struct object_id *oid1, const char *prefix,
 		unsigned short mode;
 		int len = tree_entry_len(&desc.entry);
 
-		tree_entry_extract(&desc, &name, &mode);
+		tree_entry_extract_mode(&desc, &name, &mode);
 		if (len == toplen &&
 		    !memcmp(name, prefix, toplen)) {
 			if (!S_ISDIR(mode))
diff --git a/tree-diff.c b/tree-diff.c
index 088ed52d6a3..65c7e4dbc8b 100644
--- a/tree-diff.c
+++ b/tree-diff.c
@@ -196,7 +196,7 @@ static struct combine_diff_path *emit_path(struct combine_diff_path *p,
 
 	if (t) {
 		/* path present in resulting tree */
-		oid = tree_entry_extract(t, &path, &mode);
+		oid = tree_entry_extract_mode(t, &path, &mode);
 		pathlen = tree_entry_len(&t->entry);
 		isdir = S_ISDIR(mode);
 	} else {
@@ -207,7 +207,7 @@ static struct combine_diff_path *emit_path(struct combine_diff_path *p,
 		 * 1) all modes for tp[i]=tp[imin] should be the same wrt
 		 *    S_ISDIR, thanks to base_name_compare().
 		 */
-		tree_entry_extract(&tp[imin], &path, &mode);
+		tree_entry_extract_mode(&tp[imin], &path, &mode);
 		pathlen = tree_entry_len(&tp[imin].entry);
 
 		isdir = S_ISDIR(mode);
diff --git a/tree-walk.h b/tree-walk.h
index f51485250fb..805cda649ee 100644
--- a/tree-walk.h
+++ b/tree-walk.h
@@ -48,9 +48,9 @@ struct tree_desc {
  *
  * tree_entry_extract_mode(): const char *path, unsigned int mode
  */
-static inline const struct object_id *tree_entry_extract(struct tree_desc *desc,
-							 const char **pathp,
-							 unsigned short *modep)
+static inline const struct object_id *tree_entry_extract_mode(struct tree_desc *desc,
+							      const char **pathp,
+							      unsigned short *modep)
 {
 	*pathp = desc->entry.path;
 	*modep = desc->entry.mode;
-- 
2.31.0.rc2.211.g1d0b8788b3


^ permalink raw reply	[flat|nested] 262+ messages in thread

* [PATCH v2 25/29] tree-walk.h API: add a tree_entry_extract_all() function
  2021-03-08 15:06     ` [PATCH 00/30] tree-walk: mostly "mode" to "enum object_type" Ævar Arnfjörð Bjarmason
                         ` (26 preceding siblings ...)
  2021-03-16  2:13       ` [PATCH v2 24/29] tree-entry.h API: rename tree_entry_extract() to tree_entry_extract_mode() Ævar Arnfjörð Bjarmason
@ 2021-03-16  2:13       ` Ævar Arnfjörð Bjarmason
  2021-03-16  2:13       ` [PATCH v2 26/29] tree-walk.h API: add get_tree_entry_all() Ævar Arnfjörð Bjarmason
                         ` (3 subsequent siblings)
  31 siblings, 0 replies; 262+ messages in thread
From: Ævar Arnfjörð Bjarmason @ 2021-03-16  2:13 UTC (permalink / raw)
  To: git
  Cc: Junio C Hamano, Elijah Newren, Kirill Smelkov,
	Nguyễn Thái Ngọc Duy,
	Ævar Arnfjörð Bjarmason

Add a tree_entry_extract_all() sibling function to the existing
tree_entry_extract_mode().

Having the OBJ_{BLOB,TREE,COMMIT} when you have the "mode" is strictly
speaking redundant, but hopefully makes it easier to read the
code. We'll now see which parts of the code are checking the types,
v.s. those that care about the mode specifically.

Only the first use of tree_entry_extract_mode() in emit_path() is
converted here, the other branch will use a new
get_tree_entry_mode_type() introduced in a subsequent commit.

Signed-off-by: Ævar Arnfjörð Bjarmason <avarab@gmail.com>
---
 tree-diff.c |  5 +++--
 tree-walk.c |  2 +-
 tree-walk.h | 12 ++++++++++++
 3 files changed, 16 insertions(+), 3 deletions(-)

diff --git a/tree-diff.c b/tree-diff.c
index 65c7e4dbc8b..918ad95fa61 100644
--- a/tree-diff.c
+++ b/tree-diff.c
@@ -195,10 +195,11 @@ static struct combine_diff_path *emit_path(struct combine_diff_path *p,
 	assert(t || tp);
 
 	if (t) {
+		enum object_type object_type;
 		/* path present in resulting tree */
-		oid = tree_entry_extract_mode(t, &path, &mode);
+		oid = tree_entry_extract_all(t, &path, &mode, &object_type);
 		pathlen = tree_entry_len(&t->entry);
-		isdir = S_ISDIR(mode);
+		isdir = (object_type == OBJ_TREE);
 	} else {
 		/*
 		 * a path was removed - take path from imin parent. Also take
diff --git a/tree-walk.c b/tree-walk.c
index 46ce1ba8069..f4473276c9f 100644
--- a/tree-walk.c
+++ b/tree-walk.c
@@ -577,7 +577,7 @@ static int find_tree_entry(struct repository *r, struct tree_desc *t,
 		struct object_id oid;
 		int entrylen, cmp;
 
-		oidcpy(&oid, tree_entry_extract(t, &entry, mode));
+		oidcpy(&oid, tree_entry_extract_all(t, &entry, mode, object_type));
 		entrylen = tree_entry_len(&t->entry);
 		update_tree_entry(t);
 		if (entrylen > namelen)
diff --git a/tree-walk.h b/tree-walk.h
index 805cda649ee..a4c54871747 100644
--- a/tree-walk.h
+++ b/tree-walk.h
@@ -47,6 +47,7 @@ struct tree_desc {
  * appropriate variable to fill in (NULL won't do!):
  *
  * tree_entry_extract_mode(): const char *path, unsigned int mode
+ * tree_entry_extract_all(): const char *path, unsigned int mode, enum object_type
  */
 static inline const struct object_id *tree_entry_extract_mode(struct tree_desc *desc,
 							      const char **pathp,
@@ -57,6 +58,17 @@ static inline const struct object_id *tree_entry_extract_mode(struct tree_desc *
 	return &desc->entry.oid;
 }
 
+static inline const struct object_id *tree_entry_extract_all(struct tree_desc *desc,
+							     const char **pathp,
+							     unsigned short *modep,
+							     enum object_type *object_typep)
+{
+	*pathp = desc->entry.path;
+	*modep = desc->entry.mode;
+	*object_typep = desc->entry.object_type;
+	return &desc->entry.oid;
+}
+
 /**
  * Calculate the length of a tree entry's pathname. This utilizes the
  * memory structure of a tree entry to avoid the overhead of using a
-- 
2.31.0.rc2.211.g1d0b8788b3


^ permalink raw reply	[flat|nested] 262+ messages in thread

* [PATCH v2 26/29] tree-walk.h API: add get_tree_entry_all()
  2021-03-08 15:06     ` [PATCH 00/30] tree-walk: mostly "mode" to "enum object_type" Ævar Arnfjörð Bjarmason
                         ` (27 preceding siblings ...)
  2021-03-16  2:13       ` [PATCH v2 25/29] tree-walk.h API: add a tree_entry_extract_all() function Ævar Arnfjörð Bjarmason
@ 2021-03-16  2:13       ` Ævar Arnfjörð Bjarmason
  2021-03-16  2:13       ` [PATCH v2 27/29] tree-walk.h API: add a get_tree_entry_path() function Ævar Arnfjörð Bjarmason
                         ` (2 subsequent siblings)
  31 siblings, 0 replies; 262+ messages in thread
From: Ævar Arnfjörð Bjarmason @ 2021-03-16  2:13 UTC (permalink / raw)
  To: git
  Cc: Junio C Hamano, Elijah Newren, Kirill Smelkov,
	Nguyễn Thái Ngọc Duy,
	Ævar Arnfjörð Bjarmason

Add a get_tree_entry_all() function and use it in the one caller who
cares about both the mode and the object type. Refactor it accordingly
to make it clear which parts care about the mode, and which about the
object_type.

Signed-off-by: Ævar Arnfjörð Bjarmason <avarab@gmail.com>
---
 builtin/update-index.c | 6 ++++--
 tree-walk.c            | 9 +--------
 tree-walk.h            | 4 ++++
 3 files changed, 9 insertions(+), 10 deletions(-)

diff --git a/builtin/update-index.c b/builtin/update-index.c
index 070510d6a88..b489a876392 100644
--- a/builtin/update-index.c
+++ b/builtin/update-index.c
@@ -599,16 +599,18 @@ static struct cache_entry *read_one_ent(const char *which,
 					struct object_id *ent, const char *path,
 					int namelen, int stage)
 {
+	enum object_type object_type;
 	unsigned short mode;
 	struct object_id oid;
 	struct cache_entry *ce;
 
-	if (get_tree_entry_mode(the_repository, ent, path, &oid, &mode)) {
+	if (get_tree_entry_all(the_repository, ent, path, &oid,
+			       &mode, &object_type)) {
 		if (which)
 			error("%s: not in %s branch.", path, which);
 		return NULL;
 	}
-	if (mode == S_IFDIR) {
+	if (object_type == OBJ_TREE) {
 		if (which)
 			error("%s: not a blob in %s branch.", path, which);
 		return NULL;
diff --git a/tree-walk.c b/tree-walk.c
index f4473276c9f..a90dbf87af4 100644
--- a/tree-walk.c
+++ b/tree-walk.c
@@ -559,13 +559,6 @@ struct dir_state {
 	struct object_id oid;
 };
 
-static int get_tree_entry_all(struct repository *r,
-			      const struct object_id *tree_oid,
-			      const char *name,
-			      struct object_id *oid,
-			      unsigned short *mode,
-			      enum object_type *object_type);
-
 static int find_tree_entry(struct repository *r, struct tree_desc *t,
 			   const char *name, struct object_id *result,
 			   unsigned short *mode,
@@ -605,7 +598,7 @@ static int find_tree_entry(struct repository *r, struct tree_desc *t,
 	return -1;
 }
 
-static int get_tree_entry_all(struct repository *r,
+int get_tree_entry_all(struct repository *r,
 		       const struct object_id *tree_oid,
 		       const char *name,
 		       struct object_id *oid,
diff --git a/tree-walk.h b/tree-walk.h
index a4c54871747..55ef88ef2e5 100644
--- a/tree-walk.h
+++ b/tree-walk.h
@@ -195,6 +195,7 @@ struct traverse_info {
  *
  * get_tree_entry_mode(): unsigned int mode
  * get_tree_entry_type(): enum object_type
+ * get_tree_entry_all(): unsigned int mode, enum object_type
  */
 int get_tree_entry_mode(struct repository *, const struct object_id *, const char *,
 			struct object_id *,
@@ -202,6 +203,9 @@ int get_tree_entry_mode(struct repository *, const struct object_id *, const cha
 int get_tree_entry_type(struct repository *, const struct object_id *, const char *,
 			struct object_id *,
 			enum object_type *);
+int get_tree_entry_all(struct repository *, const struct object_id *, const char *,
+		       struct object_id *,
+		       unsigned short *, enum object_type *);
 
 /**
  * Generate the full pathname of a tree entry based from the root of the
-- 
2.31.0.rc2.211.g1d0b8788b3


^ permalink raw reply	[flat|nested] 262+ messages in thread

* [PATCH v2 27/29] tree-walk.h API: add a get_tree_entry_path() function
  2021-03-08 15:06     ` [PATCH 00/30] tree-walk: mostly "mode" to "enum object_type" Ævar Arnfjörð Bjarmason
                         ` (28 preceding siblings ...)
  2021-03-16  2:13       ` [PATCH v2 26/29] tree-walk.h API: add get_tree_entry_all() Ævar Arnfjörð Bjarmason
@ 2021-03-16  2:13       ` Ævar Arnfjörð Bjarmason
  2021-03-16  6:50         ` Elijah Newren
  2021-03-16  2:13       ` [PATCH v2 28/29] blame: emit a better error on 'git blame directory' Ævar Arnfjörð Bjarmason
  2021-03-16  2:13       ` [PATCH v2 29/29] tree-walk.h API: add a tree_entry_extract_type() function Ævar Arnfjörð Bjarmason
  31 siblings, 1 reply; 262+ messages in thread
From: Ævar Arnfjörð Bjarmason @ 2021-03-16  2:13 UTC (permalink / raw)
  To: git
  Cc: Junio C Hamano, Elijah Newren, Kirill Smelkov,
	Nguyễn Thái Ngọc Duy,
	Ævar Arnfjörð Bjarmason

Add a get_tree_entry_path() variant in addition to
get_tree_entry_path_{mode,type,all}(). This is for those callers that
need neither the mode nor "enum object_type" parameters filled for
them.

There's callers here which doesn't need the "struct object_id" filled
either, and provides a throwaway variable for us.

See the following commits for the introduction of such code that's
being modified here:

 - shift_tree(): 68faf68938e (A new merge stragety 'subtree'.,
    2007-02-15) for the shift_tree()

 - tree_has_path(): 96e7ffbdc31 (merge-recursive: check for directory
   level conflicts, 2018-04-19)

 - init_notes(): fd53c9eb445 (Speed up git notes lookup, 2009-10-09)

 - diagnose_invalid_oid_path(): 009fee4774d (Detailed diagnosis when
   parsing an object name fails., 2009-12-07)

Those could potentially be refactored too, but I've got to stop at
some point, and right now I'm focusing downstream code that depends on
"mode" (or "enum object_type").

Signed-off-by: Ævar Arnfjörð Bjarmason <avarab@gmail.com>
---
 match-trees.c     |  4 +---
 merge-recursive.c |  6 ++----
 notes.c           |  3 +--
 object-name.c     |  3 +--
 tree-walk.c       | 11 +++++++++++
 tree-walk.h       |  3 +++
 6 files changed, 19 insertions(+), 11 deletions(-)

diff --git a/match-trees.c b/match-trees.c
index 2afa4968109..25bfb46fb02 100644
--- a/match-trees.c
+++ b/match-trees.c
@@ -288,12 +288,10 @@ void shift_tree(struct repository *r,
 
 	if (add_score < del_score) {
 		/* We need to pick a subtree of two */
-		unsigned short mode;
-
 		if (!*del_prefix)
 			return;
 
-		if (get_tree_entry_mode(r, hash2, del_prefix, shifted, &mode))
+		if (get_tree_entry_path(r, hash2, del_prefix, shifted))
 			die("cannot find path %s in tree %s",
 			    del_prefix, oid_to_hex(hash2));
 		return;
diff --git a/merge-recursive.c b/merge-recursive.c
index bbbb68e15bc..83d2b8b8440 100644
--- a/merge-recursive.c
+++ b/merge-recursive.c
@@ -1884,11 +1884,9 @@ static int tree_has_path(struct repository *r, struct tree *tree,
 			 const char *path)
 {
 	struct object_id hashy;
-	unsigned short mode_o;
-
-	return !get_tree_entry_mode(r,
+	return !get_tree_entry_path(r,
 				    &tree->object.oid, path,
-				    &hashy, &mode_o);
+				    &hashy);
 }
 
 /*
diff --git a/notes.c b/notes.c
index ef138606146..aa46cb2b09e 100644
--- a/notes.c
+++ b/notes.c
@@ -994,7 +994,6 @@ void init_notes(struct notes_tree *t, const char *notes_ref,
 		combine_notes_fn combine_notes, int flags)
 {
 	struct object_id oid, object_oid;
-	unsigned short mode;
 	struct leaf_node root_tree;
 
 	if (!t)
@@ -1021,7 +1020,7 @@ void init_notes(struct notes_tree *t, const char *notes_ref,
 		return;
 	if (flags & NOTES_INIT_WRITABLE && read_ref(notes_ref, &object_oid))
 		die("Cannot use notes ref %s", notes_ref);
-	if (get_tree_entry_mode(the_repository, &object_oid, "", &oid, &mode))
+	if (get_tree_entry_path(the_repository, &object_oid, "", &oid))
 		die("Failed to read notes tree referenced by %s (%s)",
 		    notes_ref, oid_to_hex(&object_oid));
 
diff --git a/object-name.c b/object-name.c
index 7e3b2d6d739..9ff5f83c1ff 100644
--- a/object-name.c
+++ b/object-name.c
@@ -1693,7 +1693,6 @@ static void diagnose_invalid_oid_path(struct repository *r,
 				      int object_name_len)
 {
 	struct object_id oid;
-	unsigned short mode;
 
 	if (!prefix)
 		prefix = "";
@@ -1704,7 +1703,7 @@ static void diagnose_invalid_oid_path(struct repository *r,
 	if (is_missing_file_error(errno)) {
 		char *fullname = xstrfmt("%s%s", prefix, filename);
 
-		if (!get_tree_entry_mode(r, tree_oid, fullname, &oid, &mode)) {
+		if (!get_tree_entry_path(r, tree_oid, fullname, &oid)) {
 			die(_("path '%s' exists, but not '%s'\n"
 			    "hint: Did you mean '%.*s:%s' aka '%.*s:./%s'?"),
 			    fullname,
diff --git a/tree-walk.c b/tree-walk.c
index a90dbf87af4..fa846535dfb 100644
--- a/tree-walk.c
+++ b/tree-walk.c
@@ -632,6 +632,17 @@ int get_tree_entry_all(struct repository *r,
 	return retval;
 }
 
+int get_tree_entry_path(struct repository *r,
+			const struct object_id *tree_oid,
+			const char *name,
+			struct object_id *oid)
+{
+	unsigned short mode;
+	enum object_type object_type;
+	return get_tree_entry_all(r, tree_oid, name, oid,
+				  &mode, &object_type);
+}
+
 int get_tree_entry_mode(struct repository *r,
 			const struct object_id *tree_oid,
 			const char *name,
diff --git a/tree-walk.h b/tree-walk.h
index 55ef88ef2e5..efcd7ccd10e 100644
--- a/tree-walk.h
+++ b/tree-walk.h
@@ -193,10 +193,13 @@ struct traverse_info {
  * "struct name_entry" you'd like. You always need a pointer to an
  * appropriate variable to fill in (NULL won't do!):
  *
+ * get_tree_entry_path(): <no extra argument, just get the common 'path'>
  * get_tree_entry_mode(): unsigned int mode
  * get_tree_entry_type(): enum object_type
  * get_tree_entry_all(): unsigned int mode, enum object_type
  */
+int get_tree_entry_path(struct repository *, const struct object_id *, const char *,
+			struct object_id *);
 int get_tree_entry_mode(struct repository *, const struct object_id *, const char *,
 			struct object_id *,
 			unsigned short *);
-- 
2.31.0.rc2.211.g1d0b8788b3


^ permalink raw reply	[flat|nested] 262+ messages in thread

* [PATCH v2 28/29] blame: emit a better error on 'git blame directory'
  2021-03-08 15:06     ` [PATCH 00/30] tree-walk: mostly "mode" to "enum object_type" Ævar Arnfjörð Bjarmason
                         ` (29 preceding siblings ...)
  2021-03-16  2:13       ` [PATCH v2 27/29] tree-walk.h API: add a get_tree_entry_path() function Ævar Arnfjörð Bjarmason
@ 2021-03-16  2:13       ` Ævar Arnfjörð Bjarmason
  2021-03-16  6:55         ` Elijah Newren
  2021-03-16  2:13       ` [PATCH v2 29/29] tree-walk.h API: add a tree_entry_extract_type() function Ævar Arnfjörð Bjarmason
  31 siblings, 1 reply; 262+ messages in thread
From: Ævar Arnfjörð Bjarmason @ 2021-03-16  2:13 UTC (permalink / raw)
  To: git
  Cc: Junio C Hamano, Elijah Newren, Kirill Smelkov,
	Nguyễn Thái Ngọc Duy,
	Ævar Arnfjörð Bjarmason

Change an early check for non-blobs in verify_working_tree_path() to
let any such objects pass, and instead die shortly thereafter in the
fake_working_tree_commit() caller's type check.

Now e.g. doing "git blame t" in git.git emits:

    fatal: unsupported file type t

Instead of:

    fatal: no such path 't' in HEAD

Signed-off-by: Ævar Arnfjörð Bjarmason <avarab@gmail.com>
---
 blame.c                         |  8 ++------
 t/t8004-blame-with-conflicts.sh | 20 ++++++++++++++++++++
 2 files changed, 22 insertions(+), 6 deletions(-)

diff --git a/blame.c b/blame.c
index 9e0543e13d4..7da162cd582 100644
--- a/blame.c
+++ b/blame.c
@@ -100,12 +100,8 @@ static void verify_working_tree_path(struct repository *r,
 
 	for (parents = work_tree->parents; parents; parents = parents->next) {
 		const struct object_id *commit_oid = &parents->item->obje