git.vger.kernel.org archive mirror
 help / color / mirror / 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 related	[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 related	[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 related	[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 related	[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 related	[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 related	[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 related	[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 related	[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 related	[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 related	[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 related	[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 related	[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 related	[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 related	[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 related	[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 related	[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 related	[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 related	[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 related	[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 related	[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 related	[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 related	[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 related	[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 related	[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 related	[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 related	[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 related	[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 related	[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 related	[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 related	[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 related	[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 related	[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 related	[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 related	[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 related	[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 related	[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 related	[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 related	[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 related	[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 related	[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 related	[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 related	[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 related	[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 related	[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 related	[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 related	[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 related	[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 related	[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 related	[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 related	[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 related	[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 related	[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 related	[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 related	[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 related	[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 related	[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 related	[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 related	[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 related	[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 related	[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 related	[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 related	[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 related	[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 related	[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 related	[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 related	[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 related	[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 related	[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 related	[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 related	[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 related	[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 related	[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 related	[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 related	[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 related	[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 related	[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 related	[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 related	[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 related	[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 related	[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->object.oid;
-		struct object_id blob_oid;
-		unsigned short 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)
+		struct object_id oid;
+		if (!get_tree_entry_path(r, commit_oid, path, &oid))
 			return;
 	}
 
diff --git a/t/t8004-blame-with-conflicts.sh b/t/t8004-blame-with-conflicts.sh
index 35414a53363..6caa504a0ea 100755
--- a/t/t8004-blame-with-conflicts.sh
+++ b/t/t8004-blame-with-conflicts.sh
@@ -73,4 +73,24 @@ test_expect_success 'blame does not crash with conflicted file in stages 1,3' '
 	git blame file1
 '
 
+test_expect_success 'setup second case' '
+	git merge --abort
+'
+
+test_expect_success 'blame on directory/file conflict' '
+	mkdir d &&
+	test_commit second &&
+	test_commit d/file &&
+	test_must_fail git blame d 2>expected &&
+
+	git reset --hard second &&
+	>d &&
+	git add d &&
+	git commit -m"a not-a-dir" &&
+	test_must_fail git merge d/file &&
+
+	test_must_fail git blame d 2>actual &&
+	test_cmp expected actual
+'
+
 test_done
-- 
2.31.0.rc2.211.g1d0b8788b3


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

* [PATCH v2 29/29] tree-walk.h API: add a tree_entry_extract_type() function
  2021-03-08 15:06     ` [PATCH 00/30] tree-walk: mostly "mode" to "enum object_type" Ævar Arnfjörð Bjarmason
                         ` (30 preceding siblings ...)
  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       ` Ævar Arnfjörð Bjarmason
  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 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 25bfb46fb02..89109659aa3 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 918ad95fa61..8409374f0ba 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 efcd7ccd10e..f5102ed5427 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.rc2.211.g1d0b8788b3


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

* Re: [PATCH v3 8/9] show tests: add test for "git show <tree>"
  2021-03-15 23:43     ` [PATCH v3 8/9] show tests: add test for "git show <tree>" Ævar Arnfjörð Bjarmason
@ 2021-03-16  5:19       ` Elijah Newren
  0 siblings, 0 replies; 262+ messages in thread
From: Elijah Newren @ 2021-03-16  5:19 UTC (permalink / raw)
  To: Ævar Arnfjörð Bjarmason
  Cc: Git Mailing List, Junio C Hamano, Derrick Stolee

On Mon, Mar 15, 2021 at 4:44 PM Ævar Arnfjörð Bjarmason
<avarab@gmail.com> wrote:
>
> 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 &&

I had used COMMIT:PATH syntax before, but I was unaware PATH could be
empty to refer to the toplevel tree.

Still, it seems main1^{tree} might be a bit clearer?

> +       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 &&

a/file: was really confusing to me.  Perhaps I should have
known/remembered that a/file was both a filename and a tagname (I
dislike that part of test_commit), and you are just using that tag but
I had to fetch your changes and run them and play around to figure out
what was going on here.

Can we just use "HEAD^{tree}" instead of "a/file:" ?

> +       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

* Re: [PATCH v3 0/9] read_tree() and read_tree_recursive() refactoring
  2021-03-15 23:43     ` [PATCH v3 0/9] read_tree() and read_tree_recursive() refactoring Ævar Arnfjörð Bjarmason
@ 2021-03-16  5:37       ` Elijah Newren
  2021-03-16 15:52       ` [PATCH v4 " Ævar Arnfjörð Bjarmason
                         ` (10 subsequent siblings)
  11 siblings, 0 replies; 262+ messages in thread
From: Elijah Newren @ 2021-03-16  5:37 UTC (permalink / raw)
  To: Ævar Arnfjörð Bjarmason
  Cc: Git Mailing List, Junio C Hamano, Derrick Stolee

On Mon, Mar 15, 2021 at 4:44 PM Ævar Arnfjörð Bjarmason
<avarab@gmail.com> wrote:
>
> 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/

Patch 8/9 was a bit harder for me to read; I'm not sure if that means
the patch needs improvement or just reflects a personal failing.  :-)
But ultimately, it's minor and the rest of the series looks good.
With or without a few tweaks to that patch:

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

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

* Re: [PATCH v2 06/29] cache.h: have base_name_compare() take "is tree?", not "mode"
  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  5:49         ` Elijah Newren
  0 siblings, 0 replies; 262+ messages in thread
From: Elijah Newren @ 2021-03-16  5:49 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 15, 2021 at 7:13 PM Æ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);
>  }

Um...these last two hunks have not changed since the last round.  They
introduce a nasty bug, as mentioned in my review last time and
highlighted in my response on the cover letter.  They need to be
fixed, and more testcases verifying their correct operation should be
added.

This is the kind of thing that makes me really scared about these
refactorings; it's too easy to introduce changes that will write
semi-broken objects in the wild, which we will then have to deal with
for the rest of forever.

>  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

The isdir -> istree updates are nice; thanks.

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

* Re: [PATCH v2 21/29] tree-walk.h API users: use "tmp" for mode in shift_tree_by()
  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  6:34         ` Elijah Newren
  0 siblings, 0 replies; 262+ messages in thread
From: Elijah Newren @ 2021-03-16  6:34 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 15, 2021 at 7:13 PM Ævar Arnfjörð Bjarmason
<avarab@gmail.com> wrote:

As with the previous round, why do you have the subject as "tree-walk:
..." instead of "match-trees: ..." ?

>
> 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

* Re: [PATCH v2 27/29] tree-walk.h API: add a get_tree_entry_path() function
  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  6:50         ` Elijah Newren
  0 siblings, 0 replies; 262+ messages in thread
From: Elijah Newren @ 2021-03-16  6:50 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 15, 2021 at 7:13 PM Æ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.

As with the previous round, this paragraph does not parse well.  My
suggestion on the last round was:

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.

you don't have to take it, but the paragraph needs rewording one way or another.

>
> 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

* Re: [PATCH v2 28/29] blame: emit a better error on 'git blame directory'
  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  6:55         ` Elijah Newren
  0 siblings, 0 replies; 262+ messages in thread
From: Elijah Newren @ 2021-03-16  6:55 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 15, 2021 at 7:13 PM Ævar Arnfjörð Bjarmason
<avarab@gmail.com> wrote:
>
> 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->object.oid;
> -               struct object_id blob_oid;
> -               unsigned short 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)
> +               struct object_id oid;
> +               if (!get_tree_entry_path(r, commit_oid, path, &oid))
>                         return;
>         }
>
> diff --git a/t/t8004-blame-with-conflicts.sh b/t/t8004-blame-with-conflicts.sh
> index 35414a53363..6caa504a0ea 100755
> --- a/t/t8004-blame-with-conflicts.sh
> +++ b/t/t8004-blame-with-conflicts.sh
> @@ -73,4 +73,24 @@ test_expect_success 'blame does not crash with conflicted file in stages 1,3' '
>         git blame file1
>  '
>
> +test_expect_success 'setup second case' '
> +       git merge --abort
> +'
> +
> +test_expect_success 'blame on directory/file conflict' '
> +       mkdir d &&
> +       test_commit second &&
> +       test_commit d/file &&
> +       test_must_fail git blame d 2>expected &&
> +
> +       git reset --hard second &&
> +       >d &&
> +       git add d &&
> +       git commit -m"a not-a-dir" &&
> +       test_must_fail git merge d/file &&
> +
> +       test_must_fail git blame d 2>actual &&
> +       test_cmp expected actual
> +'
> +
>  test_done

Given that the commit message says the change was about modifying the
error message shown, why does the new test not check for the error
message?

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

* Re: [PATCH v2 00/29] tree-walk: mostly replace "mode" with "enum object_type"
  2021-03-16  2:12       ` [PATCH v2 00/29] tree-walk: mostly replace "mode" with " Ævar Arnfjörð Bjarmason
@ 2021-03-16  7:04         ` Elijah Newren
  2021-03-16  8:30           ` Ævar Arnfjörð Bjarmason
  2021-03-16 15:57         ` [PATCH v3 00/32] " Ævar Arnfjörð Bjarmason
                           ` (32 subsequent siblings)
  33 siblings, 1 reply; 262+ messages in thread
From: Elijah Newren @ 2021-03-16  7: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 15, 2021 at 7:13 PM Ævar Arnfjörð Bjarmason
<avarab@gmail.com> wrote:
>
> 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.

Splitting those trickier bits off makes sense.

This series looks really good and addresses most of my feedback from
v1.  There were two commit message wording comments in patches 21 and
27 leftover from the previous round, and a nasty bug introduced in
patch 6 still left from the previous round.

I also had a question on the new testcase in patch 28.

Other than that, though, the series looks good to me.

>
> Æ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

* Re: [PATCH v2 00/29] tree-walk: mostly replace "mode" with "enum object_type"
  2021-03-16  7:04         ` Elijah Newren
@ 2021-03-16  8:30           ` Ævar Arnfjörð Bjarmason
  0 siblings, 0 replies; 262+ messages in thread
From: Ævar Arnfjörð Bjarmason @ 2021-03-16  8:30 UTC (permalink / raw)
  To: Elijah Newren
  Cc: Git Mailing List, Junio C Hamano, Kirill Smelkov,
	Nguyễn Thái Ngọc Duy


On Tue, Mar 16 2021, Elijah Newren wrote:

> On Mon, Mar 15, 2021 at 7:13 PM Ævar Arnfjörð Bjarmason
> <avarab@gmail.com> wrote:
>>
>> 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.
>
> Splitting those trickier bits off makes sense.
>
> This series looks really good and addresses most of my feedback from
> v1.  There were two commit message wording comments in patches 21 and
> 27 leftover from the previous round, and a nasty bug introduced in
> patch 6 still left from the previous round.
>
> I also had a question on the new testcase in patch 28.
>
> Other than that, though, the series looks good to me.

Sorry about that, and thanks for spotting those.

For what it's worth I *did* actually address all your feedback from the
last round and would have prominently noted if I'd left the issue you
noted in v1's 6/30 in v2.

The problem is that version never made it out of my local tree.

I was rebasing this in multiple passes, and I think the immediate
culprit is that I've recently aliased "git commit --amend" to "git ca"
and "git rebase --continue" as "git rc" as a UI experiment.

I then managed to mix the two up, so I aborted during the middle of one
of my rebase passes, then when I came back to the computer managed to
forget what state I should be in, knowing I'd dealt with 06/30 already
etc., and happily continued.

And then in trying to re-remember how to massage git-format-patch to
apply the correct range-diff invocation option I managed to miss that
before sending it out.

Anyway. I'm just noting the details of that local screwup I think it's
important to accurately summarize changes from the last iteration in CL
or patches when getting feedback like that.

I'll go over your v1+v2 feedback again and submit a v3 soon. It's taking
me a bit longer than I'd have wanted because of course Murphy's law
dictates that the first thing I got in my git.git this morning was a
warning about too many loose objects, and before having read my E-Mail I
thought "do I have anything outstanding but un-referenced?", "no!", and
ran "git gc --prune=now".

>>
>> Æ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 v4 0/9] read_tree() and read_tree_recursive() refactoring
  2021-03-15 23:43     ` [PATCH v3 0/9] read_tree() and read_tree_recursive() refactoring Ævar Arnfjörð Bjarmason
  2021-03-16  5:37       ` Elijah Newren
@ 2021-03-16 15:52       ` Ævar Arnfjörð Bjarmason
  2021-03-16 15:52       ` [PATCH v4 1/9] ls-files tests: add meaningful --with-tree tests Ævar Arnfjörð Bjarmason
                         ` (9 subsequent siblings)
  11 siblings, 0 replies; 262+ messages in thread
From: Ævar Arnfjörð Bjarmason @ 2021-03-16 15:52 UTC (permalink / raw)
  To: git
  Cc: Junio C Hamano, Elijah Newren, Derrick Stolee,
	Ævar Arnfjörð Bjarmason

The only changes since v3[1] is a fix for a small test nit by
Elijah[2].

1. https://lore.kernel.org/git/20210315234344.28427-1-avarab@gmail.com/
2. https://lore.kernel.org/git/CABPp-BHWDffkqXsisp9E-FJPR4PmByPWuxWkAir24WpqUu43Lg@mail.gmail.com/

Æ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:  b338f2c01a ls-files tests: add meaningful --with-tree tests
 -:  ---------- >  2:  4578b83944 tree.c API: move read_tree() into builtin/ls-files.c
 -:  ---------- >  3:  33656ff63b ls-files: don't needlessly pass around stage variable
 -:  ---------- >  4:  1c96d5d361 ls-files: refactor away read_tree()
 -:  ---------- >  5:  367cb99224 tree.h API: remove support for starting at prefix != ""
 -:  ---------- >  6:  38e36780e2 tree.h API: remove "stage" parameter from read_tree_recursive()
 -:  ---------- >  7:  859902ffd8 tree.h API: rename read_tree_recursive() to read_tree()
 1:  a63c9b49f1 !  8:  8a6bebde23 show tests: add test for "git show <tree>"
    @@ t/t7007-show.sh: test_expect_success 'showing two commits' '
     +
     +test_expect_success 'showing two trees' '
     +	cat >expected <<-EOF &&
    -+	tree main1:
    ++	tree main1^{tree}
     +
     +	main1.t
     +
    -+	tree main2:
    ++	tree main2^{tree}
     +
     +	main1.t
     +	main2.t
     +	EOF
    -+	git show main1: main2: >actual &&
    ++	git show main1^{tree} main2^{tree} >actual &&
     +	test_cmp expected actual
     +'
     +
    @@ t/t7007-show.sh: test_expect_success 'showing two commits' '
     +	mkdir not-recursive/a &&
     +	test_commit -C not-recursive a/file &&
     +	cat >expected <<-EOF &&
    -+	tree a/file:
    ++	tree HEAD^{tree}
     +
     +	a/
     +	main1.t
     +	EOF
    -+	git -C not-recursive show a/file: >actual &&
    ++	git -C not-recursive show HEAD^{tree} >actual &&
     +	test_cmp expected actual
     +'
     +
 2:  570642c862 =  9:  29996dd82b tree.h API: expose read_tree_1() as read_tree_at()
-- 
2.31.0.256.gf0ddda3145


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

* [PATCH v4 1/9] ls-files tests: add meaningful --with-tree tests
  2021-03-15 23:43     ` [PATCH v3 0/9] read_tree() and read_tree_recursive() refactoring Ævar Arnfjörð Bjarmason
  2021-03-16  5:37       ` Elijah Newren
  2021-03-16 15:52       ` [PATCH v4 " Ævar Arnfjörð Bjarmason
@ 2021-03-16 15:52       ` Ævar Arnfjörð Bjarmason
  2021-03-16 15:52       ` [PATCH v4 2/9] tree.c API: move read_tree() into builtin/ls-files.c Ævar Arnfjörð Bjarmason
                         ` (8 subsequent siblings)
  11 siblings, 0 replies; 262+ messages in thread
From: Ævar Arnfjörð Bjarmason @ 2021-03-16 15:52 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 52ed665fcd..b257c792a4 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.256.gf0ddda3145


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

* [PATCH v4 2/9] tree.c API: move read_tree() into builtin/ls-files.c
  2021-03-15 23:43     ` [PATCH v3 0/9] read_tree() and read_tree_recursive() refactoring Ævar Arnfjörð Bjarmason
                         ` (2 preceding siblings ...)
  2021-03-16 15:52       ` [PATCH v4 1/9] ls-files tests: add meaningful --with-tree tests Ævar Arnfjörð Bjarmason
@ 2021-03-16 15:52       ` Ævar Arnfjörð Bjarmason
  2021-03-16 15:52       ` [PATCH v4 3/9] ls-files: don't needlessly pass around stage variable Ævar Arnfjörð Bjarmason
                         ` (7 subsequent siblings)
  11 siblings, 0 replies; 262+ messages in thread
From: Ævar Arnfjörð Bjarmason @ 2021-03-16 15:52 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 f6f9e483b2..a445862281 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 6fda8091f1..c2f8a8eadf 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 a52479812c..a6c12f2745 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 3eb0484cbf..6b0b1dc211 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.256.gf0ddda3145


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

* [PATCH v4 3/9] ls-files: don't needlessly pass around stage variable
  2021-03-15 23:43     ` [PATCH v3 0/9] read_tree() and read_tree_recursive() refactoring Ævar Arnfjörð Bjarmason
                         ` (3 preceding siblings ...)
  2021-03-16 15:52       ` [PATCH v4 2/9] tree.c API: move read_tree() into builtin/ls-files.c Ævar Arnfjörð Bjarmason
@ 2021-03-16 15:52       ` Ævar Arnfjörð Bjarmason
  2021-03-16 15:52       ` [PATCH v4 4/9] ls-files: refactor away read_tree() Ævar Arnfjörð Bjarmason
                         ` (6 subsequent siblings)
  11 siblings, 0 replies; 262+ messages in thread
From: Ævar Arnfjörð Bjarmason @ 2021-03-16 15:52 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 a445862281..74d572a3e4 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.256.gf0ddda3145


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

* [PATCH v4 4/9] ls-files: refactor away read_tree()
  2021-03-15 23:43     ` [PATCH v3 0/9] read_tree() and read_tree_recursive() refactoring Ævar Arnfjörð Bjarmason
                         ` (4 preceding siblings ...)
  2021-03-16 15:52       ` [PATCH v4 3/9] ls-files: don't needlessly pass around stage variable Ævar Arnfjörð Bjarmason
@ 2021-03-16 15:52       ` Ævar Arnfjörð Bjarmason
  2021-03-16 15:52       ` [PATCH v4 5/9] tree.h API: remove support for starting at prefix != "" Ævar Arnfjörð Bjarmason
                         ` (5 subsequent siblings)
  11 siblings, 0 replies; 262+ messages in thread
From: Ævar Arnfjörð Bjarmason @ 2021-03-16 15:52 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 74d572a3e4..db53e2c8e6 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.256.gf0ddda3145


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

* [PATCH v4 5/9] tree.h API: remove support for starting at prefix != ""
  2021-03-15 23:43     ` [PATCH v3 0/9] read_tree() and read_tree_recursive() refactoring Ævar Arnfjörð Bjarmason
                         ` (5 preceding siblings ...)
  2021-03-16 15:52       ` [PATCH v4 4/9] ls-files: refactor away read_tree() Ævar Arnfjörð Bjarmason
@ 2021-03-16 15:52       ` Ævar Arnfjörð Bjarmason
  2021-03-16 15:52       ` [PATCH v4 6/9] tree.h API: remove "stage" parameter from read_tree_recursive() Ævar Arnfjörð Bjarmason
                         ` (4 subsequent siblings)
  11 siblings, 0 replies; 262+ messages in thread
From: Ævar Arnfjörð Bjarmason @ 2021-03-16 15:52 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 5919d9e505..9394f170f7 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 2d6550bc3c..21b742c0f0 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 f67b67d80e..ffa3fb8c28 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 db53e2c8e6..cd432ac03c 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 7cad3f24eb..7d3fb2e6d0 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 b052974f19..fa7602ff0f 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 a6c12f2745..04eb11aed3 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 6b0b1dc211..5252b5139d 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.256.gf0ddda3145


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

* [PATCH v4 6/9] tree.h API: remove "stage" parameter from read_tree_recursive()
  2021-03-15 23:43     ` [PATCH v3 0/9] read_tree() and read_tree_recursive() refactoring Ævar Arnfjörð Bjarmason
                         ` (6 preceding siblings ...)
  2021-03-16 15:52       ` [PATCH v4 5/9] tree.h API: remove support for starting at prefix != "" Ævar Arnfjörð Bjarmason
@ 2021-03-16 15:52       ` Ævar Arnfjörð Bjarmason
  2021-03-16 15:52       ` [PATCH v4 7/9] tree.h API: rename read_tree_recursive() to read_tree() Ævar Arnfjörð Bjarmason
                         ` (3 subsequent siblings)
  11 siblings, 0 replies; 262+ messages in thread
From: Ævar Arnfjörð Bjarmason @ 2021-03-16 15:52 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 9394f170f7..6669a4bd14 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 21b742c0f0..2c2d58a230 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 ffa3fb8c28..58acb2b76a 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 cd432ac03c..fa9b01b6cc 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 7d3fb2e6d0..dbb31217be 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 fa7602ff0f..1593f37449 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 04eb11aed3..fb4985f22c 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 5252b5139d..1309ab997e 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.256.gf0ddda3145


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

* [PATCH v4 7/9] tree.h API: rename read_tree_recursive() to read_tree()
  2021-03-15 23:43     ` [PATCH v3 0/9] read_tree() and read_tree_recursive() refactoring Ævar Arnfjörð Bjarmason
                         ` (7 preceding siblings ...)
  2021-03-16 15:52       ` [PATCH v4 6/9] tree.h API: remove "stage" parameter from read_tree_recursive() Ævar Arnfjörð Bjarmason
@ 2021-03-16 15:52       ` Ævar Arnfjörð Bjarmason
  2021-03-16 15:52       ` [PATCH v4 8/9] show tests: add test for "git show <tree>" Ævar Arnfjörð Bjarmason
                         ` (2 subsequent siblings)
  11 siblings, 0 replies; 262+ messages in thread
From: Ævar Arnfjörð Bjarmason @ 2021-03-16 15:52 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 6669a4bd14..c19300ecb9 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 2c2d58a230..0e66390520 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 58acb2b76a..980de59063 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 fa9b01b6cc..13bcc2d847 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 dbb31217be..3a442631c7 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 1593f37449..3d9207455b 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 fb4985f22c..f6de250d7f 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 1309ab997e..4fb713774a 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.256.gf0ddda3145


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

* [PATCH v4 8/9] show tests: add test for "git show <tree>"
  2021-03-15 23:43     ` [PATCH v3 0/9] read_tree() and read_tree_recursive() refactoring Ævar Arnfjörð Bjarmason
                         ` (8 preceding siblings ...)
  2021-03-16 15:52       ` [PATCH v4 7/9] tree.h API: rename read_tree_recursive() to read_tree() Ævar Arnfjörð Bjarmason
@ 2021-03-16 15:52       ` Ævar Arnfjörð Bjarmason
  2021-03-16 15:52       ` [PATCH v4 9/9] tree.h API: expose read_tree_1() as read_tree_at() Ævar Arnfjörð Bjarmason
  2021-03-17 17:38       ` [PATCH v3 0/9] read_tree() and read_tree_recursive() refactoring Junio C Hamano
  11 siblings, 0 replies; 262+ messages in thread
From: Ævar Arnfjörð Bjarmason @ 2021-03-16 15:52 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 42d3db6246..d6cc69e0f2 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^{tree}
+
+	main1.t
+
+	tree main2^{tree}
+
+	main1.t
+	main2.t
+	EOF
+	git show main1^{tree} main2^{tree} >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 HEAD^{tree}
+
+	a/
+	main1.t
+	EOF
+	git -C not-recursive show HEAD^{tree} >actual &&
+	test_cmp expected actual
+'
+
 test_expect_success 'showing a range walks (linear)' '
 	cat >expect <<-EOF &&
 	commit $(git rev-parse main3)
-- 
2.31.0.256.gf0ddda3145


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

* [PATCH v4 9/9] tree.h API: expose read_tree_1() as read_tree_at()
  2021-03-15 23:43     ` [PATCH v3 0/9] read_tree() and read_tree_recursive() refactoring Ævar Arnfjörð Bjarmason
                         ` (9 preceding siblings ...)
  2021-03-16 15:52       ` [PATCH v4 8/9] show tests: add test for "git show <tree>" Ævar Arnfjörð Bjarmason
@ 2021-03-16 15:52       ` Ævar Arnfjörð Bjarmason
  2021-03-17 17:38       ` [PATCH v3 0/9] read_tree() and read_tree_recursive() refactoring Junio C Hamano
  11 siblings, 0 replies; 262+ messages in thread
From: Ævar Arnfjörð Bjarmason @ 2021-03-16 15:52 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 f6de250d7f..6a2a52967e 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 4fb713774a..f0b079d2e9 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.256.gf0ddda3145


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

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

The v2 of this series was broken as noted in
https://lore.kernel.org/git/87blbjfqkh.fsf@evledraar.gmail.com/

Here's a fixed version. This should actually address all of Elijah's
comments on v1 + v2.

It's up to 32 patches because I added some tests for the
mostly-never-been-tested code being changed in 09/32.

Ævar Arnfjörð Bjarmason (32):
  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
  fast-import tests: test for sorting dir/file foo v.s. foo.txt
  mktree tests: test that "mode" is passed when sorting
  diff tests: test that "mode" is passed when sorting
  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()
  match-trees: 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           | 12 +++--
 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/t1450-fsck.sh                 | 66 ++++++++++++++++++++++++
 t/t4300-merge-tree.sh           | 44 ++++++++++++++++
 t/t8004-blame-with-conflicts.sh | 21 ++++++++
 t/t9300-fast-import.sh          | 87 ++++++++++++++++++++++++++++++++
 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 ++++----
 42 files changed, 618 insertions(+), 244 deletions(-)

Range-diff:
 1:  f9bbc30f69 =  1:  26bc38fbdd diff.c: remove redundant canon_mode() call
 2:  187fc2c3e6 =  2:  8502cf8134 notes & match-trees: use name_entry's "pathlen" member
 3:  311637c558 =  3:  68133fa6aa cache.h: add a comment to object_type()
 4:  fecfe3d462 =  4:  9f714d6c01 tree-walk.h: add object_type member to name_entry
 5:  db961ab5e8 =  5:  6dbf2b0a6a tree-walk.c: migrate to using new "object_type" field when possible
 -:  ---------- >  6:  354a8e9a2a fast-import tests: test for sorting dir/file foo v.s. foo.txt
 -:  ---------- >  7:  e2331df28e mktree tests: test that "mode" is passed when sorting
 -:  ---------- >  8:  9e9486c2ea diff tests: test that "mode" is passed when sorting
 6:  df2fc76161 !  9:  be5c713336 cache.h: have base_name_compare() take "is tree?", not "mode"
    @@ Commit message
         958ba6c96eb (Introduce "base_name_compare()" helper function,
         2005-05-20).
     
    +    None of these comparison functions used to have tests, but with
    +    preceding commits some of them now do. I thought the remainder was
    +    trivial enough to review without tests, and didn't want to spend more
    +    time on them.
    +
         Signed-off-by: Ævar Arnfjörð Bjarmason <avarab@gmail.com>
     
      ## builtin/fast-import.c ##
     @@ builtin/fast-import.c: 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);
    ++	int istree_a = S_ISDIR(a->versions[0].mode);
    ++	int istree_b = S_ISDIR(b->versions[0].mode);
      	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);
    ++		a->name->str_dat, a->name->str_len, istree_a,
    ++		b->name->str_dat, b->name->str_len, istree_b);
      }
      
      static int tecmp1 (const void *_a, const void *_b)
    -@@ builtin/fast-import.c: 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);
    ++	int istree_a = S_ISDIR(a->versions[1].mode);
    ++	int istree_b = S_ISDIR(b->versions[1].mode);
      	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);
    ++		a->name->str_dat, a->name->str_len, istree_a,
    ++		b->name->str_dat, b->name->str_len, istree_b);
      }
      
      static void mktree(struct tree_content *t, int v, struct strbuf *b)
 7:  49d5da8c08 = 10:  43623edddf tree-walk.h users: switch object_type(...) to new .object_type
 8:  c9d209d496 = 11:  030898f884 tree.h: format argument lists of read_tree_recursive() users
 9:  a6d2660fe1 = 12:  0ce197950b tree.h users: format argument lists in archive.c
10:  15f7f89acc = 13:  051c9f32ac archive: get rid of 'stage' parameter
11:  7a71404ea3 = 14:  bc73994b4c tree.h API: make read_tree_fn_t take an "enum object_type"
12:  64dc9364ba = 15:  e2b0964228 tree-walk.h users: migrate "p->mode &&" pattern
13:  93ed3edbbd = 16:  29dbc4292e tree-walk.h users: refactor chained "mode" if/else into switch
14:  7aa48aa34c = 17:  ada6d05176 tree-walk.h users: migrate miscellaneous "mode" to "object_type"
15:  3ae81621dc = 18:  01860daa55 merge-tree tests: test for the mode comparison in same_entry()
16:  4249ad5c4d = 19:  e4be48fb50 merge-ort: correct reference to test in 62fdec17a11
17:  e5e17505dd = 20:  189d2550fb fsck.c: switch on "object_type" in fsck_walk_tree()
18:  3f0b884f1f = 21:  3b7b12e6f7 tree-walk.h users: use temporary variable(s) for "mode"
19:  174167613b = 22:  6c3a07a327 tree-walk.h API: formatting changes for subsequent commit
20:  ec76db613f = 23:  879eb3da2a tree-walk.h API: rename get_tree_entry() to get_tree_entry_mode()
21:  11e3494172 ! 24:  d2fa360ab9 tree-walk.h API users: use "tmp" for mode in shift_tree_by()
    @@ Metadata
     Author: Ævar Arnfjörð Bjarmason <avarab@gmail.com>
     
      ## Commit message ##
    -    tree-walk.h API users: use "tmp" for mode in shift_tree_by()
    +    match-trees: use "tmp" for mode in shift_tree_by()
     
         Refactor code added in 85e51b783c3 (Make "subtree" part more
         orthogonal to the rest of merge-recursive., 2008-06-30) to make it
22:  b31c106557 = 25:  cc50cfcf51 tree-walk.h API: add get_tree_entry_type()
23:  304d5d4d1a = 26:  f642a35482 tree-walk.h API: document and format tree_entry_extract()
24:  346453df35 = 27:  a0bcb59fa5 tree-entry.h API: rename tree_entry_extract() to tree_entry_extract_mode()
25:  dd012b661e = 28:  c7d4ba7734 tree-walk.h API: add a tree_entry_extract_all() function
26:  b6ee8410e3 = 29:  1d5421d67a tree-walk.h API: add get_tree_entry_all()
27:  5c98afd9e7 ! 30:  a3e1063ac4 tree-walk.h API: add a get_tree_entry_path() function
    @@ Commit message
         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.
    +    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'.,
    +     - shift_tree(): 68faf68938e (A new merge stragety[sic] 'subtree'.,
             2007-02-15) for the shift_tree()
     
          - tree_has_path(): 96e7ffbdc31 (merge-recursive: check for directory
28:  3e7e0f7eb8 ! 31:  da3dd6dd53 blame: emit a better error on 'git blame directory'
    @@ Commit message
     
             fatal: no such path 't' in HEAD
     
    +    The main point of this test is to assert that we're not doing
    +    something uniquely bad when in a conflicted merge. See
    +    cd8ae20195 (git-blame shouldn't crash if run in an unmerged tree,
    +    2007-10-18) and 9aeaab6811 (blame: allow "blame file" in the middle of
    +    a conflicted merge, 2012-09-11) for the bug the t8004 test was
    +    originally meant to address.
    +
    +    But when extending it let's grep out the specific error message for
    +    good measure. Having to change it in the future (e.g. as part of my
    +    parallel series to improve such 'OID does not match type' messages) is
    +    a small price for ensuring it doesn't regress.
    +
         Signed-off-by: Ævar Arnfjörð Bjarmason <avarab@gmail.com>
     
      ## blame.c ##
    @@ t/t8004-blame-with-conflicts.sh: test_expect_success 'blame does not crash with
     +	test_commit second &&
     +	test_commit d/file &&
     +	test_must_fail git blame d 2>expected &&
    ++	grep "unsupported file type d" expected &&
     +
     +	git reset --hard second &&
     +	>d &&
29:  ac1ccf1357 = 32:  80e5cb0b30 tree-walk.h API: add a tree_entry_extract_type() function
-- 
2.31.0.256.gf0ddda3145


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

* [PATCH v3 01/32] diff.c: remove redundant canon_mode() call
  2021-03-16  2:12       ` [PATCH v2 00/29] tree-walk: mostly replace "mode" with " Ævar Arnfjörð Bjarmason
  2021-03-16  7:04         ` Elijah Newren
  2021-03-16 15:57         ` [PATCH v3 00/32] " Ævar Arnfjörð Bjarmason
@ 2021-03-16 15:57         ` Ævar Arnfjörð Bjarmason
  2021-03-16 15:57         ` [PATCH v3 02/32] notes & match-trees: use name_entry's "pathlen" member Ævar Arnfjörð Bjarmason
                           ` (30 subsequent siblings)
  33 siblings, 0 replies; 262+ messages in thread
From: Ævar Arnfjörð Bjarmason @ 2021-03-16 15:57 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 6956f5e335..bf46e6a4d8 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.256.gf0ddda3145


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

* [PATCH v3 02/32] notes & match-trees: use name_entry's "pathlen" member
  2021-03-16  2:12       ` [PATCH v2 00/29] tree-walk: mostly replace "mode" with " Ævar Arnfjörð Bjarmason
                           ` (2 preceding siblings ...)
  2021-03-16 15:57         ` [PATCH v3 01/32] diff.c: remove redundant canon_mode() call Ævar Arnfjörð Bjarmason
@ 2021-03-16 15:57         ` Ævar Arnfjörð Bjarmason
  2021-03-16 15:58         ` [PATCH v3 03/32] cache.h: add a comment to object_type() Ævar Arnfjörð Bjarmason
                           ` (29 subsequent siblings)
  33 siblings, 0 replies; 262+ messages in thread
From: Ævar Arnfjörð Bjarmason @ 2021-03-16 15:57 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 f6c194c1cc..1011357ad0 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 d5ac081e76..0a5b4fa1db 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.256.gf0ddda3145


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

* [PATCH v3 03/32] cache.h: add a comment to object_type()
  2021-03-16  2:12       ` [PATCH v2 00/29] tree-walk: mostly replace "mode" with " Ævar Arnfjörð Bjarmason
                           ` (3 preceding siblings ...)
  2021-03-16 15:57         ` [PATCH v3 02/32] notes & match-trees: use name_entry's "pathlen" member Ævar Arnfjörð Bjarmason
@ 2021-03-16 15:58         ` Ævar Arnfjörð Bjarmason
  2021-03-16 15:58         ` [PATCH v3 04/32] tree-walk.h: add object_type member to name_entry Ævar Arnfjörð Bjarmason
                           ` (28 subsequent siblings)
  33 siblings, 0 replies; 262+ messages in thread
From: Ævar Arnfjörð Bjarmason @ 2021-03-16 15:58 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 c2f8a8eadf..ae0c0bef5c 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.256.gf0ddda3145


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

* [PATCH v3 04/32] tree-walk.h: add object_type member to name_entry
  2021-03-16  2:12       ` [PATCH v2 00/29] tree-walk: mostly replace "mode" with " Ævar Arnfjörð Bjarmason
                           ` (4 preceding siblings ...)
  2021-03-16 15:58         ` [PATCH v3 03/32] cache.h: add a comment to object_type() Ævar Arnfjörð Bjarmason
@ 2021-03-16 15:58         ` Ævar Arnfjörð Bjarmason
  2021-03-16 15:58         ` [PATCH v3 05/32] tree-walk.c: migrate to using new "object_type" field when possible Ævar Arnfjörð Bjarmason
                           ` (27 subsequent siblings)
  33 siblings, 0 replies; 262+ messages in thread
From: Ævar Arnfjörð Bjarmason @ 2021-03-16 15:58 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 2d6226d5f1..b210967b73 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 a5058469e9..9f3825d277 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.256.gf0ddda3145


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

* [PATCH v3 05/32] tree-walk.c: migrate to using new "object_type" field when possible
  2021-03-16  2:12       ` [PATCH v2 00/29] tree-walk: mostly replace "mode" with " Ævar Arnfjörð Bjarmason
                           ` (5 preceding siblings ...)
  2021-03-16 15:58         ` [PATCH v3 04/32] tree-walk.h: add object_type member to name_entry Ævar Arnfjörð Bjarmason
@ 2021-03-16 15:58         ` Ævar Arnfjörð Bjarmason
  2021-03-16 15:58         ` [PATCH v3 06/32] fast-import tests: test for sorting dir/file foo v.s. foo.txt Ævar Arnfjörð Bjarmason
                           ` (26 subsequent siblings)
  33 siblings, 0 replies; 262+ messages in thread
From: Ævar Arnfjörð Bjarmason @ 2021-03-16 15:58 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 b210967b73..6e9161901d 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.256.gf0ddda3145


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

* [PATCH v3 06/32] fast-import tests: test for sorting dir/file foo v.s. foo.txt
  2021-03-16  2:12       ` [PATCH v2 00/29] tree-walk: mostly replace "mode" with " Ævar Arnfjörð Bjarmason
                           ` (6 preceding siblings ...)
  2021-03-16 15:58         ` [PATCH v3 05/32] tree-walk.c: migrate to using new "object_type" field when possible Ævar Arnfjörð Bjarmason
@ 2021-03-16 15:58         ` Ævar Arnfjörð Bjarmason
  2021-03-16 15:58         ` [PATCH v3 07/32] mktree tests: test that "mode" is passed when sorting Ævar Arnfjörð Bjarmason
                           ` (25 subsequent siblings)
  33 siblings, 0 replies; 262+ messages in thread
From: Ævar Arnfjörð Bjarmason @ 2021-03-16 15:58 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 missing test for the sorting of "foo" v.s. "foo.txt" where "foo"
can be either a file or a directory. If it's a file then "foo" should
sort before "foo.txt", and the other way around if "foo" is a
directory.

See [1] for a reply to a patch of mine introducing such a
regression. We now finally have a test for this code added back in
463acbe1c6 (Added tree and commit writing to fast-import.,
2006-08-14).

This tests both the tecmp1() and tecmp0() functions introduced inn
4cabf8583f (Implemented tree delta compression in fast-import.,
2006-08-28).

This will catch cases where the "mode" is the same, or reversed
between a & b in both functions.

There was an existing test for the tecmp1() function(s) just above
this one added here.

That existing test was added in e741130386 (New fast-import test case
for valid tree sorting, 2007-03-12) and would catch cases where
entries were reversed, but not if their mode (or rather, type) was the
the same or otherwise wrong value.

There were no tests at all for the tecmp0() function. As with the
tecmp1() test the new test will catch cases where the "mode" is the
same (e.g. "1"), or if the two are reversed. It won't catch a "return
0" from the function (i.e. already sorted), that case requires
tecmp1() to also be broken.

1. https://lore.kernel.org/git/CABPp-BEZfG_pNNTWsnxEa1xG+kgpQfpXj=KHBkCBAMikrXj-aA@mail.gmail.com/

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

diff --git a/t/t9300-fast-import.sh b/t/t9300-fast-import.sh
index 5c47ac4465..8bafb8cc51 100755
--- a/t/t9300-fast-import.sh
+++ b/t/t9300-fast-import.sh
@@ -955,6 +955,93 @@ test_expect_success 'L: verify internal tree sorting' '
 	test_cmp expect actual
 '
 
+test_expect_success 'L: verify internal tree sorting on bad input (tecmp1)' '
+	test_create_repo L1-0 &&
+
+	cat >input <<-INPUT_END &&
+	blob
+	mark :1
+	data 0
+
+	reset refs/heads/L1-0
+	commit refs/heads/L1-0
+	committer $GIT_COMMITTER_NAME <$GIT_COMMITTER_EMAIL> $GIT_COMMITTER_DATE
+	data <<COMMIT
+	create L1-0
+	COMMIT
+	M 100644 :1 x.txt
+	M 100644 :1 x/y.txt
+	M 100644 :1 z.txt
+	M 100644 :1 z
+	INPUT_END
+
+	cat >expected <<-EXPECT_END &&
+	x.txt
+	x
+	z
+	z.txt
+	EXPECT_END
+
+	git -C L1-0 fast-import <input &&
+	git -C L1-0 ls-tree L1-0 >tmp &&
+	cut -f 2 <tmp >actual &&
+	test_cmp expected actual &&
+	git -C L1-0 fsck 2>err &&
+	# Would happen if tecmp1() were broken
+	! grep "error in tree .*: treeNotSorted: " err
+'
+
+test_expect_success 'L: verify internal tree sorting on bad input (tecmp0)' '
+
+	test_create_repo L1-1 &&
+
+	cat >input <<-INPUT_END &&
+	blob
+	mark :1
+	data <<EOF
+	some data
+	EOF
+
+	reset refs/heads/L1-1
+	commit refs/heads/L1-1
+	committer $GIT_COMMITTER_NAME <$GIT_COMMITTER_EMAIL> $GIT_COMMITTER_DATE
+	data <<COMMIT
+	create L1-1
+	COMMIT
+	M 100644 :1 x.txt
+	M 100644 :1 x/y.txt
+	M 100644 :1 z.txt
+	M 100644 :1 z
+
+	commit refs/heads/L1-1
+	committer $GIT_COMMITTER_NAME <$GIT_COMMITTER_EMAIL> $GIT_COMMITTER_DATE
+	data <<COMMIT
+	update L1-1
+	COMMIT
+	M 100644 :1 another.txt
+	M 100644 :1 x.txt
+	M 100644 :1 x/y.txt
+	M 100644 :1 z.txt
+	M 100644 :1 z
+	INPUT_END
+
+	cat >expected <<-EXPECT_END &&
+	another.txt
+	x.txt
+	x
+	z
+	z.txt
+	EXPECT_END
+
+	git -C L1-1 fast-import <input &&
+	git -C L1-1 ls-tree L1-1 >tmp 2>err &&
+	# Would happen if tecmp0() passed a fixed mode
+	! grep "fatal: not a tree object" err &&
+	cut -f 2 <tmp >actual &&
+	test_cmp expected actual &&
+	git -C L1-1 fsck
+'
+
 test_expect_success 'L: nested tree copy does not corrupt deltas' '
 	cat >input <<-INPUT_END &&
 	blob
-- 
2.31.0.256.gf0ddda3145


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

* [PATCH v3 07/32] mktree tests: test that "mode" is passed when sorting
  2021-03-16  2:12       ` [PATCH v2 00/29] tree-walk: mostly replace "mode" with " Ævar Arnfjörð Bjarmason
                           ` (7 preceding siblings ...)
  2021-03-16 15:58         ` [PATCH v3 06/32] fast-import tests: test for sorting dir/file foo v.s. foo.txt Ævar Arnfjörð Bjarmason
@ 2021-03-16 15:58         ` Ævar Arnfjörð Bjarmason
  2021-03-16 15:58         ` [PATCH v3 08/32] diff " Ævar Arnfjörð Bjarmason
                           ` (24 subsequent siblings)
  33 siblings, 0 replies; 262+ messages in thread
From: Ævar Arnfjörð Bjarmason @ 2021-03-16 15:58 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 for the mode being passed to ent_compare(). That code dates
back to 83f50539a9 (git-mktree: reverse of git-ls-tree., 2006-02-20)
and there's never been a test for that particular edge case. Now we
have one.

I don't see how anything could run into this in practice. In order for
that mode sorting to matter as a tiebreaker we need to have a
duplicate entry in the tree, i.e. two "foo" entries, one a blob and
one a tree. This asserts that if that happens we'll sort on the modes
we encounter in such an invalid entry, i.e. we expect the tree entry
before the blob.

As shown here we'd need to disable the fsck.duplicateEntries error to
get to the point of running "mktree", so I doubt anyone's pushing this
sort of data around.

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

diff --git a/t/t1450-fsck.sh b/t/t1450-fsck.sh
index 5071ac63a5..46125190b4 100755
--- a/t/t1450-fsck.sh
+++ b/t/t1450-fsck.sh
@@ -318,6 +318,50 @@ test_expect_success 'tree entry with type mismatch' '
 	test_i18ngrep ! "dangling blob" out
 '
 
+test_expect_success 'tree entry with duplicate type mismatching objects' '
+	test_create_repo duplicate-entry &&
+	(
+		cd duplicate-entry &&
+		blob="$(printf "foo" | git hash-object -w --stdin)" &&
+		tree="$(printf "100644 blob $blob\tfoo" | git mktree)" &&
+		commit="$(git commit-tree $tree -m "first commit")" &&
+		git cat-file commit $commit >good-commit &&
+
+		# First bad commit, wrong type, but in the right order
+		printf "40000 A\0$(echo $tree | hex2oct)" >broken-tree-A &&
+		printf "100644 A\0$(echo $blob | hex2oct)" >broken-tree-B &&
+		cat broken-tree-A broken-tree-B >broken-tree.1 &&
+		broken_tree1="$(git hash-object -w --literally -t tree broken-tree.1)" &&
+		bad_commit1="$(git commit-tree $broken_tree1 -m "bad commit 1")" &&
+		git cat-file commit $bad_commit1 >bad-commit.1 &&
+		git update-ref refs/heads/broken-commit-1 $bad_commit1 &&
+
+		test_must_fail git fsck &&
+		git -c fsck.duplicateEntries=warn fsck 2>err &&
+		grep " in tree .*$broken_tree1: duplicateEntries" err &&
+
+		# Second bad commits, wrong types and order
+		cat broken-tree-B broken-tree-A >broken-tree.2 &&
+		broken_tree2="$(git hash-object -w --literally -t tree broken-tree.2)" &&
+		bad_commit2="$(git commit-tree $broken_tree2 -m "bad commit 2")" &&
+		git cat-file commit $bad_commit2 >bad-commit.2 &&
+		git update-ref refs/heads/broken-commit-2 $bad_commit2 &&
+
+		test_must_fail git fsck &&
+		git -c fsck.duplicateEntries=warn fsck 2>err &&
+		grep " in tree .*$broken_tree2: duplicateEntries" err &&
+
+		# git mktree should "fix" the order of this already broken data
+		git ls-tree broken-commit-1 >broken-tree-1-ls &&
+		git ls-tree broken-commit-2 >broken-tree-2-ls &&
+		! test_cmp broken-tree-1-ls broken-tree-2-ls &&
+
+		git mktree <broken-tree-1-ls >broken-mktree-1 &&
+		git mktree <broken-tree-2-ls >broken-mktree-2 &&
+		test_cmp broken-mktree-1 broken-mktree-2
+	)
+'
+
 test_expect_success 'tag pointing to nonexistent' '
 	badoid=$(test_oid deadbeef) &&
 	cat >invalid-tag <<-EOF &&
-- 
2.31.0.256.gf0ddda3145


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

* [PATCH v3 08/32] diff tests: test that "mode" is passed when sorting
  2021-03-16  2:12       ` [PATCH v2 00/29] tree-walk: mostly replace "mode" with " Ævar Arnfjörð Bjarmason
                           ` (8 preceding siblings ...)
  2021-03-16 15:58         ` [PATCH v3 07/32] mktree tests: test that "mode" is passed when sorting Ævar Arnfjörð Bjarmason
@ 2021-03-16 15:58         ` Ævar Arnfjörð Bjarmason
  2021-03-16 15:58         ` [PATCH v3 09/32] cache.h: have base_name_compare() take "is tree?", not "mode" Ævar Arnfjörð Bjarmason
                           ` (23 subsequent siblings)
  33 siblings, 0 replies; 262+ messages in thread
From: Ævar Arnfjörð Bjarmason @ 2021-03-16 15:58 UTC (permalink / raw)
  To: git
  Cc: Junio C Hamano, Elijah Newren, Kirill Smelkov,
	Nguyễn Thái Ngọc Duy,
	Ævar Arnfjörð Bjarmason

Piggy-back on the recently added fsck tests for mode comparisons in
mktree and assert that diff-tree also does the right thing in this
implausible scenario.

As with the other tests I've added in preceding commits, these tests
will fail if the mode is the same or reversed, respectively.

The diff-tree code being tested here was originally added back in
.9174026cfe (Add "diff-tree" program to show which files have changed
between two trees., 2005-04-09).

Unlike the other tests I've added there are existing tests for both of
these scenarios. Breaking that function as described above will make
tests in t4002-diff-basic.sh, t6409-merge-subtree.sh and
t4037-diff-r-t-dirs.sh fail.

I think it's good to have tests for this regardless, so let's add
these.

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

diff --git a/t/t1450-fsck.sh b/t/t1450-fsck.sh
index 46125190b4..5dd842bb82 100755
--- a/t/t1450-fsck.sh
+++ b/t/t1450-fsck.sh
@@ -362,6 +362,28 @@ test_expect_success 'tree entry with duplicate type mismatching objects' '
 	)
 '
 
+test_expect_success 'diff-tree stressing tree-diff.c::tree_entry_pathcmp(), not the same type' '
+	zero=$(test_oid zero) &&
+	git -C duplicate-entry diff-tree broken-commit-1 broken-commit-2 >1-to-2 &&
+	grep "$zero" 1-to-2 >lines &&
+	test_line_count = 2 lines &&
+
+	git -C duplicate-entry diff-tree broken-commit-2 broken-commit-1 >2-to-1 &&
+	grep "$zero" 2-to-1 >lines &&
+	test_line_count = 2 lines
+'
+
+test_expect_success 'diff-tree stressing tree-diff.c::tree_entry_pathcmp(), types not reversed' '
+	blob_ok=$(git -C duplicate-entry rev-parse broken-commit-2:A) &&
+	git -C duplicate-entry diff-tree --diff-filter=A broken-commit-1 broken-commit-2 >1-to-2 &&
+	grep "$blob_ok" 1-to-2 &&
+	test_line_count = 1 1-to-2 &&
+
+	git -C duplicate-entry diff-tree --diff-filter=A broken-commit-2 broken-commit-1 >2-to-1 &&
+	grep "$blob_ok" 2-to-1 &&
+	test_line_count = 1 2-to-1
+'
+
 test_expect_success 'tag pointing to nonexistent' '
 	badoid=$(test_oid deadbeef) &&
 	cat >invalid-tag <<-EOF &&
-- 
2.31.0.256.gf0ddda3145


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

* [PATCH v3 09/32] cache.h: have base_name_compare() take "is tree?", not "mode"
  2021-03-16  2:12       ` [PATCH v2 00/29] tree-walk: mostly replace "mode" with " Ævar Arnfjörð Bjarmason
                           ` (9 preceding siblings ...)
  2021-03-16 15:58         ` [PATCH v3 08/32] diff " Ævar Arnfjörð Bjarmason
@ 2021-03-16 15:58         ` Ævar Arnfjörð Bjarmason
  2021-03-16 15:58         ` [PATCH v3 10/32] tree-walk.h users: switch object_type(...) to new .object_type Ævar Arnfjörð Bjarmason
                           ` (22 subsequent siblings)
  33 siblings, 0 replies; 262+ messages in thread
From: Ævar Arnfjörð Bjarmason @ 2021-03-16 15:58 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).

None of these comparison functions used to have tests, but with
preceding commits some of them now do. I thought the remainder was
trivial enough to review without tests, and didn't want to spend more
time on them.

Signed-off-by: Ævar Arnfjörð Bjarmason <avarab@gmail.com>
---
 builtin/fast-import.c | 12 ++++++++----
 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, 47 insertions(+), 35 deletions(-)

diff --git a/builtin/fast-import.c b/builtin/fast-import.c
index dd4d09cece..7a89510059 100644
--- a/builtin/fast-import.c
+++ b/builtin/fast-import.c
@@ -1287,18 +1287,22 @@ 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);
+	int istree_a = S_ISDIR(a->versions[0].mode);
+	int istree_b = S_ISDIR(b->versions[0].mode);
 	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, istree_a,
+		b->name->str_dat, b->name->str_len, istree_b);
 }
 
 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);
+	int istree_a = S_ISDIR(a->versions[1].mode);
+	int istree_b = S_ISDIR(b->versions[1].mode);
 	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, istree_a,
+		b->name->str_dat, b->name->str_len, istree_b);
 }
 
 static void mktree(struct tree_content *t, int v, struct strbuf *b)
diff --git a/builtin/mktree.c b/builtin/mktree.c
index 891991b00d..2c1973229a 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 ae0c0bef5c..e38b1e1688 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 9228aebc16..ad7058a6f5 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 1011357ad0..a28c19a62a 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 603d30c521..4075d13aaa 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 3d9207455b..1c9b08695a 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 1e9a50c6c7..4257fbd8a0 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 7cebbb327e..6ec180331f 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 eb8fcda31b..d9d573df98 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.256.gf0ddda3145


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

* [PATCH v3 10/32] tree-walk.h users: switch object_type(...) to new .object_type
  2021-03-16  2:12       ` [PATCH v2 00/29] tree-walk: mostly replace "mode" with " Ævar Arnfjörð Bjarmason
                           ` (10 preceding siblings ...)
  2021-03-16 15:58         ` [PATCH v3 09/32] cache.h: have base_name_compare() take "is tree?", not "mode" Ævar Arnfjörð Bjarmason
@ 2021-03-16 15:58         ` Ævar Arnfjörð Bjarmason
  2021-03-16 15:58         ` [PATCH v3 11/32] tree.h: format argument lists of read_tree_recursive() users Ævar Arnfjörð Bjarmason
                           ` (21 subsequent siblings)
  33 siblings, 0 replies; 262+ messages in thread
From: Ævar Arnfjörð Bjarmason @ 2021-03-16 15:58 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 6d62aaf59a..d3ba1d4a4a 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 6a4a43e07f..234b79a5db 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 88d9e696a5..ac32bf2242 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 b78733f508..1db4e4e90a 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.256.gf0ddda3145


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

* [PATCH v3 11/32] tree.h: format argument lists of read_tree_recursive() users
  2021-03-16  2:12       ` [PATCH v2 00/29] tree-walk: mostly replace "mode" with " Ævar Arnfjörð Bjarmason
                           ` (11 preceding siblings ...)
  2021-03-16 15:58         ` [PATCH v3 10/32] tree-walk.h users: switch object_type(...) to new .object_type Ævar Arnfjörð Bjarmason
@ 2021-03-16 15:58         ` Ævar Arnfjörð Bjarmason
  2021-03-16 15:58         ` [PATCH v3 12/32] tree.h users: format argument lists in archive.c Ævar Arnfjörð Bjarmason
                           ` (20 subsequent siblings)
  33 siblings, 0 replies; 262+ messages in thread
From: Ævar Arnfjörð Bjarmason @ 2021-03-16 15:58 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 c19300ecb9..77d1238df9 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 0e66390520..0887352db2 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 980de59063..b7b76856a9 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 3a442631c7..8d5c3fd058 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 1c9b08695a..689a3e0007 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 f0b079d2e9..c1a936fdc4 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.256.gf0ddda3145


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

* [PATCH v3 12/32] tree.h users: format argument lists in archive.c
  2021-03-16  2:12       ` [PATCH v2 00/29] tree-walk: mostly replace "mode" with " Ævar Arnfjörð Bjarmason
                           ` (12 preceding siblings ...)
  2021-03-16 15:58         ` [PATCH v3 11/32] tree.h: format argument lists of read_tree_recursive() users Ævar Arnfjörð Bjarmason
@ 2021-03-16 15:58         ` Ævar Arnfjörð Bjarmason
  2021-03-16 15:58         ` [PATCH v3 13/32] archive: get rid of 'stage' parameter Ævar Arnfjörð Bjarmason
                           ` (19 subsequent siblings)
  33 siblings, 0 replies; 262+ messages in thread
From: Ævar Arnfjörð Bjarmason @ 2021-03-16 15:58 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 77d1238df9..8ff97751c2 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.256.gf0ddda3145


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

* [PATCH v3 13/32] archive: get rid of 'stage' parameter
  2021-03-16  2:12       ` [PATCH v2 00/29] tree-walk: mostly replace "mode" with " Ævar Arnfjörð Bjarmason
                           ` (13 preceding siblings ...)
  2021-03-16 15:58         ` [PATCH v3 12/32] tree.h users: format argument lists in archive.c Ævar Arnfjörð Bjarmason
@ 2021-03-16 15:58         ` Ævar Arnfjörð Bjarmason
  2021-03-16 15:58         ` [PATCH v3 14/32] tree.h API: make read_tree_fn_t take an "enum object_type" Ævar Arnfjörð Bjarmason
                           ` (18 subsequent siblings)
  33 siblings, 0 replies; 262+ messages in thread
From: Ævar Arnfjörð Bjarmason @ 2021-03-16 15:58 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 8ff97751c2..529623167c 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.256.gf0ddda3145


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

* [PATCH v3 14/32] tree.h API: make read_tree_fn_t take an "enum object_type"
  2021-03-16  2:12       ` [PATCH v2 00/29] tree-walk: mostly replace "mode" with " Ævar Arnfjörð Bjarmason
                           ` (14 preceding siblings ...)
  2021-03-16 15:58         ` [PATCH v3 13/32] archive: get rid of 'stage' parameter Ævar Arnfjörð Bjarmason
@ 2021-03-16 15:58         ` Ævar Arnfjörð Bjarmason
  2021-03-16 15:58         ` [PATCH v3 15/32] tree-walk.h users: migrate "p->mode &&" pattern Ævar Arnfjörð Bjarmason
                           ` (17 subsequent siblings)
  33 siblings, 0 replies; 262+ messages in thread
From: Ævar Arnfjörð Bjarmason @ 2021-03-16 15:58 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 529623167c..254e15c8d0 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 0887352db2..95b2b0edf2 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 b7b76856a9..c25f75472f 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 13bcc2d847..b954d08ae4 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 8d5c3fd058..7176d2ae06 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 689a3e0007..df4b369902 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 6a2a52967e..c840bf2ea2 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 c1a936fdc4..12edb316f0 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.256.gf0ddda3145


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

* [PATCH v3 15/32] tree-walk.h users: migrate "p->mode &&" pattern
  2021-03-16  2:12       ` [PATCH v2 00/29] tree-walk: mostly replace "mode" with " Ævar Arnfjörð Bjarmason
                           ` (15 preceding siblings ...)
  2021-03-16 15:58         ` [PATCH v3 14/32] tree.h API: make read_tree_fn_t take an "enum object_type" Ævar Arnfjörð Bjarmason
@ 2021-03-16 15:58         ` Ævar Arnfjörð Bjarmason
  2021-03-16 15:58         ` [PATCH v3 16/32] tree-walk.h users: refactor chained "mode" if/else into switch Ævar Arnfjörð Bjarmason
                           ` (16 subsequent siblings)
  33 siblings, 0 replies; 262+ messages in thread
From: Ævar Arnfjörð Bjarmason @ 2021-03-16 15:58 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 de8520778d..2de34c2d48 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 4075d13aaa..4375027914 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 d9d573df98..802de46228 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.256.gf0ddda3145


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

* [PATCH v3 16/32] tree-walk.h users: refactor chained "mode" if/else into switch
  2021-03-16  2:12       ` [PATCH v2 00/29] tree-walk: mostly replace "mode" with " Ævar Arnfjörð Bjarmason
                           ` (16 preceding siblings ...)
  2021-03-16 15:58         ` [PATCH v3 15/32] tree-walk.h users: migrate "p->mode &&" pattern Ævar Arnfjörð Bjarmason
@ 2021-03-16 15:58         ` Ævar Arnfjörð Bjarmason
  2021-03-16 15:58         ` [PATCH v3 17/32] tree-walk.h users: migrate miscellaneous "mode" to "object_type" Ævar Arnfjörð Bjarmason
                           ` (15 subsequent siblings)
  33 siblings, 0 replies; 262+ messages in thread
From: Ævar Arnfjörð Bjarmason @ 2021-03-16 15:58 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 e19589baa0..37434ba89d 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 4984bf8b3d..7ba757244e 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.256.gf0ddda3145


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

* [PATCH v3 17/32] tree-walk.h users: migrate miscellaneous "mode" to "object_type"
  2021-03-16  2:12       ` [PATCH v2 00/29] tree-walk: mostly replace "mode" with " Ævar Arnfjörð Bjarmason
                           ` (17 preceding siblings ...)
  2021-03-16 15:58         ` [PATCH v3 16/32] tree-walk.h users: refactor chained "mode" if/else into switch Ævar Arnfjörð Bjarmason
@ 2021-03-16 15:58         ` Ævar Arnfjörð Bjarmason
  2021-03-16 15:58         ` [PATCH v3 18/32] merge-tree tests: test for the mode comparison in same_entry() Ævar Arnfjörð Bjarmason
                           ` (14 subsequent siblings)
  33 siblings, 0 replies; 262+ messages in thread
From: Ævar Arnfjörð Bjarmason @ 2021-03-16 15:58 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 4e91a253ac..5a317cdd2f 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 2de34c2d48..12cb317c1b 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 d3ba1d4a4a..f92722c12d 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 09541d1c80..bcbca82aa9 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 2fb483d3c0..fbe93dd2a5 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 aa98b2e541..e7cf93acbe 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 0a5b4fa1db..d631dc5623 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 802de46228..33de78e32c 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.256.gf0ddda3145


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

* [PATCH v3 18/32] merge-tree tests: test for the mode comparison in same_entry()
  2021-03-16  2:12       ` [PATCH v2 00/29] tree-walk: mostly replace "mode" with " Ævar Arnfjörð Bjarmason
                           ` (18 preceding siblings ...)
  2021-03-16 15:58         ` [PATCH v3 17/32] tree-walk.h users: migrate miscellaneous "mode" to "object_type" Ævar Arnfjörð Bjarmason
@ 2021-03-16 15:58         ` Ævar Arnfjörð Bjarmason
  2021-03-16 15:58         ` [PATCH v3 19/32] merge-ort: correct reference to test in 62fdec17a11 Ævar Arnfjörð Bjarmason
                           ` (13 subsequent siblings)
  33 siblings, 0 replies; 262+ messages in thread
From: Ævar Arnfjörð Bjarmason @ 2021-03-16 15:58 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 e59601e5fe..f783d784d0 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.256.gf0ddda3145


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

* [PATCH v3 19/32] merge-ort: correct reference to test in 62fdec17a11
  2021-03-16  2:12       ` [PATCH v2 00/29] tree-walk: mostly replace "mode" with " Ævar Arnfjörð Bjarmason
                           ` (19 preceding siblings ...)
  2021-03-16 15:58         ` [PATCH v3 18/32] merge-tree tests: test for the mode comparison in same_entry() Ævar Arnfjörð Bjarmason
@ 2021-03-16 15:58         ` Ævar Arnfjörð Bjarmason
  2021-03-16 15:58         ` [PATCH v3 20/32] fsck.c: switch on "object_type" in fsck_walk_tree() Ævar Arnfjörð Bjarmason
                           ` (12 subsequent siblings)
  33 siblings, 0 replies; 262+ messages in thread
From: Ævar Arnfjörð Bjarmason @ 2021-03-16 15:58 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 4375027914..e54be179bd 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.256.gf0ddda3145


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

* [PATCH v3 20/32] fsck.c: switch on "object_type" in fsck_walk_tree()
  2021-03-16  2:12       ` [PATCH v2 00/29] tree-walk: mostly replace "mode" with " Ævar Arnfjörð Bjarmason
                           ` (20 preceding siblings ...)
  2021-03-16 15:58         ` [PATCH v3 19/32] merge-ort: correct reference to test in 62fdec17a11 Ævar Arnfjörð Bjarmason
@ 2021-03-16 15:58         ` Ævar Arnfjörð Bjarmason
  2021-03-16 15:58         ` [PATCH v3 21/32] tree-walk.h users: use temporary variable(s) for "mode" Ævar Arnfjörð Bjarmason
                           ` (11 subsequent siblings)
  33 siblings, 0 replies; 262+ messages in thread
From: Ævar Arnfjörð Bjarmason @ 2021-03-16 15:58 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 e3030f3b35..7c74c49d32 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.256.gf0ddda3145


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

* [PATCH v3 21/32] tree-walk.h users: use temporary variable(s) for "mode"
  2021-03-16  2:12       ` [PATCH v2 00/29] tree-walk: mostly replace "mode" with " Ævar Arnfjörð Bjarmason
                           ` (21 preceding siblings ...)
  2021-03-16 15:58         ` [PATCH v3 20/32] fsck.c: switch on "object_type" in fsck_walk_tree() Ævar Arnfjörð Bjarmason
@ 2021-03-16 15:58         ` Ævar Arnfjörð Bjarmason
  2021-03-16 15:58         ` [PATCH v3 22/32] tree-walk.h API: formatting changes for subsequent commit Ævar Arnfjörð Bjarmason
                           ` (10 subsequent siblings)
  33 siblings, 0 replies; 262+ messages in thread
From: Ævar Arnfjörð Bjarmason @ 2021-03-16 15:58 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 12cb317c1b..eec5b90656 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 a28c19a62a..f3e192ca74 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 e54be179bd..cad1043650 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 d631dc5623..688d03ee9c 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 6ec180331f..088ed52d6a 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 33de78e32c..2319b114ba 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.256.gf0ddda3145


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

* [PATCH v3 22/32] tree-walk.h API: formatting changes for subsequent commit
  2021-03-16  2:12       ` [PATCH v2 00/29] tree-walk: mostly replace "mode" with " Ævar Arnfjörð Bjarmason
                           ` (22 preceding siblings ...)
  2021-03-16 15:58         ` [PATCH v3 21/32] tree-walk.h users: use temporary variable(s) for "mode" Ævar Arnfjörð Bjarmason
@ 2021-03-16 15:58         ` Ævar Arnfjörð Bjarmason
  2021-03-16 15:58         ` [PATCH v3 23/32] tree-walk.h API: rename get_tree_entry() to get_tree_entry_mode() Ævar Arnfjörð Bjarmason
                           ` (9 subsequent siblings)
  33 siblings, 0 replies; 262+ messages in thread
From: Ævar Arnfjörð Bjarmason @ 2021-03-16 15:58 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 a5044fcfaa..83babc41d0 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 6e9161901d..e88187e371 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 9f3825d277..478a659ee2 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.256.gf0ddda3145


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

* [PATCH v3 23/32] tree-walk.h API: rename get_tree_entry() to get_tree_entry_mode()
  2021-03-16  2:12       ` [PATCH v2 00/29] tree-walk: mostly replace "mode" with " Ævar Arnfjörð Bjarmason
                           ` (23 preceding siblings ...)
  2021-03-16 15:58         ` [PATCH v3 22/32] tree-walk.h API: formatting changes for subsequent commit Ævar Arnfjörð Bjarmason
@ 2021-03-16 15:58         ` Ævar Arnfjörð Bjarmason
  2021-03-16 15:58         ` [PATCH v3 24/32] match-trees: use "tmp" for mode in shift_tree_by() Ævar Arnfjörð Bjarmason
                           ` (8 subsequent siblings)
  33 siblings, 0 replies; 262+ messages in thread
From: Ævar Arnfjörð Bjarmason @ 2021-03-16 15:58 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 254e15c8d0..ab03107958 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 83babc41d0..9e0543e13d 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 4858631e0f..4617388b29 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 79087bccea..070510d6a8 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 75c8b1acff..4790dda460 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 f3e192ca74..0faacd8f4a 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 df4b369902..bbbb68e15b 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 688d03ee9c..ef13860614 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 64202de60b..7e3b2d6d73 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 e88187e371..7819ff3e0e 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 478a659ee2..eb9b9de6cc 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.256.gf0ddda3145


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

* [PATCH v3 24/32] match-trees: use "tmp" for mode in shift_tree_by()
  2021-03-16  2:12       ` [PATCH v2 00/29] tree-walk: mostly replace "mode" with " Ævar Arnfjörð Bjarmason
                           ` (24 preceding siblings ...)
  2021-03-16 15:58         ` [PATCH v3 23/32] tree-walk.h API: rename get_tree_entry() to get_tree_entry_mode() Ævar Arnfjörð Bjarmason
@ 2021-03-16 15:58         ` Ævar Arnfjörð Bjarmason
  2021-03-16 15:58         ` [PATCH v3 25/32] tree-walk.h API: add get_tree_entry_type() Ævar Arnfjörð Bjarmason
                           ` (7 subsequent siblings)
  33 siblings, 0 replies; 262+ messages in thread
From: Ævar Arnfjörð Bjarmason @ 2021-03-16 15:58 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 0faacd8f4a..e84f993a46 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.256.gf0ddda3145


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

* [PATCH v3 25/32] tree-walk.h API: add get_tree_entry_type()
  2021-03-16  2:12       ` [PATCH v2 00/29] tree-walk: mostly replace "mode" with " Ævar Arnfjörð Bjarmason
                           ` (25 preceding siblings ...)
  2021-03-16 15:58         ` [PATCH v3 24/32] match-trees: use "tmp" for mode in shift_tree_by() Ævar Arnfjörð Bjarmason
@ 2021-03-16 15:58         ` Ævar Arnfjörð Bjarmason
  2021-03-16 15:58         ` [PATCH v3 26/32] tree-walk.h API: document and format tree_entry_extract() Ævar Arnfjörð Bjarmason
                           ` (6 subsequent siblings)
  33 siblings, 0 replies; 262+ messages in thread
From: Ævar Arnfjörð Bjarmason @ 2021-03-16 15:58 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 ab03107958..d6aef83b69 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 e84f993a46..3177558313 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 7819ff3e0e..46ce1ba806 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 eb9b9de6cc..f569960c6f 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.256.gf0ddda3145


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

* [PATCH v3 26/32] tree-walk.h API: document and format tree_entry_extract()
  2021-03-16  2:12       ` [PATCH v2 00/29] tree-walk: mostly replace "mode" with " Ævar Arnfjörð Bjarmason
                           ` (26 preceding siblings ...)
  2021-03-16 15:58         ` [PATCH v3 25/32] tree-walk.h API: add get_tree_entry_type() Ævar Arnfjörð Bjarmason
@ 2021-03-16 15:58         ` Ævar Arnfjörð Bjarmason
  2021-03-16 15:58         ` [PATCH v3 27/32] tree-entry.h API: rename tree_entry_extract() to tree_entry_extract_mode() Ævar Arnfjörð Bjarmason
                           ` (5 subsequent siblings)
  33 siblings, 0 replies; 262+ messages in thread
From: Ævar Arnfjörð Bjarmason @ 2021-03-16 15:58 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 f569960c6f..f51485250f 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.256.gf0ddda3145


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

* [PATCH v3 27/32] tree-entry.h API: rename tree_entry_extract() to tree_entry_extract_mode()
  2021-03-16  2:12       ` [PATCH v2 00/29] tree-walk: mostly replace "mode" with " Ævar Arnfjörð Bjarmason
                           ` (27 preceding siblings ...)
  2021-03-16 15:58         ` [PATCH v3 26/32] tree-walk.h API: document and format tree_entry_extract() Ævar Arnfjörð Bjarmason
@ 2021-03-16 15:58         ` Ævar Arnfjörð Bjarmason
  2021-03-16 15:58         ` [PATCH v3 28/32] tree-walk.h API: add a tree_entry_extract_all() function Ævar Arnfjörð Bjarmason
                           ` (4 subsequent siblings)
  33 siblings, 0 replies; 262+ messages in thread
From: Ævar Arnfjörð Bjarmason @ 2021-03-16 15:58 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 7c74c49d32..11678ba582 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 3177558313..2afa496810 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 088ed52d6a..65c7e4dbc8 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 f51485250f..805cda649e 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.256.gf0ddda3145


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

* [PATCH v3 28/32] tree-walk.h API: add a tree_entry_extract_all() function
  2021-03-16  2:12       ` [PATCH v2 00/29] tree-walk: mostly replace "mode" with " Ævar Arnfjörð Bjarmason
                           ` (28 preceding siblings ...)
  2021-03-16 15:58         ` [PATCH v3 27/32] tree-entry.h API: rename tree_entry_extract() to tree_entry_extract_mode() Ævar Arnfjörð Bjarmason
@ 2021-03-16 15:58         ` Ævar Arnfjörð Bjarmason
  2021-03-16 15:58         ` [PATCH v3 29/32] tree-walk.h API: add get_tree_entry_all() Ævar Arnfjörð Bjarmason
                           ` (3 subsequent siblings)
  33 siblings, 0 replies; 262+ messages in thread
From: Ævar Arnfjörð Bjarmason @ 2021-03-16 15:58 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 65c7e4dbc8..918ad95fa6 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 46ce1ba806..f4473276c9 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 805cda649e..a4c5487174 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.256.gf0ddda3145


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

* [PATCH v3 29/32] tree-walk.h API: add get_tree_entry_all()
  2021-03-16  2:12       ` [PATCH v2 00/29] tree-walk: mostly replace "mode" with " Ævar Arnfjörð Bjarmason
                           ` (29 preceding siblings ...)
  2021-03-16 15:58         ` [PATCH v3 28/32] tree-walk.h API: add a tree_entry_extract_all() function Ævar Arnfjörð Bjarmason
@ 2021-03-16 15:58         ` Ævar Arnfjörð Bjarmason
  2021-03-16 15:58         ` [PATCH v3 30/32] tree-walk.h API: add a get_tree_entry_path() function Ævar Arnfjörð Bjarmason
                           ` (2 subsequent siblings)
  33 siblings, 0 replies; 262+ messages in thread
From: Ævar Arnfjörð Bjarmason @ 2021-03-16 15:58 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 070510d6a8..b489a87639 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 f4473276c9..a90dbf87af 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 a4c5487174..55ef88ef2e 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.256.gf0ddda3145


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

* [PATCH v3 30/32] tree-walk.h API: add a get_tree_entry_path() function
  2021-03-16  2:12       ` [PATCH v2 00/29] tree-walk: mostly replace "mode" with " Ævar Arnfjörð Bjarmason
                           ` (30 preceding siblings ...)
  2021-03-16 15:58         ` [PATCH v3 29/32] tree-walk.h API: add get_tree_entry_all() Ævar Arnfjörð Bjarmason
@ 2021-03-16 15:58         ` Ævar Arnfjörð Bjarmason
  2021-03-16 15:58         ` [PATCH v3 31/32] blame: emit a better error on 'git blame directory' Ævar Arnfjörð Bjarmason
  2021-03-16 15:58         ` [PATCH v3 32/32] tree-walk.h API: add a tree_entry_extract_type() function Ævar Arnfjörð Bjarmason
  33 siblings, 0 replies; 262+ messages in thread
From: Ævar Arnfjörð Bjarmason @ 2021-03-16 15:58 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 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[sic] '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 2afa496810..25bfb46fb0 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 bbbb68e15b..83d2b8b844 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 ef13860614..aa46cb2b09 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 7e3b2d6d73..9ff5f83c1f 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 a90dbf87af..fa846535df 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 55ef88ef2e..efcd7ccd10 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.256.gf0ddda3145


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

* [PATCH v3 31/32] blame: emit a better error on 'git blame directory'
  2021-03-16  2:12       ` [PATCH v2 00/29] tree-walk: mostly replace "mode" with " Ævar Arnfjörð Bjarmason
                           ` (31 preceding siblings ...)
  2021-03-16 15:58         ` [PATCH v3 30/32] tree-walk.h API: add a get_tree_entry_path() function Ævar Arnfjörð Bjarmason
@ 2021-03-16 15:58         ` Ævar Arnfjörð Bjarmason
  2021-03-16 15:58         ` [PATCH v3 32/32] tree-walk.h API: add a tree_entry_extract_type() function Ævar Arnfjörð Bjarmason
  33 siblings, 0 replies; 262+ messages in thread
From: Ævar Arnfjörð Bjarmason @ 2021-03-16 15:58 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

The main point of this test is to assert that we're not doing
something uniquely bad when in a conflicted merge. See
cd8ae20195 (git-blame shouldn't crash if run in an unmerged tree,
2007-10-18) and 9aeaab6811 (blame: allow "blame file" in the middle of
a conflicted merge, 2012-09-11) for the bug the t8004 test was
originally meant to address.

But when extending it let's grep out the specific error message for
good measure. Having to change it in the future (e.g. as part of my
parallel series to improve such 'OID does not match type' messages) is
a small price for ensuring it doesn't regress.

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

diff --git a/blame.c b/blame.c
index 9e0543e13d..7da162cd58 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->object.oid;
-		struct object_id blob_oid;
-		unsigned short 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)
+		struct object_id oid;
+		if (!get_tree_entry_path(r, commit_oid, path, &oid))
 			return;
 	}
 
diff --git a/t/t8004-blame-with-conflicts.sh b/t/t8004-blame-with-conflicts.sh
index 35414a5336..5e3dea35a5 100755
--- a/t/t8004-blame-with-conflicts.sh
+++ b/t/t8004-blame-with-conflicts.sh
@@ -73,4 +73,25 @@ test_expect_success 'blame does not crash with conflicted file in stages 1,3' '
 	git blame file1
 '
 
+test_expect_success 'setup second case' '
+	git merge --abort
+'
+
+test_expect_success 'blame on directory/file conflict' '
+	mkdir d &&
+	test_commit second &&
+	test_commit d/file &&
+	test_must_fail git blame d 2>expected &&
+	grep "unsupported file type d" expected &&
+
+	git reset --hard second &&
+	>d &&
+	git add d &&
+	git commit -m"a not-a-dir" &&
+	test_must_fail git merge d/file &&
+
+	test_must_fail git blame d 2>actual &&
+	test_cmp expected actual
+'
+
 test_done
-- 
2.31.0.256.gf0ddda3145


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

* [PATCH v3 32/32] tree-walk.h API: add a tree_entry_extract_type() function
  2021-03-16  2:12       ` [PATCH v2 00/29] tree-walk: mostly replace "mode" with " Ævar Arnfjörð Bjarmason
                           ` (32 preceding siblings ...)
  2021-03-16 15:58         ` [PATCH v3 31/32] blame: emit a better error on 'git blame directory' Ævar Arnfjörð Bjarmason
@ 2021-03-16 15:58         ` Ævar Arnfjörð Bjarmason
  33 siblings, 0 replies; 262+ messages in thread
From: Ævar Arnfjörð Bjarmason @ 2021-03-16 15:58 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 25bfb46fb0..89109659aa 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 918ad95fa6..8409374f0b 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 efcd7ccd10..f5102ed542 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.256.gf0ddda3145


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

* Re: [PATCH v3 00/32] tree-walk: mostly replace "mode" with "enum object_type"
  2021-03-16 15:57         ` [PATCH v3 00/32] " Ævar Arnfjörð Bjarmason
@ 2021-03-16 17:28           ` Elijah Newren
  2021-03-21  0:00           ` [PATCH v4 00/29] " Ævar Arnfjörð Bjarmason
  1 sibling, 0 replies; 262+ messages in thread
From: Elijah Newren @ 2021-03-16 17: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 Tue, Mar 16, 2021 at 8:58 AM Ævar Arnfjörð Bjarmason
<avarab@gmail.com> wrote:
>
> The v2 of this series was broken as noted in
> https://lore.kernel.org/git/87blbjfqkh.fsf@evledraar.gmail.com/
>
> Here's a fixed version. This should actually address all of Elijah's
> comments on v1 + v2.

Yep, this one looks good to me.  Thanks!

>
> It's up to 32 patches because I added some tests for the
> mostly-never-been-tested code being changed in 09/32.
>
> Ævar Arnfjörð Bjarmason (32):
>   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
>   fast-import tests: test for sorting dir/file foo v.s. foo.txt
>   mktree tests: test that "mode" is passed when sorting
>   diff tests: test that "mode" is passed when sorting
>   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()
>   match-trees: 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           | 12 +++--
>  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/t1450-fsck.sh                 | 66 ++++++++++++++++++++++++
>  t/t4300-merge-tree.sh           | 44 ++++++++++++++++
>  t/t8004-blame-with-conflicts.sh | 21 ++++++++
>  t/t9300-fast-import.sh          | 87 ++++++++++++++++++++++++++++++++
>  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 ++++----
>  42 files changed, 618 insertions(+), 244 deletions(-)
>
> Range-diff:
>  1:  f9bbc30f69 =  1:  26bc38fbdd diff.c: remove redundant canon_mode() call
>  2:  187fc2c3e6 =  2:  8502cf8134 notes & match-trees: use name_entry's "pathlen" member
>  3:  311637c558 =  3:  68133fa6aa cache.h: add a comment to object_type()
>  4:  fecfe3d462 =  4:  9f714d6c01 tree-walk.h: add object_type member to name_entry
>  5:  db961ab5e8 =  5:  6dbf2b0a6a tree-walk.c: migrate to using new "object_type" field when possible
>  -:  ---------- >  6:  354a8e9a2a fast-import tests: test for sorting dir/file foo v.s. foo.txt
>  -:  ---------- >  7:  e2331df28e mktree tests: test that "mode" is passed when sorting
>  -:  ---------- >  8:  9e9486c2ea diff tests: test that "mode" is passed when sorting
>  6:  df2fc76161 !  9:  be5c713336 cache.h: have base_name_compare() take "is tree?", not "mode"
>     @@ Commit message
>          958ba6c96eb (Introduce "base_name_compare()" helper function,
>          2005-05-20).
>
>     +    None of these comparison functions used to have tests, but with
>     +    preceding commits some of them now do. I thought the remainder was
>     +    trivial enough to review without tests, and didn't want to spend more
>     +    time on them.
>     +
>          Signed-off-by: Ævar Arnfjörð Bjarmason <avarab@gmail.com>
>
>       ## builtin/fast-import.c ##
>      @@ builtin/fast-import.c: 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);
>     ++  int istree_a = S_ISDIR(a->versions[0].mode);
>     ++  int istree_b = S_ISDIR(b->versions[0].mode);
>         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);
>     ++          a->name->str_dat, a->name->str_len, istree_a,
>     ++          b->name->str_dat, b->name->str_len, istree_b);
>       }
>
>       static int tecmp1 (const void *_a, const void *_b)
>     -@@ builtin/fast-import.c: 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);
>     ++  int istree_a = S_ISDIR(a->versions[1].mode);
>     ++  int istree_b = S_ISDIR(b->versions[1].mode);
>         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);
>     ++          a->name->str_dat, a->name->str_len, istree_a,
>     ++          b->name->str_dat, b->name->str_len, istree_b);
>       }
>
>       static void mktree(struct tree_content *t, int v, struct strbuf *b)
>  7:  49d5da8c08 = 10:  43623edddf tree-walk.h users: switch object_type(...) to new .object_type
>  8:  c9d209d496 = 11:  030898f884 tree.h: format argument lists of read_tree_recursive() users
>  9:  a6d2660fe1 = 12:  0ce197950b tree.h users: format argument lists in archive.c
> 10:  15f7f89acc = 13:  051c9f32ac archive: get rid of 'stage' parameter
> 11:  7a71404ea3 = 14:  bc73994b4c tree.h API: make read_tree_fn_t take an "enum object_type"
> 12:  64dc9364ba = 15:  e2b0964228 tree-walk.h users: migrate "p->mode &&" pattern
> 13:  93ed3edbbd = 16:  29dbc4292e tree-walk.h users: refactor chained "mode" if/else into switch
> 14:  7aa48aa34c = 17:  ada6d05176 tree-walk.h users: migrate miscellaneous "mode" to "object_type"
> 15:  3ae81621dc = 18:  01860daa55 merge-tree tests: test for the mode comparison in same_entry()
> 16:  4249ad5c4d = 19:  e4be48fb50 merge-ort: correct reference to test in 62fdec17a11
> 17:  e5e17505dd = 20:  189d2550fb fsck.c: switch on "object_type" in fsck_walk_tree()
> 18:  3f0b884f1f = 21:  3b7b12e6f7 tree-walk.h users: use temporary variable(s) for "mode"
> 19:  174167613b = 22:  6c3a07a327 tree-walk.h API: formatting changes for subsequent commit
> 20:  ec76db613f = 23:  879eb3da2a tree-walk.h API: rename get_tree_entry() to get_tree_entry_mode()
> 21:  11e3494172 ! 24:  d2fa360ab9 tree-walk.h API users: use "tmp" for mode in shift_tree_by()
>     @@ Metadata
>      Author: Ævar Arnfjörð Bjarmason <avarab@gmail.com>
>
>       ## Commit message ##
>     -    tree-walk.h API users: use "tmp" for mode in shift_tree_by()
>     +    match-trees: use "tmp" for mode in shift_tree_by()
>
>          Refactor code added in 85e51b783c3 (Make "subtree" part more
>          orthogonal to the rest of merge-recursive., 2008-06-30) to make it
> 22:  b31c106557 = 25:  cc50cfcf51 tree-walk.h API: add get_tree_entry_type()
> 23:  304d5d4d1a = 26:  f642a35482 tree-walk.h API: document and format tree_entry_extract()
> 24:  346453df35 = 27:  a0bcb59fa5 tree-entry.h API: rename tree_entry_extract() to tree_entry_extract_mode()
> 25:  dd012b661e = 28:  c7d4ba7734 tree-walk.h API: add a tree_entry_extract_all() function
> 26:  b6ee8410e3 = 29:  1d5421d67a tree-walk.h API: add get_tree_entry_all()
> 27:  5c98afd9e7 ! 30:  a3e1063ac4 tree-walk.h API: add a get_tree_entry_path() function
>     @@ Commit message
>          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.
>     +    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'.,
>     +     - shift_tree(): 68faf68938e (A new merge stragety[sic] 'subtree'.,
>              2007-02-15) for the shift_tree()
>
>           - tree_has_path(): 96e7ffbdc31 (merge-recursive: check for directory
> 28:  3e7e0f7eb8 ! 31:  da3dd6dd53 blame: emit a better error on 'git blame directory'
>     @@ Commit message
>
>              fatal: no such path 't' in HEAD
>
>     +    The main point of this test is to assert that we're not doing
>     +    something uniquely bad when in a conflicted merge. See
>     +    cd8ae20195 (git-blame shouldn't crash if run in an unmerged tree,
>     +    2007-10-18) and 9aeaab6811 (blame: allow "blame file" in the middle of
>     +    a conflicted merge, 2012-09-11) for the bug the t8004 test was
>     +    originally meant to address.
>     +
>     +    But when extending it let's grep out the specific error message for
>     +    good measure. Having to change it in the future (e.g. as part of my
>     +    parallel series to improve such 'OID does not match type' messages) is
>     +    a small price for ensuring it doesn't regress.
>     +
>          Signed-off-by: Ævar Arnfjörð Bjarmason <avarab@gmail.com>
>
>       ## blame.c ##
>     @@ t/t8004-blame-with-conflicts.sh: test_expect_success 'blame does not crash with
>      +  test_commit second &&
>      +  test_commit d/file &&
>      +  test_must_fail git blame d 2>expected &&
>     ++  grep "unsupported file type d" expected &&
>      +
>      +  git reset --hard second &&
>      +  >d &&
> 29:  ac1ccf1357 = 32:  80e5cb0b30 tree-walk.h API: add a tree_entry_extract_type() function
> --
> 2.31.0.256.gf0ddda3145
>

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

* Re: [PATCH v3 0/9] read_tree() and read_tree_recursive() refactoring
  2021-03-15 23:43     ` [PATCH v3 0/9] read_tree() and read_tree_recursive() refactoring Ævar Arnfjörð Bjarmason
                         ` (10 preceding siblings ...)
  2021-03-16 15:52       ` [PATCH v4 9/9] tree.h API: expose read_tree_1() as read_tree_at() Ævar Arnfjörð Bjarmason
@ 2021-03-17 17:38       ` Junio C Hamano
  2021-03-20 22:37         ` [PATCH v5 0/8] " Ævar Arnfjörð Bjarmason
  11 siblings, 1 reply; 262+ messages in thread
From: Junio C Hamano @ 2021-03-17 17:38 UTC (permalink / raw)
  To: Ævar Arnfjörð Bjarmason; +Cc: git, Elijah Newren, Derrick Stolee

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

> 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()

The end-result looks good, but it seeps through the structure of the
series that the steps #7-#9 are afterthought of fixing a mistake
made in the step #5.  If #4 refactors away and removes read_tree()
and makes the name available, a natural next step would be to
introduce a thin-wrapper read_tree() around read_tree_recursive(),
which is to be used by majority of callers that do not need
non-empty prefix and stage, and that would become step #5 if I were
doing the series.  That step makes the codebase ready to change the
callers of read_tree_recursive() to call the simpler read_tree(),
which would be step #6.  The read_tree_recursive() would only have
one caller (i.e. the new read_tree() which is a castrated version of
read_tree_recursive()) and renaming it to read_tree_at() would be
another simple step #7.

>  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()

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

* [PATCH v5 0/8] read_tree() and read_tree_recursive() refactoring
  2021-03-17 17:38       ` [PATCH v3 0/9] read_tree() and read_tree_recursive() refactoring Junio C Hamano
@ 2021-03-20 22:37         ` Ævar Arnfjörð Bjarmason
  2021-03-20 22:37           ` [PATCH v5 1/8] show tests: add test for "git show <tree>" Ævar Arnfjörð Bjarmason
                             ` (8 more replies)
  0 siblings, 9 replies; 262+ messages in thread
From: Ævar Arnfjörð Bjarmason @ 2021-03-20 22:37 UTC (permalink / raw)
  To: git
  Cc: Junio C Hamano, Elijah Newren, Derrick Stolee,
	Ævar Arnfjörð Bjarmason

A refactoring of v4[1], not quite as as suggested by Junio in[2], but
which I think makes this whole thing less confusing and more
straightforward.

I now start by entirely getting rid of the meaningful passing of the
"stage" variable before removing it and the path variable entirely in
8/8, but before that in 7/8 I've introduced the read_tree_at()
function Derrick Stolee needs for his in-flight series.

1. http://lore.kernel.org/git/20210316155244.28328-1-avarab@gmail.com
2. https://lore.kernel.org/git/xmqqpmzxy939.fsf@gitster.g/

Ævar Arnfjörð Bjarmason (8):
  show tests: add test for "git show <tree>"
  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()
  archive: stop passing "stage" through read_tree_recursive()
  tree.h API: expose read_tree_1() as read_tree_at()
  tree.h API: simplify read_tree_recursive() signature

 archive.c                     |  30 ++++-----
 builtin/checkout.c            |   8 +--
 builtin/log.c                 |   8 +--
 builtin/ls-files.c            |  75 ++++++++++++++++++++-
 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                        | 119 ++++------------------------------
 tree.h                        |  18 ++---
 11 files changed, 205 insertions(+), 147 deletions(-)

Range-diff:
 8:  8a6bebde234 !  1:  c307eb53331 show tests: add test for "git show <tree>"
    @@ Commit message
     
         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
    +    t7701-repack-unpack-unreachable.sh happily pass if we start buggily
         emitting trees recursively.
     
         Signed-off-by: Ævar Arnfjörð Bjarmason <avarab@gmail.com>
 1:  b338f2c01a4 =  2:  f37d7705cf0 ls-files tests: add meaningful --with-tree tests
 2:  4578b83944c =  3:  6291d8a1b5e tree.c API: move read_tree() into builtin/ls-files.c
 3:  33656ff63b8 !  4:  466b518e915 ls-files: don't needlessly pass around stage variable
    @@ Commit message
         Now that read_tree() has been moved to ls-files.c we can get rid of
         the stage != 1 case that'll never happen.
     
    +    Let's not use read_tree_recursive() as a pass-through to pass "stage =
    +    1" either. For now we'll pass an unused "stage = 0" for consistency
    +    with other read_tree_recursive() callers, that argument will be
    +    removed in a follow-up commit.
    +
         Signed-off-by: Ævar Arnfjörð Bjarmason <avarab@gmail.com>
     
      ## builtin/ls-files.c ##
    +@@ builtin/ls-files.c: 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)
    ++			      unsigned mode, int opt)
    + {
    + 	int len;
    + 	struct cache_entry *ce;
    +@@ builtin/ls-files.c: static int read_one_entry_opt(struct index_state *istate,
    + 	ce = make_empty_cache_entry(istate, baselen + 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 = baselen + len;
    + 	memcpy(ce->name, base, baselen);
    + 	memcpy(ce->name + baselen, pathname, len+1);
    +@@ builtin/ls-files.c: static int read_one_entry(const struct object_id *oid, struct strbuf *base,
    + {
    + 	struct index_state *istate = context;
    + 	return read_one_entry_opt(istate, oid, base->buf, base->len, pathname,
    +-				  mode, stage,
    ++				  mode,
    + 				  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
    + {
    + 	struct index_state *istate = context;
    + 	return read_one_entry_opt(istate, oid, base->buf, base->len, pathname,
    +-				  mode, stage,
    ++				  mode,
    + 				  ADD_CACHE_JUST_APPEND);
      }
      
      
    @@ builtin/ls-files.c: static int read_tree(struct repository *r, struct tree *tree
      	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);
    ++	err = read_tree_recursive(r, tree, "", 0, 0, match, fn, istate);
      	if (fn == read_one_entry || err)
      		return err;
      
 4:  1c96d5d3611 !  5:  30c3abfe9b9 ls-files: refactor away read_tree()
    @@ builtin/ls-files.c: static int get_common_prefix_len(const char *common_prefix)
     -			      const char *base, int baselen,
     +			      struct strbuf *base,
      			      const char *pathname,
    - 			      unsigned mode, int stage, int opt)
    + 			      unsigned mode, int opt)
      {
     @@ builtin/ls-files.c: static int read_one_entry_opt(struct index_state *istate,
      		return READ_TREE_RECURSIVE;
    @@ 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);
    - 	ce->ce_flags = create_ce_flags(stage);
    + 	ce->ce_flags = create_ce_flags(1);
     -	ce->ce_namelen = baselen + len;
     -	memcpy(ce->name, base, baselen);
     -	memcpy(ce->name + baselen, pathname, len+1);
    @@ builtin/ls-files.c: static int read_one_entry(const struct object_id *oid, struc
      	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,
    + 				  mode,
      				  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
    @@ builtin/ls-files.c: static int read_one_entry_quick(const struct object_id *oid,
      {
      	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);
    - }
    - 
    +-				  mode,
    +-				  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_quick(const struct object_id *oid,
     -
     -	if (!fn)
     -		fn = read_one_entry_quick;
    --	err = read_tree_recursive(r, tree, "", 0, 1, match, fn, istate);
    +-	err = read_tree_recursive(r, tree, "", 0, 0, match, fn, istate);
     -	if (fn == read_one_entry || err)
     -		return err;
     -
    @@ builtin/ls-files.c: static int read_one_entry_quick(const struct object_id *oid,
     -	cache_tree_free(&istate->cache_tree);
     -	QSORT(istate->cache, istate->cache_nr, cmp_cache_name_compare);
     -	return 0;
    --}
    --
    ++	return read_one_entry_opt(istate, oid, base, pathname,
    ++				  mode, 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;
 5:  367cb99224b <  -:  ----------- tree.h API: remove support for starting at prefix != ""
 6:  38e36780e22 <  -:  ----------- tree.h API: remove "stage" parameter from read_tree_recursive()
 7:  859902ffd83 <  -:  ----------- tree.h API: rename read_tree_recursive() to read_tree()
 -:  ----------- >  6:  02c42be9249 archive: stop passing "stage" through read_tree_recursive()
 9:  29996dd82bc !  7:  d55e8d4042b tree.h API: expose read_tree_1() as read_tree_at()
    @@ Metadata
      ## Commit message ##
         tree.h API: expose read_tree_1() as read_tree_at()
     
    -    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 "".
    +    Rename the static read_tree_1() function to read_tree_at(). This
    +    function works just like read_tree_recursive(), except you provide
    +    your own strbuf.
     
    -    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.
    +    This step doesn't make much sense now, but in follow-up commits I'll
    +    remove the base/baselen/stage arguments to read_tree_recursive(). At
    +    that point an anticipated in-tree user[1] for the old
    +    read_tree_recursive() couldn't provide a path to start the
    +    traversal.
     
    -    1. https://lore.kernel.org/git/xmqqft106sok.fsf@gitster.g/#t
    +    Let's give them a function to do so with an API that makes more sense
    +    for them, by taking a strbuf we should be able to avoid more casting
    +    and/or reallocations in the future.
    +
    +    1. https://lore.kernel.org/git/xmqqft106sok.fsf@gitster.g
     
      ## tree.c ##
     @@
    @@ tree.c
      
     -static int read_tree_1(struct repository *r,
     -		       struct tree *tree, struct strbuf *base,
    --		       const struct pathspec *pathspec,
    +-		       int stage, const struct pathspec *pathspec,
     -		       read_tree_fn_t fn, void *context)
     +int read_tree_at(struct repository *r,
     +		 struct tree *tree, struct strbuf *base,
    ++		 int stage,
     +		 const struct pathspec *pathspec,
     +		 read_tree_fn_t fn, void *context)
      {
    @@ tree.c: 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, pathspec,
    +-				     base, stage, pathspec,
     -				     fn, context);
     +		retval = read_tree_at(r, lookup_tree(r, &oid),
    -+				      base, pathspec,
    ++				      base, stage, pathspec,
     +				      fn, context);
      		strbuf_setlen(base, oldlen);
      		if (retval)
      			return -1;
    -@@ tree.c: int read_tree(struct repository *r,
    - 	struct strbuf sb = STRBUF_INIT;
    +@@ tree.c: int read_tree_recursive(struct repository *r,
      	int ret;
      
    --	ret = read_tree_1(r, tree, &sb, pathspec, fn, context);
    -+	ret = read_tree_at(r, tree, &sb, pathspec, fn, context);
    + 	strbuf_add(&sb, base, baselen);
    +-	ret = read_tree_1(r, tree, &sb, stage, pathspec, fn, context);
    ++	ret = read_tree_at(r, tree, &sb, stage, pathspec, fn, context);
      	strbuf_release(&sb);
      	return ret;
      }
    @@ tree.c: int read_tree(struct repository *r,
      ## tree.h ##
     @@ tree.h: 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, int, void *);
      
     +int read_tree_at(struct repository *r,
    -+		 struct tree *tree,
    -+		 struct strbuf *at,
    ++		 struct tree *tree, struct strbuf *base,
    ++		 int stage,
     +		 const struct pathspec *pathspec,
     +		 read_tree_fn_t fn, void *context);
     +
    - int read_tree(struct repository *r,
    - 	      struct tree *tree,
    - 	      const struct pathspec *pathspec,
    + int read_tree_recursive(struct repository *r,
    + 			struct tree *tree,
    + 			const char *base, int baselen,
 -:  ----------- >  8:  fa157d8baee tree.h API: simplify read_tree_recursive() signature
-- 
2.31.0.286.gc175f2cb894


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

* [PATCH v5 1/8] show tests: add test for "git show <tree>"
  2021-03-20 22:37         ` [PATCH v5 0/8] " Ævar Arnfjörð Bjarmason
@ 2021-03-20 22:37           ` Ævar Arnfjörð Bjarmason
  2021-03-20 22:37           ` [PATCH v5 2/8] ls-files tests: add meaningful --with-tree tests Ævar Arnfjörð Bjarmason
                             ` (7 subsequent siblings)
  8 siblings, 0 replies; 262+ messages in thread
From: Ævar Arnfjörð Bjarmason @ 2021-03-20 22:37 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 pass 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..d6cc69e0f2c 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^{tree}
+
+	main1.t
+
+	tree main2^{tree}
+
+	main1.t
+	main2.t
+	EOF
+	git show main1^{tree} main2^{tree} >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 HEAD^{tree}
+
+	a/
+	main1.t
+	EOF
+	git -C not-recursive show HEAD^{tree} >actual &&
+	test_cmp expected actual
+'
+
 test_expect_success 'showing a range walks (linear)' '
 	cat >expect <<-EOF &&
 	commit $(git rev-parse main3)
-- 
2.31.0.286.gc175f2cb894


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

* [PATCH v5 2/8] ls-files tests: add meaningful --with-tree tests
  2021-03-20 22:37         ` [PATCH v5 0/8] " Ævar Arnfjörð Bjarmason
  2021-03-20 22:37           ` [PATCH v5 1/8] show tests: add test for "git show <tree>" Ævar Arnfjörð Bjarmason
@ 2021-03-20 22:37           ` Ævar Arnfjörð Bjarmason
  2021-03-20 22:37           ` [PATCH v5 3/8] tree.c API: move read_tree() into builtin/ls-files.c Ævar Arnfjörð Bjarmason
                             ` (6 subsequent siblings)
  8 siblings, 0 replies; 262+ messages in thread
From: Ævar Arnfjörð Bjarmason @ 2021-03-20 22:37 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.286.gc175f2cb894


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

* [PATCH v5 3/8] tree.c API: move read_tree() into builtin/ls-files.c
  2021-03-20 22:37         ` [PATCH v5 0/8] " Ævar Arnfjörð Bjarmason
  2021-03-20 22:37           ` [PATCH v5 1/8] show tests: add test for "git show <tree>" Ævar Arnfjörð Bjarmason
  2021-03-20 22:37           ` [PATCH v5 2/8] ls-files tests: add meaningful --with-tree tests Ævar Arnfjörð Bjarmason
@ 2021-03-20 22:37           ` Ævar Arnfjörð Bjarmason
  2021-03-20 22:37           ` [PATCH v5 4/8] ls-files: don't needlessly pass around stage variable Ævar Arnfjörð Bjarmason
                             ` (5 subsequent siblings)
  8 siblings, 0 replies; 262+ messages in thread
From: Ævar Arnfjörð Bjarmason @ 2021-03-20 22:37 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.286.gc175f2cb894


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

* [PATCH v5 4/8] ls-files: don't needlessly pass around stage variable
  2021-03-20 22:37         ` [PATCH v5 0/8] " Ævar Arnfjörð Bjarmason
                             ` (2 preceding siblings ...)
  2021-03-20 22:37           ` [PATCH v5 3/8] tree.c API: move read_tree() into builtin/ls-files.c Ævar Arnfjörð Bjarmason
@ 2021-03-20 22:37           ` Ævar Arnfjörð Bjarmason
  2021-03-20 22:37           ` [PATCH v5 5/8] ls-files: refactor away read_tree() Ævar Arnfjörð Bjarmason
                             ` (4 subsequent siblings)
  8 siblings, 0 replies; 262+ messages in thread
From: Ævar Arnfjörð Bjarmason @ 2021-03-20 22:37 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.

Let's not use read_tree_recursive() as a pass-through to pass "stage =
1" either. For now we'll pass an unused "stage = 0" for consistency
with other read_tree_recursive() callers, that argument will be
removed in a follow-up commit.

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

diff --git a/builtin/ls-files.c b/builtin/ls-files.c
index a4458622813..3149a2769a3 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,
 			      const char *base, int baselen,
 			      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, baselen + 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 = baselen + len;
 	memcpy(ce->name, base, baselen);
 	memcpy(ce->name + baselen, pathname, len+1);
@@ -451,7 +451,7 @@ static int read_one_entry(const struct object_id *oid, struct strbuf *base,
 {
 	struct index_state *istate = context;
 	return read_one_entry_opt(istate, oid, base->buf, base->len, pathname,
-				  mode, stage,
+				  mode,
 				  ADD_CACHE_OK_TO_ADD|ADD_CACHE_SKIP_DFCHECK);
 }
 
@@ -465,26 +465,17 @@ static int read_one_entry_quick(const struct object_id *oid, struct strbuf *base
 {
 	struct index_state *istate = context;
 	return read_one_entry_opt(istate, oid, base->buf, base->len, pathname,
-				  mode, stage,
+				  mode,
 				  ADD_CACHE_JUST_APPEND);
 }
 
 
-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, 0, 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.286.gc175f2cb894


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

* [PATCH v5 5/8] ls-files: refactor away read_tree()
  2021-03-20 22:37         ` [PATCH v5 0/8] " Ævar Arnfjörð Bjarmason
                             ` (3 preceding siblings ...)
  2021-03-20 22:37           ` [PATCH v5 4/8] ls-files: don't needlessly pass around stage variable Ævar Arnfjörð Bjarmason
@ 2021-03-20 22:37           ` Ævar Arnfjörð Bjarmason
  2021-03-20 22:37           ` [PATCH v5 6/8] archive: stop passing "stage" through read_tree_recursive() Ævar Arnfjörð Bjarmason
                             ` (3 subsequent siblings)
  8 siblings, 0 replies; 262+ messages in thread
From: Ævar Arnfjörð Bjarmason @ 2021-03-20 22:37 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 | 77 ++++++++++++++++++++--------------------------
 1 file changed, 34 insertions(+), 43 deletions(-)

diff --git a/builtin/ls-files.c b/builtin/ls-files.c
index 3149a2769a3..aa153423b80 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 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(1);
-	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,
 				  ADD_CACHE_OK_TO_ADD|ADD_CACHE_SKIP_DFCHECK);
 }
@@ -464,42 +464,8 @@ 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,
-				  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, 0, 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 read_one_entry_opt(istate, oid, base, pathname,
+				  mode, ADD_CACHE_JUST_APPEND);
 }
 
 /*
@@ -518,6 +484,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 +508,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.286.gc175f2cb894


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

* [PATCH v5 6/8] archive: stop passing "stage" through read_tree_recursive()
  2021-03-20 22:37         ` [PATCH v5 0/8] " Ævar Arnfjörð Bjarmason
                             ` (4 preceding siblings ...)
  2021-03-20 22:37           ` [PATCH v5 5/8] ls-files: refactor away read_tree() Ævar Arnfjörð Bjarmason
@ 2021-03-20 22:37           ` Ævar Arnfjörð Bjarmason
  2021-03-20 22:37           ` [PATCH v5 7/8] tree.h API: expose read_tree_1() as read_tree_at() Ævar Arnfjörð Bjarmason
                             ` (2 subsequent siblings)
  8 siblings, 0 replies; 262+ messages in thread
From: Ævar Arnfjörð Bjarmason @ 2021-03-20 22:37 UTC (permalink / raw)
  To: git
  Cc: Junio C Hamano, Elijah Newren, Derrick Stolee,
	Ævar Arnfjörð Bjarmason

The "stage" variable being passed around in the archive code has only
ever been an elaborate way to hardcode the value "0".

This code was added in its original form in e4fbbfe9ecc (Add
git-zip-tree, 2006-08-26), at which point a hardcoded "0" would be
passed down through read_tree_recursive() to write_zip_entry().

It was then diligently added to the "struct directory" in
ed22b4173bd (archive: support filtering paths with glob, 2014-09-21),
but we were still not doing anything except passing it around as-is.

Let's stop doing that in the code internal to archive.c, we'll still
feed "0" to read_tree_recursive() itself, but won't use it. That we're
providing it at all to read_tree_recursive() will be changed in a
follow-up commit.

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

diff --git a/archive.c b/archive.c
index 5919d9e5050..4f271331543 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];
 };
 
@@ -138,7 +137,7 @@ 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,
+		int baselen, const char *filename, unsigned mode,
 		void *context)
 {
 	static struct strbuf path = STRBUF_INIT;
@@ -197,7 +196,7 @@ 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)
+		unsigned mode, struct archiver_context *c)
 {
 	struct directory *d;
 	size_t len = st_add4(base->len, 1, strlen(filename), 1);
@@ -205,7 +204,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);
@@ -224,7 +222,7 @@ static int write_directory(struct archiver_context *c)
 		write_directory(c) ||
 		write_archive_entry(&d->oid, d->path, d->baselen,
 				    d->path + d->baselen, d->mode,
-				    d->stage, c) != READ_TREE_RECURSIVE;
+				    c) != READ_TREE_RECURSIVE;
 	free(d);
 	return ret ? -1 : 0;
 }
@@ -256,14 +254,14 @@ 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, c);
 		return READ_TREE_RECURSIVE;
 	}
 
 	if (write_directory(c))
 		return -1;
 	return write_archive_entry(oid, base->buf, base->len, filename, mode,
-				   stage, context);
+				   context);
 }
 
 struct extra_file_info {
@@ -377,8 +375,8 @@ 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)
+			const char *filename, unsigned mode, int stage,
+			void *context)
 {
 	int ret = -1;
 	struct path_exists_context *ctx = context;
-- 
2.31.0.286.gc175f2cb894


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

* [PATCH v5 7/8] tree.h API: expose read_tree_1() as read_tree_at()
  2021-03-20 22:37         ` [PATCH v5 0/8] " Ævar Arnfjörð Bjarmason
                             ` (5 preceding siblings ...)
  2021-03-20 22:37           ` [PATCH v5 6/8] archive: stop passing "stage" through read_tree_recursive() Ævar Arnfjörð Bjarmason
@ 2021-03-20 22:37           ` Ævar Arnfjörð Bjarmason
  2021-03-20 22:37           ` [PATCH v5 8/8] tree.h API: simplify read_tree_recursive() signature Ævar Arnfjörð Bjarmason
  2021-03-20 23:08           ` [PATCH v5 0/8] read_tree() and read_tree_recursive() refactoring Junio C Hamano
  8 siblings, 0 replies; 262+ messages in thread
From: Ævar Arnfjörð Bjarmason @ 2021-03-20 22:37 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
function works just like read_tree_recursive(), except you provide
your own strbuf.

This step doesn't make much sense now, but in follow-up commits I'll
remove the base/baselen/stage arguments to read_tree_recursive(). At
that point an anticipated in-tree user[1] for the old
read_tree_recursive() couldn't provide a path to start the
traversal.

Let's give them a function to do so with an API that makes more sense
for them, by taking a strbuf we should be able to avoid more casting
and/or reallocations in the future.

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

diff --git a/tree.c b/tree.c
index a6c12f2745a..f67c2153054 100644
--- a/tree.c
+++ b/tree.c
@@ -11,10 +11,11 @@
 
 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,
-		       read_tree_fn_t fn, void *context)
+int read_tree_at(struct repository *r,
+		 struct tree *tree, struct strbuf *base,
+		 int stage,
+		 const struct pathspec *pathspec,
+		 read_tree_fn_t fn, void *context)
 {
 	struct tree_desc desc;
 	struct name_entry entry;
@@ -71,9 +72,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, stage, pathspec,
-				     fn, context);
+		retval = read_tree_at(r, lookup_tree(r, &oid),
+				      base, stage, pathspec,
+				      fn, context);
 		strbuf_setlen(base, oldlen);
 		if (retval)
 			return -1;
@@ -91,7 +92,7 @@ int read_tree_recursive(struct repository *r,
 	int ret;
 
 	strbuf_add(&sb, base, baselen);
-	ret = read_tree_1(r, tree, &sb, stage, pathspec, fn, context);
+	ret = read_tree_at(r, tree, &sb, stage, pathspec, fn, context);
 	strbuf_release(&sb);
 	return ret;
 }
diff --git a/tree.h b/tree.h
index 6b0b1dc211a..123fc41efe6 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, int, void *);
 
+int read_tree_at(struct repository *r,
+		 struct tree *tree, struct strbuf *base,
+		 int stage,
+		 const struct pathspec *pathspec,
+		 read_tree_fn_t fn, void *context);
+
 int read_tree_recursive(struct repository *r,
 			struct tree *tree,
 			const char *base, int baselen,
-- 
2.31.0.286.gc175f2cb894


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

* [PATCH v5 8/8] tree.h API: simplify read_tree_recursive() signature
  2021-03-20 22:37         ` [PATCH v5 0/8] " Ævar Arnfjörð Bjarmason
                             ` (6 preceding siblings ...)
  2021-03-20 22:37           ` [PATCH v5 7/8] tree.h API: expose read_tree_1() as read_tree_at() Ævar Arnfjörð Bjarmason
@ 2021-03-20 22:37           ` Ævar Arnfjörð Bjarmason
  2021-03-20 23:08           ` [PATCH v5 0/8] read_tree() and read_tree_recursive() refactoring Junio C Hamano
  8 siblings, 0 replies; 262+ messages in thread
From: Ævar Arnfjörð Bjarmason @ 2021-03-20 22:37 UTC (permalink / raw)
  To: git
  Cc: Junio C Hamano, Elijah Newren, Derrick Stolee,
	Ævar Arnfjörð Bjarmason

Simplify the signature of read_tree_recursive() to omit the "base",
"baselen" and "stage" arguments. No callers of it use these parameters
for anything anymore.

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).

The last user of the "stage" parameter went away in the last commit,
and even that use was mere boilerplate.

So let's remove those and rename the read_tree_recursive() function to
just read_tree(). We had another read_tree() function that I've
refactored away in preceding commits, 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          | 18 +++++++++---------
 builtin/checkout.c |  8 ++++----
 builtin/log.c      |  8 ++++----
 builtin/ls-files.c |  6 +++---
 builtin/ls-tree.c  |  6 +++---
 merge-recursive.c  |  6 +++---
 tree.c             | 19 +++++++------------
 tree.h             | 13 ++++++-------
 8 files changed, 39 insertions(+), 45 deletions(-)

diff --git a/archive.c b/archive.c
index 4f271331543..4921dc8a69f 100644
--- a/archive.c
+++ b/archive.c
@@ -229,7 +229,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, int stage, void *context)
+		unsigned mode, void *context)
 {
 	struct archiver_context *c = context;
 
@@ -314,10 +314,10 @@ 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,
-				  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) {
@@ -375,7 +375,7 @@ struct path_exists_context {
 };
 
 static int reject_entry(const struct object_id *oid, struct strbuf *base,
-			const char *filename, unsigned mode, int stage,
+			const char *filename, unsigned mode,
 			void *context)
 {
 	int ret = -1;
@@ -403,9 +403,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, "",
-				  0, 0, &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 2d6550bc3c8..0e663905200 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,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, "", 0, 0,
-			    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 f67b67d80ed..980de590638 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) ? "/" : "");
@@ -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, "",
-					    0, 0, &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 aa153423b80..60a2913a01e 100644
--- a/builtin/ls-files.c
+++ b/builtin/ls-files.c
@@ -446,7 +446,7 @@ 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;
@@ -460,7 +460,7 @@ 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;
@@ -522,7 +522,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(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 7cad3f24ebd..3a442631c71 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, 0,
-				     &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 b69e694d986..ed31f9496cb 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,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, "", 0, 0,
-			    &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 f67c2153054..410e3b477e5 100644
--- a/tree.c
+++ b/tree.c
@@ -13,7 +13,6 @@ const char *tree_type = "tree";
 
 int read_tree_at(struct repository *r,
 		 struct tree *tree, struct strbuf *base,
-		 int stage,
 		 const struct pathspec *pathspec,
 		 read_tree_fn_t fn, void *context)
 {
@@ -39,7 +38,7 @@ int read_tree_at(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:
@@ -73,7 +72,7 @@ int read_tree_at(struct repository *r,
 		strbuf_add(base, entry.path, len);
 		strbuf_addch(base, '/');
 		retval = read_tree_at(r, lookup_tree(r, &oid),
-				      base, stage, pathspec,
+				      base, pathspec,
 				      fn, context);
 		strbuf_setlen(base, oldlen);
 		if (retval)
@@ -82,17 +81,13 @@ int read_tree_at(struct repository *r,
 	return 0;
 }
 
-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)
+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;
-
-	strbuf_add(&sb, base, baselen);
-	ret = read_tree_at(r, tree, &sb, stage, pathspec, fn, context);
+	int ret = read_tree_at(r, tree, &sb, pathspec, fn, context);
 	strbuf_release(&sb);
 	return ret;
 }
diff --git a/tree.h b/tree.h
index 123fc41efe6..6efff003e21 100644
--- a/tree.h
+++ b/tree.h
@@ -31,17 +31,16 @@ 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_at(struct repository *r,
 		 struct tree *tree, struct strbuf *base,
-		 int stage,
 		 const struct pathspec *pathspec,
 		 read_tree_fn_t fn, void *context);
 
-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);
+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.286.gc175f2cb894


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

* Re: [PATCH v5 0/8] read_tree() and read_tree_recursive() refactoring
  2021-03-20 22:37         ` [PATCH v5 0/8] " Ævar Arnfjörð Bjarmason
                             ` (7 preceding siblings ...)
  2021-03-20 22:37           ` [PATCH v5 8/8] tree.h API: simplify read_tree_recursive() signature Ævar Arnfjörð Bjarmason
@ 2021-03-20 23:08           ` Junio C Hamano
  8 siblings, 0 replies; 262+ messages in thread
From: Junio C Hamano @ 2021-03-20 23:08 UTC (permalink / raw)
  To: Ævar Arnfjörð Bjarmason; +Cc: git, Elijah Newren, Derrick Stolee

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

> A refactoring of v4[1], not quite as as suggested by Junio in[2], but
> which I think makes this whole thing less confusing and more
> straightforward.

Yeah, I admit that I gave only a cursory look, but the progression
presented in this round makes a lot of sense to me.

Thanks, will replace.

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

* [PATCH v4 00/29] tree-walk: mostly replace "mode" with "enum object_type"
  2021-03-16 15:57         ` [PATCH v3 00/32] " Ævar Arnfjörð Bjarmason
  2021-03-16 17:28           ` Elijah Newren
@ 2021-03-21  0:00           ` Ævar Arnfjörð Bjarmason
  2021-03-21  0:00             ` [PATCH v4 01/29] notes & match-trees: use name_entry's "pathlen" member Ævar Arnfjörð Bjarmason
                               ` (29 more replies)
  1 sibling, 30 replies; 262+ messages in thread
From: Ævar Arnfjörð Bjarmason @ 2021-03-21  0:00 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 re-roll of v3 of this series[1] and on top of (and requires) my
just-submitted v5 re-roll of the read_tree() refactoring series[2].

There was a regression in 1/32 of the old series. Removing the
canon_mode() call in diff.c didn't account for us needing to
canonicalize "diff --no-index" modes. There were no tests for this,
and it failed or not depending on the FS modes in the git.git checkout
being tested. This fixes the CI smoke coming from this series.

I plan to submit another set of patches to fix git diff --no-index's
test coverage, but for this series it was best to just eject it.

I'm confident that this is in a good shape now. There is now no
canon_mode() change in this series, just refactoring of
s/mode/object_type/g.

As discussed in earlier rounds the point of this prep series is to get
to a point where we can expose an API to fix long-standin blindspots
in fsck checks.

This is a long journey to get to that point, and isn't strictly
necessary to fix tht issue. But I think it's worth it since it leaves
the API use in a much better state where it's clear which things
actually require the mode bits, and which are just asking about the
object type of tree entries.

I dropped a couple of more patches to do with archive.c, in my
re-rolled [2] I'm now dealing with the "stage" parameter there, so
there's no need to do that here anymore.

1. https://lore.kernel.org/git/20210316155829.31242-1-avarab@gmail.com/
2. https://lore.kernel.org/git/xmqqy2ehctjo.fsf@gitster.g

Ævar Arnfjörð Bjarmason (29):
  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
  fast-import tests: test for sorting dir/file foo v.s. foo.txt
  mktree tests: test that "mode" is passed when sorting
  diff tests: test that "mode" is passed when sorting
  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 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()
  match-trees: 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                       | 29 ++++++-----
 blame.c                         |  9 ++--
 builtin/checkout.c              |  6 ++-
 builtin/fast-import.c           | 12 +++--
 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 +-
 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/t1450-fsck.sh                 | 66 ++++++++++++++++++++++++
 t/t4300-merge-tree.sh           | 44 ++++++++++++++++
 t/t8004-blame-with-conflicts.sh | 21 ++++++++
 t/t9300-fast-import.sh          | 87 ++++++++++++++++++++++++++++++++
 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 ++++----
 41 files changed, 606 insertions(+), 233 deletions(-)

Range-diff:
 1:  26bc38fbdd0 <  -:  ----------- diff.c: remove redundant canon_mode() call
 2:  8502cf8134b =  1:  0390b1e9ded notes & match-trees: use name_entry's "pathlen" member
 3:  68133fa6aaa =  2:  186f7a7a44b cache.h: add a comment to object_type()
 4:  9f714d6c01f =  3:  4fed508f3cb tree-walk.h: add object_type member to name_entry
 5:  6dbf2b0a6aa =  4:  c557b67231b tree-walk.c: migrate to using new "object_type" field when possible
 6:  354a8e9a2a1 =  5:  7016008554a fast-import tests: test for sorting dir/file foo v.s. foo.txt
 7:  e2331df28e1 =  6:  b0546197b1b mktree tests: test that "mode" is passed when sorting
 8:  9e9486c2ea0 =  7:  73e92ac187d diff tests: test that "mode" is passed when sorting
 9:  be5c713336a =  8:  1b6a10f814c cache.h: have base_name_compare() take "is tree?", not "mode"
10:  43623edddfb =  9:  f8912a409b5 tree-walk.h users: switch object_type(...) to new .object_type
11:  030898f884c ! 10:  df43f1a76ac tree.h: format argument lists of read_tree_recursive() users
    @@ 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,
    +-		int baselen, const char *filename, unsigned mode,
     -		void *context)
     +			       int baselen, const char *filename,
     +			       unsigned mode,
    -+			       int stage,
     +			       void *context)
      {
      	static struct strbuf path = STRBUF_INIT;
    @@ archive.c: static int write_directory(struct archiver_context *c)
     +					void *context)
      {
      	struct archiver_context *c = context;
    - 	int stage = 0;
    + 
     @@ archive.c: struct path_exists_context {
      };
      
    @@ tree.h: struct tree *parse_tree_indirect(const struct object_id *oid);
     +			      void *);
      
      int read_tree_at(struct repository *r,
    - 		 struct tree *tree,
    + 		 struct tree *tree, struct strbuf *base,
12:  0ce197950b0 <  -:  ----------- tree.h users: format argument lists in archive.c
13:  051c9f32ac6 <  -:  ----------- archive: get rid of 'stage' parameter
14:  bc73994b4c7 = 11:  152c6d88542 tree.h API: make read_tree_fn_t take an "enum object_type"
15:  e2b0964228f = 12:  1c2f65cb674 tree-walk.h users: migrate "p->mode &&" pattern
16:  29dbc4292e0 = 13:  163922d427c tree-walk.h users: refactor chained "mode" if/else into switch
17:  ada6d051769 = 14:  21df7c668be tree-walk.h users: migrate miscellaneous "mode" to "object_type"
18:  01860daa556 = 15:  592fecb7abc merge-tree tests: test for the mode comparison in same_entry()
19:  e4be48fb50f = 16:  092472f3c8d merge-ort: correct reference to test in 62fdec17a11
20:  189d2550fb8 = 17:  685da1abbdc fsck.c: switch on "object_type" in fsck_walk_tree()
21:  3b7b12e6f79 = 18:  4babecb7855 tree-walk.h users: use temporary variable(s) for "mode"
22:  6c3a07a3279 = 19:  7251654dd52 tree-walk.h API: formatting changes for subsequent commit
23:  879eb3da2a4 = 20:  9e521a3cbf2 tree-walk.h API: rename get_tree_entry() to get_tree_entry_mode()
24:  d2fa360ab9e = 21:  40f37e99cd9 match-trees: use "tmp" for mode in shift_tree_by()
25:  cc50cfcf517 = 22:  7f699bf2d5c tree-walk.h API: add get_tree_entry_type()
26:  f642a35482b = 23:  7ab7576cb16 tree-walk.h API: document and format tree_entry_extract()
27:  a0bcb59fa57 = 24:  a1bd81d64aa tree-entry.h API: rename tree_entry_extract() to tree_entry_extract_mode()
28:  c7d4ba77340 = 25:  ce7c19ad39c tree-walk.h API: add a tree_entry_extract_all() function
29:  1d5421d67af = 26:  95eec961be8 tree-walk.h API: add get_tree_entry_all()
30:  a3e1063ac45 = 27:  a2a34fd3e2d tree-walk.h API: add a get_tree_entry_path() function
31:  da3dd6dd532 = 28:  81da5490221 blame: emit a better error on 'git blame directory'
32:  80e5cb0b30c = 29:  4d51da4ea39 tree-walk.h API: add a tree_entry_extract_type() function
-- 
2.31.0.286.gc175f2cb894


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

* [PATCH v4 01/29] notes & match-trees: use name_entry's "pathlen" member
  2021-03-21  0:00           ` [PATCH v4 00/29] " Ævar Arnfjörð Bjarmason
@ 2021-03-21  0:00             ` Ævar Arnfjörð Bjarmason
  2021-03-21  0:00             ` [PATCH v4 02/29] cache.h: add a comment to object_type() Ævar Arnfjörð Bjarmason
                               ` (28 subsequent siblings)
  29 siblings, 0 replies; 262+ messages in thread
From: Ævar Arnfjörð Bjarmason @ 2021-03-21  0:00 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 a19e4ad7943..e2fec12a39e 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.286.gc175f2cb894


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

* [PATCH v4 02/29] cache.h: add a comment to object_type()
  2021-03-21  0:00           ` [PATCH v4 00/29] " Ævar Arnfjörð Bjarmason
  2021-03-21  0:00             ` [PATCH v4 01/29] notes & match-trees: use name_entry's "pathlen" member Ævar Arnfjörð Bjarmason
@ 2021-03-21  0:00             ` Ævar Arnfjörð Bjarmason
  2021-03-21  0:00             ` [PATCH v4 03/29] tree-walk.h: add object_type member to name_entry Ævar Arnfjörð Bjarmason
                               ` (27 subsequent siblings)
  29 siblings, 0 replies; 262+ messages in thread
From: Ævar Arnfjörð Bjarmason @ 2021-03-21  0:00 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.286.gc175f2cb894


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

* [PATCH v4 03/29] tree-walk.h: add object_type member to name_entry
  2021-03-21  0:00           ` [PATCH v4 00/29] " Ævar Arnfjörð Bjarmason
  2021-03-21  0:00             ` [PATCH v4 01/29] notes & match-trees: use name_entry's "pathlen" member Ævar Arnfjörð Bjarmason
  2021-03-21  0:00             ` [PATCH v4 02/29] cache.h: add a comment to object_type() Ævar Arnfjörð Bjarmason
@ 2021-03-21  0:00             ` Ævar Arnfjörð Bjarmason
  2021-03-21  0:00             ` [PATCH v4 04/29] tree-walk.c: migrate to using new "object_type" field when possible Ævar Arnfjörð Bjarmason
                               ` (26 subsequent siblings)
  29 siblings, 0 replies; 262+ messages in thread
From: Ævar Arnfjörð Bjarmason @ 2021-03-21  0:00 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.286.gc175f2cb894


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

* [PATCH v4 04/29] tree-walk.c: migrate to using new "object_type" field when possible
  2021-03-21  0:00           ` [PATCH v4 00/29] " Ævar Arnfjörð Bjarmason
                               ` (2 preceding siblings ...)
  2021-03-21  0:00             ` [PATCH v4 03/29] tree-walk.h: add object_type member to name_entry Ævar Arnfjörð Bjarmason
@ 2021-03-21  0:00             ` Ævar Arnfjörð Bjarmason
  2021-03-21  0:00             ` [PATCH v4 05/29] fast-import tests: test for sorting dir/file foo v.s. foo.txt Ævar Arnfjörð Bjarmason
                               ` (25 subsequent siblings)
  29 siblings, 0 replies; 262+ messages in thread
From: Ævar Arnfjörð Bjarmason @ 2021-03-21  0:00 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.286.gc175f2cb894


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

* [PATCH v4 05/29] fast-import tests: test for sorting dir/file foo v.s. foo.txt
  2021-03-21  0:00           ` [PATCH v4 00/29] " Ævar Arnfjörð Bjarmason
                               ` (3 preceding siblings ...)
  2021-03-21  0:00             ` [PATCH v4 04/29] tree-walk.c: migrate to using new "object_type" field when possible Ævar Arnfjörð Bjarmason
@ 2021-03-21  0:00             ` Ævar Arnfjörð Bjarmason
  2021-03-21  0:00             ` [PATCH v4 06/29] mktree tests: test that "mode" is passed when sorting Ævar Arnfjörð Bjarmason
                               ` (24 subsequent siblings)
  29 siblings, 0 replies; 262+ messages in thread
From: Ævar Arnfjörð Bjarmason @ 2021-03-21  0:00 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 missing test for the sorting of "foo" v.s. "foo.txt" where "foo"
can be either a file or a directory. If it's a file then "foo" should
sort before "foo.txt", and the other way around if "foo" is a
directory.

See [1] for a reply to a patch of mine introducing such a
regression. We now finally have a test for this code added back in
463acbe1c6 (Added tree and commit writing to fast-import.,
2006-08-14).

This tests both the tecmp1() and tecmp0() functions introduced inn
4cabf8583f (Implemented tree delta compression in fast-import.,
2006-08-28).

This will catch cases where the "mode" is the same, or reversed
between a & b in both functions.

There was an existing test for the tecmp1() function(s) just above
this one added here.

That existing test was added in e741130386 (New fast-import test case
for valid tree sorting, 2007-03-12) and would catch cases where
entries were reversed, but not if their mode (or rather, type) was the
the same or otherwise wrong value.

There were no tests at all for the tecmp0() function. As with the
tecmp1() test the new test will catch cases where the "mode" is the
same (e.g. "1"), or if the two are reversed. It won't catch a "return
0" from the function (i.e. already sorted), that case requires
tecmp1() to also be broken.

1. https://lore.kernel.org/git/CABPp-BEZfG_pNNTWsnxEa1xG+kgpQfpXj=KHBkCBAMikrXj-aA@mail.gmail.com/

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

diff --git a/t/t9300-fast-import.sh b/t/t9300-fast-import.sh
index 5c47ac4465c..8bafb8cc515 100755
--- a/t/t9300-fast-import.sh
+++ b/t/t9300-fast-import.sh
@@ -955,6 +955,93 @@ test_expect_success 'L: verify internal tree sorting' '
 	test_cmp expect actual
 '
 
+test_expect_success 'L: verify internal tree sorting on bad input (tecmp1)' '
+	test_create_repo L1-0 &&
+
+	cat >input <<-INPUT_END &&
+	blob
+	mark :1
+	data 0
+
+	reset refs/heads/L1-0
+	commit refs/heads/L1-0
+	committer $GIT_COMMITTER_NAME <$GIT_COMMITTER_EMAIL> $GIT_COMMITTER_DATE
+	data <<COMMIT
+	create L1-0
+	COMMIT
+	M 100644 :1 x.txt
+	M 100644 :1 x/y.txt
+	M 100644 :1 z.txt
+	M 100644 :1 z
+	INPUT_END
+
+	cat >expected <<-EXPECT_END &&
+	x.txt
+	x
+	z
+	z.txt
+	EXPECT_END
+
+	git -C L1-0 fast-import <input &&
+	git -C L1-0 ls-tree L1-0 >tmp &&
+	cut -f 2 <tmp >actual &&
+	test_cmp expected actual &&
+	git -C L1-0 fsck 2>err &&
+	# Would happen if tecmp1() were broken
+	! grep "error in tree .*: treeNotSorted: " err
+'
+
+test_expect_success 'L: verify internal tree sorting on bad input (tecmp0)' '
+
+	test_create_repo L1-1 &&
+
+	cat >input <<-INPUT_END &&
+	blob
+	mark :1
+	data <<EOF
+	some data
+	EOF
+
+	reset refs/heads/L1-1
+	commit refs/heads/L1-1
+	committer $GIT_COMMITTER_NAME <$GIT_COMMITTER_EMAIL> $GIT_COMMITTER_DATE
+	data <<COMMIT
+	create L1-1
+	COMMIT
+	M 100644 :1 x.txt
+	M 100644 :1 x/y.txt
+	M 100644 :1 z.txt
+	M 100644 :1 z
+
+	commit refs/heads/L1-1
+	committer $GIT_COMMITTER_NAME <$GIT_COMMITTER_EMAIL> $GIT_COMMITTER_DATE
+	data <<COMMIT
+	update L1-1
+	COMMIT
+	M 100644 :1 another.txt
+	M 100644 :1 x.txt
+	M 100644 :1 x/y.txt
+	M 100644 :1 z.txt
+	M 100644 :1 z
+	INPUT_END
+
+	cat >expected <<-EXPECT_END &&
+	another.txt
+	x.txt
+	x
+	z
+	z.txt
+	EXPECT_END
+
+	git -C L1-1 fast-import <input &&
+	git -C L1-1 ls-tree L1-1 >tmp 2>err &&
+	# Would happen if tecmp0() passed a fixed mode
+	! grep "fatal: not a tree object" err &&
+	cut -f 2 <tmp >actual &&
+	test_cmp expected actual &&
+	git -C L1-1 fsck
+'
+
 test_expect_success 'L: nested tree copy does not corrupt deltas' '
 	cat >input <<-INPUT_END &&
 	blob
-- 
2.31.0.286.gc175f2cb894


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

* [PATCH v4 06/29] mktree tests: test that "mode" is passed when sorting
  2021-03-21  0:00           ` [PATCH v4 00/29] " Ævar Arnfjörð Bjarmason
                               ` (4 preceding siblings ...)
  2021-03-21  0:00             ` [PATCH v4 05/29] fast-import tests: test for sorting dir/file foo v.s. foo.txt Ævar Arnfjörð Bjarmason
@ 2021-03-21  0:00             ` Ævar Arnfjörð Bjarmason
  2021-03-21  0:00             ` [PATCH v4 07/29] diff " Ævar Arnfjörð Bjarmason
                               ` (23 subsequent siblings)
  29 siblings, 0 replies; 262+ messages in thread
From: Ævar Arnfjörð Bjarmason @ 2021-03-21  0:00 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 for the mode being passed to ent_compare(). That code dates
back to 83f50539a9 (git-mktree: reverse of git-ls-tree., 2006-02-20)
and there's never been a test for that particular edge case. Now we
have one.

I don't see how anything could run into this in practice. In order for
that mode sorting to matter as a tiebreaker we need to have a
duplicate entry in the tree, i.e. two "foo" entries, one a blob and
one a tree. This asserts that if that happens we'll sort on the modes
we encounter in such an invalid entry, i.e. we expect the tree entry
before the blob.

As shown here we'd need to disable the fsck.duplicateEntries error to
get to the point of running "mktree", so I doubt anyone's pushing this
sort of data around.

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

diff --git a/t/t1450-fsck.sh b/t/t1450-fsck.sh
index 5071ac63a5b..46125190b45 100755
--- a/t/t1450-fsck.sh
+++ b/t/t1450-fsck.sh
@@ -318,6 +318,50 @@ test_expect_success 'tree entry with type mismatch' '
 	test_i18ngrep ! "dangling blob" out
 '
 
+test_expect_success 'tree entry with duplicate type mismatching objects' '
+	test_create_repo duplicate-entry &&
+	(
+		cd duplicate-entry &&
+		blob="$(printf "foo" | git hash-object -w --stdin)" &&
+		tree="$(printf "100644 blob $blob\tfoo" | git mktree)" &&
+		commit="$(git commit-tree $tree -m "first commit")" &&
+		git cat-file commit $commit >good-commit &&
+
+		# First bad commit, wrong type, but in the right order
+		printf "40000 A\0$(echo $tree | hex2oct)" >broken-tree-A &&
+		printf "100644 A\0$(echo $blob | hex2oct)" >broken-tree-B &&
+		cat broken-tree-A broken-tree-B >broken-tree.1 &&
+		broken_tree1="$(git hash-object -w --literally -t tree broken-tree.1)" &&
+		bad_commit1="$(git commit-tree $broken_tree1 -m "bad commit 1")" &&
+		git cat-file commit $bad_commit1 >bad-commit.1 &&
+		git update-ref refs/heads/broken-commit-1 $bad_commit1 &&
+
+		test_must_fail git fsck &&
+		git -c fsck.duplicateEntries=warn fsck 2>err &&
+		grep " in tree .*$broken_tree1: duplicateEntries" err &&
+
+		# Second bad commits, wrong types and order
+		cat broken-tree-B broken-tree-A >broken-tree.2 &&
+		broken_tree2="$(git hash-object -w --literally -t tree broken-tree.2)" &&
+		bad_commit2="$(git commit-tree $broken_tree2 -m "bad commit 2")" &&
+		git cat-file commit $bad_commit2 >bad-commit.2 &&
+		git update-ref refs/heads/broken-commit-2 $bad_commit2 &&
+
+		test_must_fail git fsck &&
+		git -c fsck.duplicateEntries=warn fsck 2>err &&
+		grep " in tree .*$broken_tree2: duplicateEntries" err &&
+
+		# git mktree should "fix" the order of this already broken data
+		git ls-tree broken-commit-1 >broken-tree-1-ls &&
+		git ls-tree broken-commit-2 >broken-tree-2-ls &&
+		! test_cmp broken-tree-1-ls broken-tree-2-ls &&
+
+		git mktree <broken-tree-1-ls >broken-mktree-1 &&
+		git mktree <broken-tree-2-ls >broken-mktree-2 &&
+		test_cmp broken-mktree-1 broken-mktree-2
+	)
+'
+
 test_expect_success 'tag pointing to nonexistent' '
 	badoid=$(test_oid deadbeef) &&
 	cat >invalid-tag <<-EOF &&
-- 
2.31.0.286.gc175f2cb894


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

* [PATCH v4 07/29] diff tests: test that "mode" is passed when sorting
  2021-03-21  0:00           ` [PATCH v4 00/29] " Ævar Arnfjörð Bjarmason
                               ` (5 preceding siblings ...)
  2021-03-21  0:00             ` [PATCH v4 06/29] mktree tests: test that "mode" is passed when sorting Ævar Arnfjörð Bjarmason
@ 2021-03-21  0:00             ` Ævar Arnfjörð Bjarmason
  2021-03-21  0:00             ` [PATCH v4 08/29] cache.h: have base_name_compare() take "is tree?", not "mode" Ævar Arnfjörð Bjarmason
                               ` (22 subsequent siblings)
  29 siblings, 0 replies; 262+ messages in thread
From: Ævar Arnfjörð Bjarmason @ 2021-03-21  0:00 UTC (permalink / raw)
  To: git
  Cc: Junio C Hamano, Elijah Newren, Kirill Smelkov,
	Nguyễn Thái Ngọc Duy,
	Ævar Arnfjörð Bjarmason

Piggy-back on the recently added fsck tests for mode comparisons in
mktree and assert that diff-tree also does the right thing in this
implausible scenario.

As with the other tests I've added in preceding commits, these tests
will fail if the mode is the same or reversed, respectively.

The diff-tree code being tested here was originally added back in
.9174026cfe (Add "diff-tree" program to show which files have changed
between two trees., 2005-04-09).

Unlike the other tests I've added there are existing tests for both of
these scenarios. Breaking that function as described above will make
tests in t4002-diff-basic.sh, t6409-merge-subtree.sh and
t4037-diff-r-t-dirs.sh fail.

I think it's good to have tests for this regardless, so let's add
these.

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

diff --git a/t/t1450-fsck.sh b/t/t1450-fsck.sh
index 46125190b45..5dd842bb82c 100755
--- a/t/t1450-fsck.sh
+++ b/t/t1450-fsck.sh
@@ -362,6 +362,28 @@ test_expect_success 'tree entry with duplicate type mismatching objects' '
 	)
 '
 
+test_expect_success 'diff-tree stressing tree-diff.c::tree_entry_pathcmp(), not the same type' '
+	zero=$(test_oid zero) &&
+	git -C duplicate-entry diff-tree broken-commit-1 broken-commit-2 >1-to-2 &&
+	grep "$zero" 1-to-2 >lines &&
+	test_line_count = 2 lines &&
+
+	git -C duplicate-entry diff-tree broken-commit-2 broken-commit-1 >2-to-1 &&
+	grep "$zero" 2-to-1 >lines &&
+	test_line_count = 2 lines
+'
+
+test_expect_success 'diff-tree stressing tree-diff.c::tree_entry_pathcmp(), types not reversed' '
+	blob_ok=$(git -C duplicate-entry rev-parse broken-commit-2:A) &&
+	git -C duplicate-entry diff-tree --diff-filter=A broken-commit-1 broken-commit-2 >1-to-2 &&
+	grep "$blob_ok" 1-to-2 &&
+	test_line_count = 1 1-to-2 &&
+
+	git -C duplicate-entry diff-tree --diff-filter=A broken-commit-2 broken-commit-1 >2-to-1 &&
+	grep "$blob_ok" 2-to-1 &&
+	test_line_count = 1 2-to-1
+'
+
 test_expect_success 'tag pointing to nonexistent' '
 	badoid=$(test_oid deadbeef) &&
 	cat >invalid-tag <<-EOF &&
-- 
2.31.0.286.gc175f2cb894


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

* [PATCH v4 08/29] cache.h: have base_name_compare() take "is tree?", not "mode"
  2021-03-21  0:00           ` [PATCH v4 00/29] " Ævar Arnfjörð Bjarmason
                               ` (6 preceding siblings ...)
  2021-03-21  0:00             ` [PATCH v4 07/29] diff " Ævar Arnfjörð Bjarmason
@ 2021-03-21  0:00             ` Ævar Arnfjörð Bjarmason
  2021-03-21  0:00             ` [PATCH v4 09/29] tree-walk.h users: switch object_type(...) to new .object_type Ævar Arnfjörð Bjarmason
                               ` (21 subsequent siblings)
  29 siblings, 0 replies; 262+ messages in thread
From: Ævar Arnfjörð Bjarmason @ 2021-03-21  0:00 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).

None of these comparison functions used to have tests, but with
preceding commits some of them now do. I thought the remainder was
trivial enough to review without tests, and didn't want to spend more
time on them.

Signed-off-by: Ævar Arnfjörð Bjarmason <avarab@gmail.com>
---
 builtin/fast-import.c | 12 ++++++++----
 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, 47 insertions(+), 35 deletions(-)

diff --git a/builtin/fast-import.c b/builtin/fast-import.c
index 3afa81cf9ac..2fb56d6e9b7 100644
--- a/builtin/fast-import.c
+++ b/builtin/fast-import.c
@@ -1287,18 +1287,22 @@ 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);
+	int istree_a = S_ISDIR(a->versions[0].mode);
+	int istree_b = S_ISDIR(b->versions[0].mode);
 	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, istree_a,
+		b->name->str_dat, b->name->str_len, istree_b);
 }
 
 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);
+	int istree_a = S_ISDIR(a->versions[1].mode);
+	int istree_b = S_ISDIR(b->versions[1].mode);
 	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, istree_a,
+		b->name->str_dat, b->name->str_len, istree_b);
 }
 
 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 06635f91bc2..155d52971e6 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 92dea35e57a..68eaa8f294f 100644
--- a/merge-ort.c
+++ b/merge-ort.c
@@ -2389,8 +2389,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 ed31f9496cb..97520a88646 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 5a907af2fb5..6e0b41ed175 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 9298fe1d9b3..ea1ce7894ba 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.286.gc175f2cb894


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

* [PATCH v4 09/29] tree-walk.h users: switch object_type(...) to new .object_type
  2021-03-21  0:00           ` [PATCH v4 00/29] " Ævar Arnfjörð Bjarmason
                               ` (7 preceding siblings ...)
  2021-03-21  0:00             ` [PATCH v4 08/29] cache.h: have base_name_compare() take "is tree?", not "mode" Ævar Arnfjörð Bjarmason
@ 2021-03-21  0:00             ` Ævar Arnfjörð Bjarmason
  2021-03-21  0:00             ` [PATCH v4 10/29] tree.h: format argument lists of read_tree_recursive() users Ævar Arnfjörð Bjarmason
                               ` (20 subsequent siblings)
  29 siblings, 0 replies; 262+ messages in thread
From: Ævar Arnfjörð Bjarmason @ 2021-03-21  0:00 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 4bb602688c1..12fcbb3b8d4 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 b60d5fcc85d..aeb011de8d4 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 99c859f7971..aba74cb65a2 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.286.gc175f2cb894


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

* [PATCH v4 10/29] tree.h: format argument lists of read_tree_recursive() users
  2021-03-21  0:00           ` [PATCH v4 00/29] " Ævar Arnfjörð Bjarmason
                               ` (8 preceding siblings ...)
  2021-03-21  0:00             ` [PATCH v4 09/29] tree-walk.h users: switch object_type(...) to new .object_type Ævar Arnfjörð Bjarmason
@ 2021-03-21  0:00             ` Ævar Arnfjörð Bjarmason
  2021-03-21  0:00             ` [PATCH v4 11/29] tree.h API: make read_tree_fn_t take an "enum object_type" Ævar Arnfjörð Bjarmason
                               ` (19 subsequent siblings)
  29 siblings, 0 replies; 262+ messages in thread
From: Ævar Arnfjörð Bjarmason @ 2021-03-21  0:00 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 4921dc8a69f..feed5c02fb2 100644
--- a/archive.c
+++ b/archive.c
@@ -137,8 +137,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,
-		void *context)
+			       int baselen, const char *filename,
+			       unsigned mode,
+			       void *context)
 {
 	static struct strbuf path = STRBUF_INIT;
 	struct archiver_context *c = context;
@@ -228,8 +229,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;
 
@@ -375,7 +377,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 97520a88646..57198b29fe7 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 6efff003e21..10c8637ab3e 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, struct strbuf *base,
-- 
2.31.0.286.gc175f2cb894


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

* [PATCH v4 11/29] tree.h API: make read_tree_fn_t take an "enum object_type"
  2021-03-21  0:00           ` [PATCH v4 00/29] " Ævar Arnfjörð Bjarmason
                               ` (9 preceding siblings ...)
  2021-03-21  0:00             ` [PATCH v4 10/29] tree.h: format argument lists of read_tree_recursive() users Ævar Arnfjörð Bjarmason
@ 2021-03-21  0:00             ` Ævar Arnfjörð Bjarmason
  2021-03-21  0:00             ` [PATCH v4 12/29] tree-walk.h users: migrate "p->mode &&" pattern Ævar Arnfjörð Bjarmason
                               ` (18 subsequent siblings)
  29 siblings, 0 replies; 262+ messages in thread
From: Ævar Arnfjörð Bjarmason @ 2021-03-21  0:00 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 feed5c02fb2..ca28d6ca3b8 100644
--- a/archive.c
+++ b/archive.c
@@ -230,7 +230,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;
@@ -243,7 +243,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;
 
@@ -378,13 +378,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 60a2913a01e..cb217870cbd 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 57198b29fe7..6bc1e659a7b 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 410e3b477e5..f48b170090f 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 10c8637ab3e..1675da7e85c 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.286.gc175f2cb894


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

* [PATCH v4 12/29] tree-walk.h users: migrate "p->mode &&" pattern
  2021-03-21  0:00           ` [PATCH v4 00/29] " Ævar Arnfjörð Bjarmason
                               ` (10 preceding siblings ...)
  2021-03-21  0:00             ` [PATCH v4 11/29] tree.h API: make read_tree_fn_t take an "enum object_type" Ævar Arnfjörð Bjarmason
@ 2021-03-21  0:00             ` Ævar Arnfjörð Bjarmason
  2021-03-21  0:00             ` [PATCH v4 13/29] tree-walk.h users: refactor chained "mode" if/else into switch Ævar Arnfjörð Bjarmason
                               ` (17 subsequent siblings)
  29 siblings, 0 replies; 262+ messages in thread
From: Ævar Arnfjörð Bjarmason @ 2021-03-21  0:00 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 68eaa8f294f..052231efdb2 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 ea1ce7894ba..e6cb505fcb0 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.286.gc175f2cb894


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

* [PATCH v4 13/29] tree-walk.h users: refactor chained "mode" if/else into switch
  2021-03-21  0:00           ` [PATCH v4 00/29] " Ævar Arnfjörð Bjarmason
                               ` (11 preceding siblings ...)
  2021-03-21  0:00             ` [PATCH v4 12/29] tree-walk.h users: migrate "p->mode &&" pattern Ævar Arnfjörð Bjarmason
@ 2021-03-21  0:00             ` Ævar Arnfjörð Bjarmason
  2021-03-21  0:00             ` [PATCH v4 14/29] tree-walk.h users: migrate miscellaneous "mode" to "object_type" Ævar Arnfjörð Bjarmason
                               ` (16 subsequent siblings)
  29 siblings, 0 replies; 262+ messages in thread
From: Ævar Arnfjörð Bjarmason @ 2021-03-21  0:00 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.286.gc175f2cb894


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

* [PATCH v4 14/29] tree-walk.h users: migrate miscellaneous "mode" to "object_type"
  2021-03-21  0:00           ` [PATCH v4 00/29] " Ævar Arnfjörð Bjarmason
                               ` (12 preceding siblings ...)
  2021-03-21  0:00             ` [PATCH v4 13/29] tree-walk.h users: refactor chained "mode" if/else into switch Ævar Arnfjörð Bjarmason
@ 2021-03-21  0:00             ` Ævar Arnfjörð Bjarmason
  2021-03-21  0:00             ` [PATCH v4 15/29] merge-tree tests: test for the mode comparison in same_entry() Ævar Arnfjörð Bjarmason
                               ` (15 subsequent siblings)
  29 siblings, 0 replies; 262+ messages in thread
From: Ævar Arnfjörð Bjarmason @ 2021-03-21  0:00 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 ccd8d08f3dd..6349bbf59ee 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 12fcbb3b8d4..6079d1d7935 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 add1f077131..c15a6829585 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 e2fec12a39e..8b03ace52bf 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 e6cb505fcb0..72b2cf5a741 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.286.gc175f2cb894


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

* [PATCH v4 15/29] merge-tree tests: test for the mode comparison in same_entry()
  2021-03-21  0:00           ` [PATCH v4 00/29] " Ævar Arnfjörð Bjarmason
                               ` (13 preceding siblings ...)
  2021-03-21  0:00             ` [PATCH v4 14/29] tree-walk.h users: migrate miscellaneous "mode" to "object_type" Ævar Arnfjörð Bjarmason
@ 2021-03-21  0:00             ` Ævar Arnfjörð Bjarmason
  2021-03-21  0:00             ` [PATCH v4 16/29] merge-ort: correct reference to test in 62fdec17a11 Ævar Arnfjörð Bjarmason
                               ` (14 subsequent siblings)
  29 siblings, 0 replies; 262+ messages in thread
From: Ævar Arnfjörð Bjarmason @ 2021-03-21  0:00 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.286.gc175f2cb894


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

* [PATCH v4 16/29] merge-ort: correct reference to test in 62fdec17a11
  2021-03-21  0:00           ` [PATCH v4 00/29] " Ævar Arnfjörð Bjarmason
                               ` (14 preceding siblings ...)
  2021-03-21  0:00             ` [PATCH v4 15/29] merge-tree tests: test for the mode comparison in same_entry() Ævar Arnfjörð Bjarmason
@ 2021-03-21  0:00             ` Ævar Arnfjörð Bjarmason
  2021-03-21  0:00             ` [PATCH v4 17/29] fsck.c: switch on "object_type" in fsck_walk_tree() Ævar Arnfjörð Bjarmason
                               ` (13 subsequent siblings)
  29 siblings, 0 replies; 262+ messages in thread
From: Ævar Arnfjörð Bjarmason @ 2021-03-21  0:00 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 052231efdb2..c9047e279c6 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.286.gc175f2cb894


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

* [PATCH v4 17/29] fsck.c: switch on "object_type" in fsck_walk_tree()
  2021-03-21  0:00           ` [PATCH v4 00/29] " Ævar Arnfjörð Bjarmason
                               ` (15 preceding siblings ...)
  2021-03-21  0:00             ` [PATCH v4 16/29] merge-ort: correct reference to test in 62fdec17a11 Ævar Arnfjörð Bjarmason
@ 2021-03-21  0:00             ` Ævar Arnfjörð Bjarmason
  2021-03-21  0:00             ` [PATCH v4 18/29] tree-walk.h users: use temporary variable(s) for "mode" Ævar Arnfjörð Bjarmason
                               ` (12 subsequent siblings)
  29 siblings, 0 replies; 262+ messages in thread
From: Ævar Arnfjörð Bjarmason @ 2021-03-21  0:00 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.286.gc175f2cb894


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

* [PATCH v4 18/29] tree-walk.h users: use temporary variable(s) for "mode"
  2021-03-21  0:00           ` [PATCH v4 00/29] " Ævar Arnfjörð Bjarmason
                               ` (16 preceding siblings ...)
  2021-03-21  0:00             ` [PATCH v4 17/29] fsck.c: switch on "object_type" in fsck_walk_tree() Ævar Arnfjörð Bjarmason
@ 2021-03-21  0:00             ` Ævar Arnfjörð Bjarmason
  2021-03-21  0:00             ` [PATCH v4 19/29] tree-walk.h API: formatting changes for subsequent commit Ævar Arnfjörð Bjarmason
                               ` (11 subsequent siblings)
  29 siblings, 0 replies; 262+ messages in thread
From: Ævar Arnfjörð Bjarmason @ 2021-03-21  0:00 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 c9047e279c6..4ef03e605a3 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 8b03ace52bf..970650431fb 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 72b2cf5a741..4653e61c3e3 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.286.gc175f2cb894


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

* [PATCH v4 19/29] tree-walk.h API: formatting changes for subsequent commit
  2021-03-21  0:00           ` [PATCH v4 00/29] " Ævar Arnfjörð Bjarmason
                               ` (17 preceding siblings ...)
  2021-03-21  0:00             ` [PATCH v4 18/29] tree-walk.h users: use temporary variable(s) for "mode" Ævar Arnfjörð Bjarmason
@ 2021-03-21  0:00             ` Ævar Arnfjörð Bjarmason
  2021-03-21  0:00             ` [PATCH v4 20/29] tree-walk.h API: rename get_tree_entry() to get_tree_entry_mode() Ævar Arnfjörð Bjarmason
                               ` (10 subsequent siblings)
  29 siblings, 0 replies; 262+ messages in thread
From: Ævar Arnfjörð Bjarmason @ 2021-03-21  0:00 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 5018bb8fb2c..6ed1520e619 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.286.gc175f2cb894


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

* [PATCH v4 20/29] tree-walk.h API: rename get_tree_entry() to get_tree_entry_mode()
  2021-03-21  0:00           ` [PATCH v4 00/29] " Ævar Arnfjörð Bjarmason
                               ` (18 preceding siblings ...)
  2021-03-21  0:00             ` [PATCH v4 19/29] tree-walk.h API: formatting changes for subsequent commit Ævar Arnfjörð Bjarmason
@ 2021-03-21  0:00             ` Ævar Arnfjörð Bjarmason
  2021-03-21  0:00             ` [PATCH v4 21/29] match-trees: use "tmp" for mode in shift_tree_by() Ævar Arnfjörð Bjarmason
                               ` (9 subsequent siblings)
  29 siblings, 0 replies; 262+ messages in thread
From: Ævar Arnfjörð Bjarmason @ 2021-03-21  0:00 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 ca28d6ca3b8..14f8e694596 100644
--- a/archive.c
+++ b/archive.c
@@ -478,10 +478,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 6ed1520e619..13825b86e65 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 51d93310a4d..d8ba9229212 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 6bc1e659a7b..f5cccb8deab 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);
 }
 
 /*
@@ -2540,11 +2540,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 970650431fb..b7a5ddce3ae 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.286.gc175f2cb894


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

* [PATCH v4 21/29] match-trees: use "tmp" for mode in shift_tree_by()
  2021-03-21  0:00           ` [PATCH v4 00/29] " Ævar Arnfjörð Bjarmason
                               ` (19 preceding siblings ...)
  2021-03-21  0:00             ` [PATCH v4 20/29] tree-walk.h API: rename get_tree_entry() to get_tree_entry_mode() Ævar Arnfjörð Bjarmason
@ 2021-03-21  0:00             ` Ævar Arnfjörð Bjarmason
  2021-03-21  0:00             ` [PATCH v4 22/29] tree-walk.h API: add get_tree_entry_type() Ævar Arnfjörð Bjarmason
                               ` (8 subsequent siblings)
  29 siblings, 0 replies; 262+ messages in thread
From: Ævar Arnfjörð Bjarmason @ 2021-03-21  0:00 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.286.gc175f2cb894


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

* [PATCH v4 22/29] tree-walk.h API: add get_tree_entry_type()
  2021-03-21  0:00           ` [PATCH v4 00/29] " Ævar Arnfjörð Bjarmason
                               ` (20 preceding siblings ...)
  2021-03-21  0:00             ` [PATCH v4 21/29] match-trees: use "tmp" for mode in shift_tree_by() Ævar Arnfjörð Bjarmason
@ 2021-03-21  0:00             ` Ævar Arnfjörð Bjarmason
  2021-03-21  0:00             ` [PATCH v4 23/29] tree-walk.h API: document and format tree_entry_extract() Ævar Arnfjörð Bjarmason
                               ` (7 subsequent siblings)
  29 siblings, 0 replies; 262+ messages in thread
From: Ævar Arnfjörð Bjarmason @ 2021-03-21  0:00 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 14f8e694596..fb2791f4328 100644
--- a/archive.c
+++ b/archive.c
@@ -475,14 +475,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.286.gc175f2cb894


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

* [PATCH v4 23/29] tree-walk.h API: document and format tree_entry_extract()
  2021-03-21  0:00           ` [PATCH v4 00/29] " Ævar Arnfjörð Bjarmason
                               ` (21 preceding siblings ...)
  2021-03-21  0:00             ` [PATCH v4 22/29] tree-walk.h API: add get_tree_entry_type() Ævar Arnfjörð Bjarmason
@ 2021-03-21  0:00             ` Ævar Arnfjörð Bjarmason
  2021-03-21  0:00             ` [PATCH v4 24/29] tree-entry.h API: rename tree_entry_extract() to tree_entry_extract_mode() Ævar Arnfjörð Bjarmason
                               ` (6 subsequent siblings)
  29 siblings, 0 replies; 262+ messages in thread
From: Ævar Arnfjörð Bjarmason @ 2021-03-21  0:00 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.286.gc175f2cb894


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

* [PATCH v4 24/29] tree-entry.h API: rename tree_entry_extract() to tree_entry_extract_mode()
  2021-03-21  0:00           ` [PATCH v4 00/29] " Ævar Arnfjörð Bjarmason
                               ` (22 preceding siblings ...)
  2021-03-21  0:00             ` [PATCH v4 23/29] tree-walk.h API: document and format tree_entry_extract() Ævar Arnfjörð Bjarmason
@ 2021-03-21  0:00             ` Ævar Arnfjörð Bjarmason
  2021-03-21  0:00             ` [PATCH v4 25/29] tree-walk.h API: add a tree_entry_extract_all() function Ævar Arnfjörð Bjarmason
                               ` (5 subsequent siblings)
  29 siblings, 0 replies; 262+ messages in thread
From: Ævar Arnfjörð Bjarmason @ 2021-03-21  0:00 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.286.gc175f2cb894


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

* [PATCH v4 25/29] tree-walk.h API: add a tree_entry_extract_all() function
  2021-03-21  0:00           ` [PATCH v4 00/29] " Ævar Arnfjörð Bjarmason
                               ` (23 preceding siblings ...)
  2021-03-21  0:00             ` [PATCH v4 24/29] tree-entry.h API: rename tree_entry_extract() to tree_entry_extract_mode() Ævar Arnfjörð Bjarmason
@ 2021-03-21  0:00             ` Ævar Arnfjörð Bjarmason
  2021-03-21  0:00             ` [PATCH v4 26/29] tree-walk.h API: add get_tree_entry_all() Ævar Arnfjörð Bjarmason
                               ` (4 subsequent siblings)
  29 siblings, 0 replies; 262+ messages in thread
From: Ævar Arnfjörð Bjarmason @ 2021-03-21  0:00 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.286.gc175f2cb894


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

* [PATCH v4 26/29] tree-walk.h API: add get_tree_entry_all()
  2021-03-21  0:00           ` [PATCH v4 00/29] " Ævar Arnfjörð Bjarmason
                               ` (24 preceding siblings ...)
  2021-03-21  0:00             ` [PATCH v4 25/29] tree-walk.h API: add a tree_entry_extract_all() function Ævar Arnfjörð Bjarmason
@ 2021-03-21  0:00             ` Ævar Arnfjörð Bjarmason
  2021-03-21  0:01             ` [PATCH v4 27/29] tree-walk.h API: add a get_tree_entry_path() function Ævar Arnfjörð Bjarmason
                               ` (3 subsequent siblings)
  29 siblings, 0 replies; 262+ messages in thread
From: Ævar Arnfjörð Bjarmason @ 2021-03-21  0:00 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.286.gc175f2cb894


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

* [PATCH v4 27/29] tree-walk.h API: add a get_tree_entry_path() function
  2021-03-21  0:00           ` [PATCH v4 00/29] " Ævar Arnfjörð Bjarmason
                               ` (25 preceding siblings ...)
  2021-03-21  0:00             ` [PATCH v4 26/29] tree-walk.h API: add get_tree_entry_all() Ævar Arnfjörð Bjarmason
@ 2021-03-21  0:01             ` Ævar Arnfjörð Bjarmason
  2021-03-21  0:01             ` [PATCH v4 28/29] blame: emit a better error on 'git blame directory' Ævar Arnfjörð Bjarmason
                               ` (2 subsequent siblings)
  29 siblings, 0 replies; 262+ messages in thread
From: Ævar Arnfjörð Bjarmason @ 2021-03-21  0:01 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 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[sic] '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 f5cccb8deab..e46eea9688e 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 b7a5ddce3ae..7ffae3a0f62 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.286.gc175f2cb894


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

* [PATCH v4 28/29] blame: emit a better error on 'git blame directory'
  2021-03-21  0:00           ` [PATCH v4 00/29] " Ævar Arnfjörð Bjarmason
                               ` (26 preceding siblings ...)
  2021-03-21  0:01             ` [PATCH v4 27/29] tree-walk.h API: add a get_tree_entry_path() function Ævar Arnfjörð Bjarmason
@ 2021-03-21  0:01             ` Ævar Arnfjörð Bjarmason
  2021-03-21  0:01             ` [PATCH v4 29/29] tree-walk.h API: add a tree_entry_extract_type() function Ævar Arnfjörð Bjarmason
  2021-03-21  1:16             ` [PATCH v4 00/29] tree-walk: mostly replace "mode" with "enum object_type" Junio C Hamano
  29 siblings, 0 replies; 262+ messages in thread
From: Ævar Arnfjörð Bjarmason @ 2021-03-21  0:01 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

The main point of this test is to assert that we're not doing
something uniquely bad when in a conflicted merge. See
cd8ae20195 (git-blame shouldn't crash if run in an unmerged tree,
2007-10-18) and 9aeaab6811 (blame: allow "blame file" in the middle of
a conflicted merge, 2012-09-11) for the bug the t8004 test was
originally meant to address.

But when extending it let's grep out the specific error message for
good measure. Having to change it in the future (e.g. as part of my
parallel series to improve such 'OID does not match type' messages) is
a small price for ensuring it doesn't regress.

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

diff --git a/blame.c b/blame.c
index 13825b86e65..3c3cb2f8f96 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->object.oid;
-		struct object_id blob_oid;
-		unsigned short 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)
+		struct object_id oid;
+		if (!get_tree_entry_path(r, commit_oid, path, &oid))
 			return;
 	}
 
diff --git a/t/t8004-blame-with-conflicts.sh b/t/t8004-blame-with-conflicts.sh
index 35414a53363..5e3dea35a50 100755
--- a/t/t8004-blame-with-conflicts.sh
+++ b/t/t8004-blame-with-conflicts.sh
@@ -73,4 +73,25 @@ test_expect_success 'blame does not crash with conflicted file in stages 1,3' '
 	git blame file1
 '
 
+test_expect_success 'setup second case' '
+	git merge --abort
+'
+
+test_expect_success 'blame on directory/file conflict' '
+	mkdir d &&
+	test_commit second &&
+	test_commit d/file &&
+	test_must_fail git blame d 2>expected &&
+	grep "unsupported file type d" expected &&
+
+	git reset --hard second &&
+	>d &&
+	git add d &&
+	git commit -m"a not-a-dir" &&
+	test_must_fail git merge d/file &&
+
+	test_must_fail git blame d 2>actual &&
+	test_cmp expected actual
+'
+
 test_done
-- 
2.31.0.286.gc175f2cb894


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

* [PATCH v4 29/29] tree-walk.h API: add a tree_entry_extract_type() function
  2021-03-21  0:00           ` [PATCH v4 00/29] " Ævar Arnfjörð Bjarmason
                               ` (27 preceding siblings ...)
  2021-03-21  0:01             ` [PATCH v4 28/29] blame: emit a better error on 'git blame directory' Ævar Arnfjörð Bjarmason
@ 2021-03-21  0:01             ` Ævar Arnfjörð Bjarmason
  2021-03-21  1:16             ` [PATCH v4 00/29] tree-walk: mostly replace "mode" with "enum object_type" Junio C Hamano
  29 siblings, 0 replies; 262+ messages in thread
From: Ævar Arnfjörð Bjarmason @ 2021-03-21  0:01 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 25bfb46fb02..89109659aa3 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 918ad95fa61..8409374f0ba 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 efcd7ccd10e..f5102ed5427 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.286.gc175f2cb894


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

* Re: [PATCH v4 00/29] tree-walk: mostly replace "mode" with "enum object_type"
  2021-03-21  0:00           ` [PATCH v4 00/29] " Ævar Arnfjörð Bjarmason
                               ` (28 preceding siblings ...)
  2021-03-21  0:01             ` [PATCH v4 29/29] tree-walk.h API: add a tree_entry_extract_type() function Ævar Arnfjörð Bjarmason
@ 2021-03-21  1:16             ` Junio C Hamano
  2021-03-21 12:26               ` Ævar Arnfjörð Bjarmason
  29 siblings, 1 reply; 262+ messages in thread
From: Junio C Hamano @ 2021-03-21  1:16 UTC (permalink / raw)
  To: Ævar Arnfjörð Bjarmason
  Cc: git, Elijah Newren, Kirill Smelkov,
	Nguyễn Thái Ngọc Duy

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

> A re-roll of v3 of this series[1] and on top of (and requires) my
> just-submitted v5 re-roll of the read_tree() refactoring series[2].
>
> There was a regression in 1/32 of the old series. Removing the
> canon_mode() call in diff.c didn't account for us needing to
> canonicalize "diff --no-index" modes. There were no tests for this,
> and it failed or not depending on the FS modes in the git.git checkout
> being tested. This fixes the CI smoke coming from this series.

Sorry, but quite honestly, I am not quite sure what value this
entire code churn is trying to add to the codebase.

The function signature of read_tree_fn_t callback function gets
changed from the mode bits (which is capable to express differences
between regular files, executable files and symbolic links) to "enum
object_type" (which can only say "this is a blob"), which is a
regression, no?  

A callback can no longer do things like this, for example:

static int add_path_to_index(const struct object_id *oid,
			     struct strbuf *base, const char *path,
			     unsigned int mode, void *context)
{
	struct index_state *istate = (struct index_state *)context;
	struct cache_entry *ce;
	size_t len = base->len;

	if (S_ISDIR(mode))
		return READ_TREE_RECURSIVE;

	strbuf_addstr(base, path);

	ce = make_cache_entry(istate, mode, oid, base->buf, 0, 0);
	ce->ce_flags |= CE_SKIP_WORKTREE;
	set_index_entry(istate, istate->cache_nr++, ce);

	strbuf_setlen(base, len);
	return 0;
}

where executableness or symlinkshood is lost.

This probably is the third time I caught similar "let's lose
information passed through the call chain as nobody seems to need
it" mistakes in the iterations of this series, and that is two times
too many.  We should learn from our earlier mistakes---tweaking of
the API that happens to be still OK with the current codebase can be
either a needless churn that loses useful expressiveness from the
API, or a useful clean-up to kill dead parameter or excess
flexibility.

And these three incidents we have seen so far are the former.

Thanks.






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

* Re: [PATCH v4 00/29] tree-walk: mostly replace "mode" with "enum object_type"
  2021-03-21  1:16             ` [PATCH v4 00/29] tree-walk: mostly replace "mode" with "enum object_type" Junio C Hamano
@ 2021-03-21 12:26               ` Ævar Arnfjörð Bjarmason
  2021-03-21 12:39                 ` [PATCH 0/2] diff --no-index: fix test blind spots Ævar Arnfjörð Bjarmason
  2021-03-21 17:13                 ` [PATCH v4 00/29] tree-walk: mostly replace "mode" with "enum object_type" Junio C Hamano
  0 siblings, 2 replies; 262+ messages in thread
From: Ævar Arnfjörð Bjarmason @ 2021-03-21 12:26 UTC (permalink / raw)
  To: Junio C Hamano
  Cc: git, Elijah Newren, Kirill Smelkov,
	Nguyễn Thái Ngọc Duy


On Sun, Mar 21 2021, Junio C Hamano wrote:

> Ævar Arnfjörð Bjarmason  <avarab@gmail.com> writes:
>
>> A re-roll of v3 of this series[1] and on top of (and requires) my
>> just-submitted v5 re-roll of the read_tree() refactoring series[2].
>>
>> There was a regression in 1/32 of the old series. Removing the
>> canon_mode() call in diff.c didn't account for us needing to
>> canonicalize "diff --no-index" modes. There were no tests for this,
>> and it failed or not depending on the FS modes in the git.git checkout
>> being tested. This fixes the CI smoke coming from this series.
>
> Sorry, but quite honestly, I am not quite sure what value this
> entire code churn is trying to add to the codebase.
>
> The function signature of read_tree_fn_t callback function gets
> changed from the mode bits (which is capable to express differences
> between regular files, executable files and symbolic links) to "enum
> object_type" (which can only say "this is a blob"), which is a
> regression, no?  
>
> A callback can no longer do things like this, for example:
>
> static int add_path_to_index(const struct object_id *oid,
> 			     struct strbuf *base, const char *path,
> 			     unsigned int mode, void *context)
> {
> 	struct index_state *istate = (struct index_state *)context;
> 	struct cache_entry *ce;
> 	size_t len = base->len;
>
> 	if (S_ISDIR(mode))
> 		return READ_TREE_RECURSIVE;
>
> 	strbuf_addstr(base, path);
>
> 	ce = make_cache_entry(istate, mode, oid, base->buf, 0, 0);
> 	ce->ce_flags |= CE_SKIP_WORKTREE;
> 	set_index_entry(istate, istate->cache_nr++, ce);
>
> 	strbuf_setlen(base, len);
> 	return 0;
> }
>
> where executableness or symlinkshood is lost.

Yes, that would be a serious regression. I agree that all these
functions/callbacks etc. should have a way to get at the mode bits.

I'm adding "enum object_type", not removing the "mode" parameter in
read_tree_fn_t. This function (which is in "seen" as 03316f20347
(sparse-index: implement ensure_full_index(), 2021-03-16)) works just
fine in combination with this series.

The other APIs modified here all retain the ability to give you the mode
bit, they (the tree-walk.h changes) just optionally give you the option
of getting just the type (or just the path), and as it turns out most
users of the API can be converted over to that.

> This probably is the third time I caught similar "let's lose
> information passed through the call chain as nobody seems to need
> it" mistakes in the iterations of this series, and that is two times
> too many.  We should learn from our earlier mistakes---tweaking of
> the API that happens to be still OK with the current codebase can be
> either a needless churn that loses useful expressiveness from the
> API, or a useful clean-up to kill dead parameter or excess
> flexibility.
>
> And these three incidents we have seen so far are the former.

The current codebase will allow you to stick arbitrary mode bits in
trees, we have an fsck check to prevent that which doesn't work. I had a
summary of this in v1, but should probably have provided a recap[1].

This series is an admittedly long journey towards fixing that. I've got
unsubmitted patchen on top that make that fsck check work again.

I think the root cause of these bugs and other ones I've found along the
way (some of which I'm not quite comfortable discussing the details of
on the public list yet) is that the tree walking API is unnecessarily
low-level for most callers.

Most of those callers don't care about the details of the mode bits, but
are just traversing a tree and doing something with one the object
types.

As opposed to having a mode, but do you want a mode as-is from a tree,
normalized to canon_mode() (for writing?) etc. I think being able to
clearly tell apart those callers from the simpler ones is a clear win.

So I'm hoping you'll bear with me & this series, sorry about the
breakages so far, in my slight defense they were all subtle testing
blind spots (but we now have tests!).

1. https://lore.kernel.org/git/20210308150650.18626-1-avarab@gmail.com/

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

* [PATCH 0/2] diff --no-index: fix test blind spots
  2021-03-21 12:26               ` Ævar Arnfjörð Bjarmason
@ 2021-03-21 12:39                 ` Ævar Arnfjörð Bjarmason
  2021-03-21 12:39                   ` [PATCH 1/2] diff --no-index tests: add test for --exit-code Ævar Arnfjörð Bjarmason
                                     ` (2 more replies)
  2021-03-21 17:13                 ` [PATCH v4 00/29] tree-walk: mostly replace "mode" with "enum object_type" Junio C Hamano
  1 sibling, 3 replies; 262+ messages in thread
From: Ævar Arnfjörð Bjarmason @ 2021-03-21 12:39 UTC (permalink / raw)
  To: git; +Cc: Junio C Hamano, Ævar Arnfjörð Bjarmason

A trivial series to add tests for "git diff --no-index"'s mode
handling, and a missing test for how --exit-code behaves in
combination with --no-index while I was at it.

This would have caught the regression I inadvertently introduced
in[1]. It's related to my much larger tree-walk.h series[2], but
applies independently of that. I wanted to split it off as there were
no conflicts or behavior changes related to canon_mode() in that
series anymore.

1. https://lore.kernel.org/git/20210316155829.31242-2-avarab@gmail.com/
2. https://lore.kernel.org/git/cover.1616282533.git.avarab@gmail.com/


Ævar Arnfjörð Bjarmason (2):
  diff --no-index tests: add test for --exit-code
  diff --no-index tests: test mode normalization

 t/t4053-diff-no-index.sh | 37 ++++++++++++++++++++++++++++++++++++-
 1 file changed, 36 insertions(+), 1 deletion(-)

-- 
2.31.0.282.gcc1ec606501


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

* [PATCH 1/2] diff --no-index tests: add test for --exit-code
  2021-03-21 12:39                 ` [PATCH 0/2] diff --no-index: fix test blind spots Ævar Arnfjörð Bjarmason
@ 2021-03-21 12:39                   ` Ævar Arnfjörð Bjarmason
  2021-03-21 18:33                     ` Ramsay Jones
  2021-03-21 12:39                   ` [PATCH 2/2] diff --no-index tests: test mode normalization Ævar Arnfjörð Bjarmason
  2021-03-21 22:36                   ` [PATCH v2 0/2] diff --no-index: fix test blind spots Ævar Arnfjörð Bjarmason
  2 siblings, 1 reply; 262+ messages in thread
From: Ævar Arnfjörð Bjarmason @ 2021-03-21 12:39 UTC (permalink / raw)
  To: git; +Cc: Junio C Hamano, Ævar Arnfjörð Bjarmason

Add a test for --exit-code working with --no-index. There's no reason
to suppose it wouldn't, but we weren't testing for it anywhere in our
tests. Let's fix that blind spot.

Signed-off-by: Ævar Arnfjörð Bjarmason <avarab@gmail.com>
---
 t/t4053-diff-no-index.sh | 7 ++++++-
 1 file changed, 6 insertions(+), 1 deletion(-)

diff --git a/t/t4053-diff-no-index.sh b/t/t4053-diff-no-index.sh
index 0168946b639..9b7a8ebfd3f 100755
--- a/t/t4053-diff-no-index.sh
+++ b/t/t4053-diff-no-index.sh
@@ -16,7 +16,12 @@ test_expect_success 'setup' '
 	echo 1 >non/git/b
 '
 
-test_expect_success 'git diff --no-index directories' '
+test_expect_success 'git diff --no-index --exit-code' '
+	git diff --no-index --exit-code a/1 non/git/a &&
+	test_expect_code 1 git diff --no-index --exit-code a/1 a/2
+'
+
+Test_expect_success 'git diff --no-index directories' '
 	test_expect_code 1 git diff --no-index a b >cnt &&
 	test_line_count = 14 cnt
 '
-- 
2.31.0.282.gcc1ec606501


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

* [PATCH 2/2] diff --no-index tests: test mode normalization
  2021-03-21 12:39                 ` [PATCH 0/2] diff --no-index: fix test blind spots Ævar Arnfjörð Bjarmason
  2021-03-21 12:39                   ` [PATCH 1/2] diff --no-index tests: add test for --exit-code Ævar Arnfjörð Bjarmason
@ 2021-03-21 12:39                   ` Ævar Arnfjörð Bjarmason
  2021-03-21 22:36                   ` [PATCH v2 0/2] diff --no-index: fix test blind spots Ævar Arnfjörð Bjarmason
  2 siblings, 0 replies; 262+ messages in thread
From: Ævar Arnfjörð Bjarmason @ 2021-03-21 12:39 UTC (permalink / raw)
  To: git; +Cc: Junio C Hamano, Ævar Arnfjörð Bjarmason

When "git diff --no-index X Y" is run the modes of the files being
differ are normalized by canon_mode() in fill_filespec().

I recently broke that behavior in a patch of mine[1] which would pass
all tests, or not, depending on the umask of the git.git checkout.

Let's test for this explicitly. Arguably this should not be the
behavior of "git diff --no-index". We aren't diffing our own objects
or the index, so it might be useful to show mode differences between
files.

On the other hand diff(1) does not do that, and it would be needlessly
distracting when e.g. diffing an extracted tar archive whose contents
is the same, but whose file modes are different.

1. https://lore.kernel.org/git/20210316155829.31242-2-avarab@gmail.com/

Signed-off-by: Ævar Arnfjörð Bjarmason <avarab@gmail.com>
---
 t/t4053-diff-no-index.sh | 30 ++++++++++++++++++++++++++++++
 1 file changed, 30 insertions(+)

diff --git a/t/t4053-diff-no-index.sh b/t/t4053-diff-no-index.sh
index 9b7a8ebfd3f..6fae18612fc 100755
--- a/t/t4053-diff-no-index.sh
+++ b/t/t4053-diff-no-index.sh
@@ -149,4 +149,34 @@ test_expect_success 'diff --no-index allows external diff' '
 	test_cmp expect actual
 '
 
+test_expect_success 'diff --no-index normalizes mode: no changes' '
+	echo foo >x &&
+	cp x y &&
+	git diff --no-index x y >out &&
+	test_must_be_empty out
+'
+
+test_expect_success 'diff --no-index normalizes mode: chmod +x' '
+	chmod +x y &&
+	cat >expected <<-\EOF &&
+	diff --git a/x b/y
+	old mode 100644
+	new mode 100755
+	EOF
+	test_expect_code 1 git diff --no-index x y >actual &&
+	test_cmp expected actual
+'
+
+test_expect_success 'diff --no-index normalizes: mode not like git mode' '
+	chmod 666 x &&
+	chmod 777 y &&
+	cat >expected <<-\EOF &&
+	diff --git a/x b/y
+	old mode 100644
+	new mode 100755
+	EOF
+	test_expect_code 1 git diff --no-index x y >actual &&
+	test_cmp expected actual
+'
+
 test_done
-- 
2.31.0.282.gcc1ec606501


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

* Re: [PATCH v4 00/29] tree-walk: mostly replace "mode" with "enum object_type"
  2021-03-21 12:26               ` Ævar Arnfjörð Bjarmason
  2021-03-21 12:39                 ` [PATCH 0/2] diff --no-index: fix test blind spots Ævar Arnfjörð Bjarmason
@ 2021-03-21 17:13                 ` Junio C Hamano
  2021-03-21 18:42                   ` Ævar Arnfjörð Bjarmason
  1 sibling, 1 reply; 262+ messages in thread
From: Junio C Hamano @ 2021-03-21 17:13 UTC (permalink / raw)
  To: Ævar Arnfjörð Bjarmason
  Cc: git, Elijah Newren, Kirill Smelkov,
	Nguyễn Thái Ngọc Duy

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

> Yes, that would be a serious regression. I agree that all these
> functions/callbacks etc. should have a way to get at the mode bits.
>
> I'm adding "enum object_type", not removing the "mode" parameter in
> read_tree_fn_t. This function (which is in "seen" as 03316f20347
> (sparse-index: implement ensure_full_index(), 2021-03-16)) works just
> fine in combination with this series.
>
> The other APIs modified here all retain the ability to give you the mode
> bit, they (the tree-walk.h changes) just optionally give you the option
> of getting just the type (or just the path), and as it turns out most
> users of the API can be converted over to that.

I have a vague feeling that such an approach may be still repeating
the same mistake.

If the original premise is that "unsigned mode" bit can be abused to
feed impossible values like 0100653 to the system and the code
should catch it, ...

> The current codebase will allow you to stick arbitrary mode bits in
> trees, ...

... then I would understand it if the approach is to introduce a
distinct type that enumerates all possible mode bit values (and
nothing else), and have the compiler validate the callchain, so that
nobody can pass bogus mode bits (and when reading mode bits fields
in existing objects, the one that converts from the series of octal
bytes to that distsinct type would notice and complain).  And we've
already seen from this particular breakages that the "distinct type"
appropriate to be used for that purpose is not "enum object_type".
It is not expressive enough to enumerate all possible mode bit
values (besides, an enum is interchangeable with an int, so there
isn't much protection we would be getting from the compiler---we
could use a small struct of a new type, and have one static const
instance for each possible mode bit combination, I guess, but the
point here is that insisting on using "enum object_type" seems to be
the source of the problem).

I am afraid that it is even worse to pass both object type and
"unsigned mode" together.  It would still leave room for a bug to
pass nonsense mode bits, which we said we wanted to catch in our
original mission statement.  In addition, we now have a new room for
a bug, which is to pass an inconsistent pair of object type and mode
to the callchain.  Somebody would need to say "yuck, we got a mode
100644 but the type says TREE" now, in addition to validating if the
mode is sensible, which we should be doing somehow, no?

So, I am not sure how these changes are making anything better.

> ... I had a
> summary of this in v1, but should probably have provided a recap[1].

Oh, absolutely.  When we iterate, we should be welcoming to those
who missed earlier iterations.


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

* Re: [PATCH 1/2] diff --no-index tests: add test for --exit-code
  2021-03-21 12:39                   ` [PATCH 1/2] diff --no-index tests: add test for --exit-code Ævar Arnfjörð Bjarmason
@ 2021-03-21 18:33                     ` Ramsay Jones
  2021-03-21 21:33                       ` Junio C Hamano
  0 siblings, 1 reply; 262+ messages in thread
From: Ramsay Jones @ 2021-03-21 18:33 UTC (permalink / raw)
  To: Ævar Arnfjörð Bjarmason, git; +Cc: Junio C Hamano



On 21/03/2021 12:39, Ævar Arnfjörð Bjarmason wrote:
> Add a test for --exit-code working with --no-index. There's no reason
> to suppose it wouldn't, but we weren't testing for it anywhere in our
> tests. Let's fix that blind spot.
> 
> Signed-off-by: Ævar Arnfjörð Bjarmason <avarab@gmail.com>
> ---
>  t/t4053-diff-no-index.sh | 7 ++++++-
>  1 file changed, 6 insertions(+), 1 deletion(-)
> 
> diff --git a/t/t4053-diff-no-index.sh b/t/t4053-diff-no-index.sh
> index 0168946b639..9b7a8ebfd3f 100755
> --- a/t/t4053-diff-no-index.sh
> +++ b/t/t4053-diff-no-index.sh
> @@ -16,7 +16,12 @@ test_expect_success 'setup' '
>  	echo 1 >non/git/b
>  '
>  
> -test_expect_success 'git diff --no-index directories' '
> +test_expect_success 'git diff --no-index --exit-code' '
> +	git diff --no-index --exit-code a/1 non/git/a &&
> +	test_expect_code 1 git diff --no-index --exit-code a/1 a/2
> +'
> +
> +Test_expect_success 'git diff --no-index directories' '

I assume that s/test/Test/ was not intended. ;-)

ATB,
Ramsay Jones

>  	test_expect_code 1 git diff --no-index a b >cnt &&
>  	test_line_count = 14 cnt
>  '
> 

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

* Re: [PATCH v4 00/29] tree-walk: mostly replace "mode" with "enum object_type"
  2021-03-21 17:13                 ` [PATCH v4 00/29] tree-walk: mostly replace "mode" with "enum object_type" Junio C Hamano
@ 2021-03-21 18:42                   ` Ævar Arnfjörð Bjarmason
  2021-03-31 19:09                     ` [PATCH v5 00/18] tree-walk.h: slimmed down Ævar Arnfjörð Bjarmason
  0 siblings, 1 reply; 262+ messages in thread
From: Ævar Arnfjörð Bjarmason @ 2021-03-21 18:42 UTC (permalink / raw)
  To: Junio C Hamano
  Cc: git, Elijah Newren, Kirill Smelkov,
	Nguyễn Thái Ngọc Duy


On Sun, Mar 21 2021, Junio C Hamano wrote:

> Ævar Arnfjörð Bjarmason <avarab@gmail.com> writes:
>
>> Yes, that would be a serious regression. I agree that all these
>> functions/callbacks etc. should have a way to get at the mode bits.
>>
>> I'm adding "enum object_type", not removing the "mode" parameter in
>> read_tree_fn_t. This function (which is in "seen" as 03316f20347
>> (sparse-index: implement ensure_full_index(), 2021-03-16)) works just
>> fine in combination with this series.
>>
>> The other APIs modified here all retain the ability to give you the mode
>> bit, they (the tree-walk.h changes) just optionally give you the option
>> of getting just the type (or just the path), and as it turns out most
>> users of the API can be converted over to that.
>
> I have a vague feeling that such an approach may be still repeating
> the same mistake.
>
> If the original premise is that "unsigned mode" bit can be abused to
> feed impossible values like 0100653 to the system and the code
> should catch it, ...
>
>> The current codebase will allow you to stick arbitrary mode bits in
>> trees, ...
>
> ... then I would understand it if the approach is to introduce a
> distinct type that enumerates all possible mode bit values (and
> nothing else), and have the compiler validate the callchain, so that
> nobody can pass bogus mode bits (and when reading mode bits fields
> in existing objects, the one that converts from the series of octal
> bytes to that distsinct type would notice and complain).  And we've
> already seen from this particular breakages that the "distinct type"
> appropriate to be used for that purpose is not "enum object_type".
> It is not expressive enough to enumerate all possible mode bit
> values (besides, an enum is interchangeable with an int, so there
> isn't much protection we would be getting from the compiler---we
> could use a small struct of a new type, and have one static const
> instance for each possible mode bit combination, I guess, but the
> point here is that insisting on using "enum object_type" seems to be
> the source of the problem).

Yes, this is a good suggestion, but one which'll be much easier to do
after this series. Since the majority of callers don't care about the
raw mode bits or anything except if the entry is a blob/tree/commit.

> I am afraid that it is even worse to pass both object type and
> "unsigned mode" together.  It would still leave room for a bug to
> pass nonsense mode bits, which we said we wanted to catch in our
> original mission statement.  In addition, we now have a new room for
> a bug, which is to pass an inconsistent pair of object type and mode
> to the callchain.  Somebody would need to say "yuck, we got a mode
> 100644 but the type says TREE" now, in addition to validating if the
> mode is sensible, which we should be doing somehow, no?

Indeed. This goes back to my "bear with me" comment upthread. I'm
planning to fix these cases too, and starting by moving most things to
"enum object_type" makes that a lot easier.

Right now we simply trust the mode bits, but that opens the door to the
same sort of bug I'm fixing in another series (that I need to re-roll)
where we have a "type commit" and "object ID" in a tag, but the ID is
really a tree or whatever.

We then get confused because we trusted the invalid metadata over
checking the type of the object ID we have in the object store.

So this particular series doesn't fix this bug at the end of it, the
"object_type" in tree-walk.c is just a function of deriving it from the
mode bits.

But once I've audited the cases where we're really just acting on the
type and don't have or use the mode (so we know we're not re-writing the
mode somewhere) then we would set the object_type to the actual type, as
in what we'd get from oid_object_info(ID).

Then we can e.g. scream murder about a mode/type mismatch in fsck, but
still be able to list/diff/inspect etc. that object in any codepath that
just wants to e.g. recursively iterate over the tree.



> So, I am not sure how these changes are making anything better.
>
>> ... I had a
>> summary of this in v1, but should probably have provided a recap[1].
>
> Oh, absolutely.  When we iterate, we should be welcoming to those
> who missed earlier iterations.


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

* Re: [PATCH 1/2] diff --no-index tests: add test for --exit-code
  2021-03-21 18:33                     ` Ramsay Jones
@ 2021-03-21 21:33                       ` Junio C Hamano
  2021-03-21 22:44                         ` Ævar Arnfjörð Bjarmason
  0 siblings, 1 reply; 262+ messages in thread
From: Junio C Hamano @ 2021-03-21 21:33 UTC (permalink / raw)
  To: Ramsay Jones; +Cc: Ævar Arnfjörð Bjarmason, git

Ramsay Jones <ramsay@ramsayjones.plus.com> writes:

> On 21/03/2021 12:39, Ævar Arnfjörð Bjarmason wrote:
>> Add a test for --exit-code working with --no-index. There's no reason
>> to suppose it wouldn't, but we weren't testing for it anywhere in our
>> tests. Let's fix that blind spot.
>> 
>> Signed-off-by: Ævar Arnfjörð Bjarmason <avarab@gmail.com>
>> ---
>>  t/t4053-diff-no-index.sh | 7 ++++++-
>>  1 file changed, 6 insertions(+), 1 deletion(-)
>> 
>> diff --git a/t/t4053-diff-no-index.sh b/t/t4053-diff-no-index.sh
>> index 0168946b639..9b7a8ebfd3f 100755
>> --- a/t/t4053-diff-no-index.sh
>> +++ b/t/t4053-diff-no-index.sh
>> @@ -16,7 +16,12 @@ test_expect_success 'setup' '
>>  	echo 1 >non/git/b
>>  '
>>  
>> -test_expect_success 'git diff --no-index directories' '
>> +test_expect_success 'git diff --no-index --exit-code' '
>> +	git diff --no-index --exit-code a/1 non/git/a &&
>> +	test_expect_code 1 git diff --no-index --exit-code a/1 a/2
>> +'
>> +
>> +Test_expect_success 'git diff --no-index directories' '
>
> I assume that s/test/Test/ was not intended. ;-)

;-)  

Love to see reviewers are more careful than submitters' shells that
are too lenient to allow such a test to pass before such a patch
gets submitted.


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

* [PATCH v2 0/2] diff --no-index: fix test blind spots
  2021-03-21 12:39                 ` [PATCH 0/2] diff --no-index: fix test blind spots Ævar Arnfjörð Bjarmason
  2021-03-21 12:39                   ` [PATCH 1/2] diff --no-index tests: add test for --exit-code Ævar Arnfjörð Bjarmason
  2021-03-21 12:39                   ` [PATCH 2/2] diff --no-index tests: test mode normalization Ævar Arnfjörð Bjarmason
@ 2021-03-21 22:36                   ` Ævar Arnfjörð Bjarmason
  2021-03-21 22:36                     ` [PATCH v2 1/2] diff --no-index tests: add test for --exit-code Ævar Arnfjörð Bjarmason
                                       ` (3 more replies)
  2 siblings, 4 replies; 262+ messages in thread
From: Ævar Arnfjörð Bjarmason @ 2021-03-21 22:36 UTC (permalink / raw)
  To: git; +Cc: Junio C Hamano, Ramsay Jones, Ævar Arnfjörð Bjarmason

Fixes a stupid s/Test/test/ typo in v1. Thanks Ramsey. I also noticed
a failure on one of the Windows CI's (curiously, not all?), so
POSIXPERM for these tests is another thing I forgot.

I've also added a symlink diff test for good measure. I'm testing the
full output, but using the the approprite variables, so it passes
under both GIT_TEST_DEFAULT_HASH=sha1 & sha256.

Ævar Arnfjörð Bjarmason (2):
  diff --no-index tests: add test for --exit-code
  diff --no-index tests: test mode normalization

 t/t4053-diff-no-index.sh | 60 ++++++++++++++++++++++++++++++++++++++++
 1 file changed, 60 insertions(+)

Range-diff:
1:  a6e4ed6c3f1 ! 1:  2dbc6c253e2 diff --no-index tests: add test for --exit-code
    @@ t/t4053-diff-no-index.sh: test_expect_success 'setup' '
      	echo 1 >non/git/b
      '
      
    --test_expect_success 'git diff --no-index directories' '
     +test_expect_success 'git diff --no-index --exit-code' '
     +	git diff --no-index --exit-code a/1 non/git/a &&
     +	test_expect_code 1 git diff --no-index --exit-code a/1 a/2
     +'
     +
    -+Test_expect_success 'git diff --no-index directories' '
    + test_expect_success 'git diff --no-index directories' '
      	test_expect_code 1 git diff --no-index a b >cnt &&
      	test_line_count = 14 cnt
    - '
2:  2dcc8bccf97 ! 2:  a1ab6a323f2 diff --no-index tests: test mode normalization
    @@ t/t4053-diff-no-index.sh: test_expect_success 'diff --no-index allows external d
     +	test_must_be_empty out
     +'
     +
    -+test_expect_success 'diff --no-index normalizes mode: chmod +x' '
    ++test_expect_success POSIXPERM 'diff --no-index normalizes mode: chmod +x' '
     +	chmod +x y &&
     +	cat >expected <<-\EOF &&
     +	diff --git a/x b/y
    @@ t/t4053-diff-no-index.sh: test_expect_success 'diff --no-index allows external d
     +	test_cmp expected actual
     +'
     +
    -+test_expect_success 'diff --no-index normalizes: mode not like git mode' '
    ++test_expect_success POSIXPERM 'diff --no-index normalizes: mode not like git mode' '
     +	chmod 666 x &&
     +	chmod 777 y &&
     +	cat >expected <<-\EOF &&
    @@ t/t4053-diff-no-index.sh: test_expect_success 'diff --no-index allows external d
     +	test_expect_code 1 git diff --no-index x y >actual &&
     +	test_cmp expected actual
     +'
    ++
    ++test_expect_success POSIXPERM,SYMLINKS 'diff --no-index normalizes: mode not like git mode (symlink)' '
    ++	ln -s y z &&
    ++	X_OID=$(git hash-object --stdin <x) &&
    ++	Z_OID=$(echo -n y | git hash-object --stdin) &&
    ++	cat >expected <<-EOF &&
    ++	diff --git a/x b/x
    ++	deleted file mode 100644
    ++	index $X_OID..$ZERO_OID
    ++	--- a/x
    ++	+++ /dev/null
    ++	@@ -1 +0,0 @@
    ++	-foo
    ++	diff --git a/z b/z
    ++	new file mode 120000
    ++	index $ZERO_OID..$Z_OID
    ++	--- /dev/null
    ++	+++ b/z
    ++	@@ -0,0 +1 @@
    ++	+y
    ++	\ No newline at end of file
    ++	EOF
    ++	test_expect_code 1 git -c core.abbrev=no diff --no-index x z >actual &&
    ++	test_cmp expected actual
    ++'
     +
      test_done
-- 
2.31.0.285.gb40d23e604f


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

* [PATCH v2 1/2] diff --no-index tests: add test for --exit-code
  2021-03-21 22:36                   ` [PATCH v2 0/2] diff --no-index: fix test blind spots Ævar Arnfjörð Bjarmason
@ 2021-03-21 22:36                     ` Ævar Arnfjörð Bjarmason
  2021-03-21 22:36                     ` [PATCH v2 2/2] diff --no-index tests: test mode normalization Ævar Arnfjörð Bjarmason
                                       ` (2 subsequent siblings)
  3 siblings, 0 replies; 262+ messages in thread
From: Ævar Arnfjörð Bjarmason @ 2021-03-21 22:36 UTC (permalink / raw)
  To: git; +Cc: Junio C Hamano, Ramsay Jones, Ævar Arnfjörð Bjarmason

Add a test for --exit-code working with --no-index. There's no reason
to suppose it wouldn't, but we weren't testing for it anywhere in our
tests. Let's fix that blind spot.

Signed-off-by: Ævar Arnfjörð Bjarmason <avarab@gmail.com>
---
 t/t4053-diff-no-index.sh | 5 +++++
 1 file changed, 5 insertions(+)

diff --git a/t/t4053-diff-no-index.sh b/t/t4053-diff-no-index.sh
index 0168946b639..44b932fbb20 100755
--- a/t/t4053-diff-no-index.sh
+++ b/t/t4053-diff-no-index.sh
@@ -16,6 +16,11 @@ test_expect_success 'setup' '
 	echo 1 >non/git/b
 '
 
+test_expect_success 'git diff --no-index --exit-code' '
+	git diff --no-index --exit-code a/1 non/git/a &&
+	test_expect_code 1 git diff --no-index --exit-code a/1 a/2
+'
+
 test_expect_success 'git diff --no-index directories' '
 	test_expect_code 1 git diff --no-index a b >cnt &&
 	test_line_count = 14 cnt
-- 
2.31.0.285.gb40d23e604f


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

* [PATCH v2 2/2] diff --no-index tests: test mode normalization
  2021-03-21 22:36                   ` [PATCH v2 0/2] diff --no-index: fix test blind spots Ævar Arnfjörð Bjarmason
  2021-03-21 22:36                     ` [PATCH v2 1/2] diff --no-index tests: add test for --exit-code Ævar Arnfjörð Bjarmason
@ 2021-03-21 22:36                     ` Ævar Arnfjörð Bjarmason
  2021-03-22 19:22                       ` Junio C Hamano
  2021-03-22  4:27                     ` [PATCH v2 0/2] diff --no-index: fix test blind spots Junio C Hamano
  2021-03-23 16:40                     ` [PATCH v3 " Ævar Arnfjörð Bjarmason
  3 siblings, 1 reply; 262+ messages in thread
From: Ævar Arnfjörð Bjarmason @ 2021-03-21 22:36 UTC (permalink / raw)
  To: git; +Cc: Junio C Hamano, Ramsay Jones, Ævar Arnfjörð Bjarmason

When "git diff --no-index X Y" is run the modes of the files being
differ are normalized by canon_mode() in fill_filespec().

I recently broke that behavior in a patch of mine[1] which would pass
all tests, or not, depending on the umask of the git.git checkout.

Let's test for this explicitly. Arguably this should not be the
behavior of "git diff --no-index". We aren't diffing our own objects
or the index, so it might be useful to show mode differences between
files.

On the other hand diff(1) does not do that, and it would be needlessly
distracting when e.g. diffing an extracted tar archive whose contents
is the same, but whose file modes are different.

1. https://lore.kernel.org/git/20210316155829.31242-2-avarab@gmail.com/

Signed-off-by: Ævar Arnfjörð Bjarmason <avarab@gmail.com>
---
 t/t4053-diff-no-index.sh | 55 ++++++++++++++++++++++++++++++++++++++++
 1 file changed, 55 insertions(+)

diff --git a/t/t4053-diff-no-index.sh b/t/t4053-diff-no-index.sh
index 44b932fbb20..39d1da1f362 100755
--- a/t/t4053-diff-no-index.sh
+++ b/t/t4053-diff-no-index.sh
@@ -149,4 +149,59 @@ test_expect_success 'diff --no-index allows external diff' '
 	test_cmp expect actual
 '
 
+test_expect_success 'diff --no-index normalizes mode: no changes' '
+	echo foo >x &&
+	cp x y &&
+	git diff --no-index x y >out &&
+	test_must_be_empty out
+'
+
+test_expect_success POSIXPERM 'diff --no-index normalizes mode: chmod +x' '
+	chmod +x y &&
+	cat >expected <<-\EOF &&
+	diff --git a/x b/y
+	old mode 100644
+	new mode 100755
+	EOF
+	test_expect_code 1 git diff --no-index x y >actual &&
+	test_cmp expected actual
+'
+
+test_expect_success POSIXPERM 'diff --no-index normalizes: mode not like git mode' '
+	chmod 666 x &&
+	chmod 777 y &&
+	cat >expected <<-\EOF &&
+	diff --git a/x b/y
+	old mode 100644
+	new mode 100755
+	EOF
+	test_expect_code 1 git diff --no-index x y >actual &&
+	test_cmp expected actual
+'
+
+test_expect_success POSIXPERM,SYMLINKS 'diff --no-index normalizes: mode not like git mode (symlink)' '
+	ln -s y z &&
+	X_OID=$(git hash-object --stdin <x) &&
+	Z_OID=$(echo -n y | git hash-object --stdin) &&
+	cat >expected <<-EOF &&
+	diff --git a/x b/x
+	deleted file mode 100644
+	index $X_OID..$ZERO_OID
+	--- a/x
+	+++ /dev/null
+	@@ -1 +0,0 @@
+	-foo
+	diff --git a/z b/z
+	new file mode 120000
+	index $ZERO_OID..$Z_OID
+	--- /dev/null
+	+++ b/z
+	@@ -0,0 +1 @@
+	+y
+	\ No newline at end of file
+	EOF
+	test_expect_code 1 git -c core.abbrev=no diff --no-index x z >actual &&
+	test_cmp expected actual
+'
+
 test_done
-- 
2.31.0.285.gb40d23e604f


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

* Re: [PATCH 1/2] diff --no-index tests: add test for --exit-code
  2021-03-21 21:33                       ` Junio C Hamano
@ 2021-03-21 22:44                         ` Ævar Arnfjörð Bjarmason
  0 siblings, 0 replies; 262+ messages in thread
From: Ævar Arnfjörð Bjarmason @ 2021-03-21 22:44 UTC (permalink / raw)
  To: Junio C Hamano; +Cc: Ramsay Jones, git


On Sun, Mar 21 2021, Junio C Hamano wrote:

> Ramsay Jones <ramsay@ramsayjones.plus.com> writes:
>
>> On 21/03/2021 12:39, Ævar Arnfjörð Bjarmason wrote:
>>> Add a test for --exit-code working with --no-index. There's no reason
>>> to suppose it wouldn't, but we weren't testing for it anywhere in our
>>> tests. Let's fix that blind spot.
>>> 
>>> Signed-off-by: Ævar Arnfjörð Bjarmason <avarab@gmail.com>
>>> ---
>>>  t/t4053-diff-no-index.sh | 7 ++++++-
>>>  1 file changed, 6 insertions(+), 1 deletion(-)
>>> 
>>> diff --git a/t/t4053-diff-no-index.sh b/t/t4053-diff-no-index.sh
>>> index 0168946b639..9b7a8ebfd3f 100755
>>> --- a/t/t4053-diff-no-index.sh
>>> +++ b/t/t4053-diff-no-index.sh
>>> @@ -16,7 +16,12 @@ test_expect_success 'setup' '
>>>  	echo 1 >non/git/b
>>>  '
>>>  
>>> -test_expect_success 'git diff --no-index directories' '
>>> +test_expect_success 'git diff --no-index --exit-code' '
>>> +	git diff --no-index --exit-code a/1 non/git/a &&
>>> +	test_expect_code 1 git diff --no-index --exit-code a/1 a/2
>>> +'
>>> +
>>> +Test_expect_success 'git diff --no-index directories' '
>>
>> I assume that s/test/Test/ was not intended. ;-)
>
> ;-)  
>
> Love to see reviewers are more careful than submitters' shells that
> are too lenient to allow such a test to pass before such a patch
> gets submitted.

Sorry about that, and thanks Ramsey for spotting it.

FWIW I don't think there's any shell you can run the tests with that
would catch this. We won't run the tests at all with "set -e"[1], and we
don't use "set -e" in the tests themselves by convention.

So you'll see a notice about an unknown Test_expect_success function in
the output if you're not blind to it as I apparently was, but the the
test will succeed, CI will pass etc.

1. In this case the thing holding it back is the structure of the sanity
   check added in 2006f0adaee (t/test-lib: make sure Git has already
   been built, 2012-09-17), we'd proceed if it was part of the "if",
   hrm...

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

* Re: [PATCH v2 0/2] diff --no-index: fix test blind spots
  2021-03-21 22:36                   ` [PATCH v2 0/2] diff --no-index: fix test blind spots Ævar Arnfjörð Bjarmason
  2021-03-21 22:36                     ` [PATCH v2 1/2] diff --no-index tests: add test for --exit-code Ævar Arnfjörð Bjarmason
  2021-03-21 22:36                     ` [PATCH v2 2/2] diff --no-index tests: test mode normalization Ævar Arnfjörð Bjarmason
@ 2021-03-22  4:27                     ` Junio C Hamano
  2021-03-23 16:40                     ` [PATCH v3 " Ævar Arnfjörð Bjarmason
  3 siblings, 0 replies; 262+ messages in thread
From: Junio C Hamano @ 2021-03-22  4:27 UTC (permalink / raw)
  To: Ævar Arnfjörð Bjarmason; +Cc: git, Ramsay Jones

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

> Fixes a stupid s/Test/test/ typo in v1. Thanks Ramsey. I also noticed
> a failure on one of the Windows CI's (curiously, not all?), so
> POSIXPERM for these tests is another thing I forgot.

Nice.  Thanks for a quick reroll.

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

* Re: [PATCH v2 2/2] diff --no-index tests: test mode normalization
  2021-03-21 22:36                     ` [PATCH v2 2/2] diff --no-index tests: test mode normalization Ævar Arnfjörð Bjarmason
@ 2021-03-22 19:22                       ` Junio C Hamano
  0 siblings, 0 replies; 262+ messages in thread
From: Junio C Hamano @ 2021-03-22 19:22 UTC (permalink / raw)
  To: Ævar Arnfjörð Bjarmason; +Cc: git, Ramsay Jones

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

> +test_expect_success POSIXPERM,SYMLINKS 'diff --no-index normalizes: mode not like git mode (symlink)' '
> +	ln -s y z &&
> +	X_OID=$(git hash-object --stdin <x) &&
> +	Z_OID=$(echo -n y | git hash-object --stdin) &&

s/echo -n/printf/

t4053-diff-no-index.sh:185: error: echo with option is not portable
(use printf): Z_OID=$(echo -n y | git hash-object --stdin) &&
gmake[1]: *** [Makefile:95: test-lint-shell-syntax] Error 1
gmake[1]: Leaving directory '/home/jch/w/buildfarm/jch/t'
gmake: *** [Makefile:2855: test] Error 2

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

* [PATCH v3 0/2] diff --no-index: fix test blind spots
  2021-03-21 22:36                   ` [PATCH v2 0/2] diff --no-index: fix test blind spots Ævar Arnfjörð Bjarmason
                                       ` (2 preceding siblings ...)
  2021-03-22  4:27                     ` [PATCH v2 0/2] diff --no-index: fix test blind spots Junio C Hamano
@ 2021-03-23 16:40                     ` Ævar Arnfjörð Bjarmason
  2021-03-23 16:40                       ` [PATCH v3 1/2] diff --no-index tests: add test for --exit-code Ævar Arnfjörð Bjarmason
                                         ` (2 more replies)
  3 siblings, 3 replies; 262+ messages in thread
From: Ævar Arnfjörð Bjarmason @ 2021-03-23 16:40 UTC (permalink / raw)
  To: git; +Cc: Junio C Hamano, Ramsay Jones, Ævar Arnfjörð Bjarmason

Since v2[1]: s/echo -n/printf/ (and I re-adjusted my test setup to run
the linting..)

1. https://lore.kernel.org/git/cover.1616366036.git.avarab@gmail.com/

Ævar Arnfjörð Bjarmason (2):
  diff --no-index tests: add test for --exit-code
  diff --no-index tests: test mode normalization

 t/t4053-diff-no-index.sh | 60 ++++++++++++++++++++++++++++++++++++++++
 1 file changed, 60 insertions(+)

Range-diff:
1:  2dbc6c253e2 = 1:  7dd5c309a70 diff --no-index tests: add test for --exit-code
2:  a1ab6a323f2 ! 2:  e5bb094b783 diff --no-index tests: test mode normalization
    @@ t/t4053-diff-no-index.sh: test_expect_success 'diff --no-index allows external d
     +test_expect_success POSIXPERM,SYMLINKS 'diff --no-index normalizes: mode not like git mode (symlink)' '
     +	ln -s y z &&
     +	X_OID=$(git hash-object --stdin <x) &&
    -+	Z_OID=$(echo -n y | git hash-object --stdin) &&
    ++	Z_OID=$(printf "y" | git hash-object --stdin) &&
     +	cat >expected <<-EOF &&
     +	diff --git a/x b/x
     +	deleted file mode 100644
-- 
2.31.0.366.g871543fb182


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

* [PATCH v3 1/2] diff --no-index tests: add test for --exit-code
  2021-03-23 16:40                     ` [PATCH v3 " Ævar Arnfjörð Bjarmason
@ 2021-03-23 16:40                       ` Ævar Arnfjörð Bjarmason
  2021-03-23 16:40                       ` [PATCH v3 2/2] diff --no-index tests: test mode normalization Ævar Arnfjörð Bjarmason
  2021-03-23 16:47                       ` [PATCH v3 0/2] diff --no-index: fix test blind spots Junio C Hamano
  2 siblings, 0 replies; 262+ messages in thread
From: Ævar Arnfjörð Bjarmason @ 2021-03-23 16:40 UTC (permalink / raw)
  To: git; +Cc: Junio C Hamano, Ramsay Jones, Ævar Arnfjörð Bjarmason

Add a test for --exit-code working with --no-index. There's no reason
to suppose it wouldn't, but we weren't testing for it anywhere in our
tests. Let's fix that blind spot.

Signed-off-by: Ævar Arnfjörð Bjarmason <avarab@gmail.com>
---
 t/t4053-diff-no-index.sh | 5 +++++
 1 file changed, 5 insertions(+)

diff --git a/t/t4053-diff-no-index.sh b/t/t4053-diff-no-index.sh
index 0168946b639..44b932fbb20 100755
--- a/t/t4053-diff-no-index.sh
+++ b/t/t4053-diff-no-index.sh
@@ -16,6 +16,11 @@ test_expect_success 'setup' '
 	echo 1 >non/git/b
 '
 
+test_expect_success 'git diff --no-index --exit-code' '
+	git diff --no-index --exit-code a/1 non/git/a &&
+	test_expect_code 1 git diff --no-index --exit-code a/1 a/2
+'
+
 test_expect_success 'git diff --no-index directories' '
 	test_expect_code 1 git diff --no-index a b >cnt &&
 	test_line_count = 14 cnt
-- 
2.31.0.366.g871543fb182


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

* [PATCH v3 2/2] diff --no-index tests: test mode normalization
  2021-03-23 16:40                     ` [PATCH v3 " Ævar Arnfjörð Bjarmason
  2021-03-23 16:40                       ` [PATCH v3 1/2] diff --no-index tests: add test for --exit-code Ævar Arnfjörð Bjarmason
@ 2021-03-23 16:40                       ` Ævar Arnfjörð Bjarmason
  2021-03-23 16:47                       ` [PATCH v3 0/2] diff --no-index: fix test blind spots Junio C Hamano
  2 siblings, 0 replies; 262+ messages in thread
From: Ævar Arnfjörð Bjarmason @ 2021-03-23 16:40 UTC (permalink / raw)
  To: git; +Cc: Junio C Hamano, Ramsay Jones, Ævar Arnfjörð Bjarmason

When "git diff --no-index X Y" is run the modes of the files being
differ are normalized by canon_mode() in fill_filespec().

I recently broke that behavior in a patch of mine[1] which would pass
all tests, or not, depending on the umask of the git.git checkout.

Let's test for this explicitly. Arguably this should not be the
behavior of "git diff --no-index". We aren't diffing our own objects
or the index, so it might be useful to show mode differences between
files.

On the other hand diff(1) does not do that, and it would be needlessly
distracting when e.g. diffing an extracted tar archive whose contents
is the same, but whose file modes are different.

1. https://lore.kernel.org/git/20210316155829.31242-2-avarab@gmail.com/

Signed-off-by: Ævar Arnfjörð Bjarmason <avarab@gmail.com>
---
 t/t4053-diff-no-index.sh | 55 ++++++++++++++++++++++++++++++++++++++++
 1 file changed, 55 insertions(+)

diff --git a/t/t4053-diff-no-index.sh b/t/t4053-diff-no-index.sh
index 44b932fbb20..5c5545f91bf 100755
--- a/t/t4053-diff-no-index.sh
+++ b/t/t4053-diff-no-index.sh
@@ -149,4 +149,59 @@ test_expect_success 'diff --no-index allows external diff' '
 	test_cmp expect actual
 '
 
+test_expect_success 'diff --no-index normalizes mode: no changes' '
+	echo foo >x &&
+	cp x y &&
+	git diff --no-index x y >out &&
+	test_must_be_empty out
+'
+
+test_expect_success POSIXPERM 'diff --no-index normalizes mode: chmod +x' '
+	chmod +x y &&
+	cat >expected <<-\EOF &&
+	diff --git a/x b/y
+	old mode 100644
+	new mode 100755
+	EOF
+	test_expect_code 1 git diff --no-index x y >actual &&
+	test_cmp expected actual
+'
+
+test_expect_success POSIXPERM 'diff --no-index normalizes: mode not like git mode' '
+	chmod 666 x &&
+	chmod 777 y &&
+	cat >expected <<-\EOF &&
+	diff --git a/x b/y
+	old mode 100644
+	new mode 100755
+	EOF
+	test_expect_code 1 git diff --no-index x y >actual &&
+	test_cmp expected actual
+'
+
+test_expect_success POSIXPERM,SYMLINKS 'diff --no-index normalizes: mode not like git mode (symlink)' '
+	ln -s y z &&
+	X_OID=$(git hash-object --stdin <x) &&
+	Z_OID=$(printf "y" | git hash-object --stdin) &&
+	cat >expected <<-EOF &&
+	diff --git a/x b/x
+	deleted file mode 100644
+	index $X_OID..$ZERO_OID
+	--- a/x
+	+++ /dev/null
+	@@ -1 +0,0 @@
+	-foo
+	diff --git a/z b/z
+	new file mode 120000
+	index $ZERO_OID..$Z_OID
+	--- /dev/null
+	+++ b/z
+	@@ -0,0 +1 @@
+	+y
+	\ No newline at end of file
+	EOF
+	test_expect_code 1 git -c core.abbrev=no diff --no-index x z >actual &&
+	test_cmp expected actual
+'
+
 test_done
-- 
2.31.0.366.g871543fb182


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

* Re: [PATCH v3 0/2] diff --no-index: fix test blind spots
  2021-03-23 16:40                     ` [PATCH v3 " Ævar Arnfjörð Bjarmason
  2021-03-23 16:40                       ` [PATCH v3 1/2] diff --no-index tests: add test for --exit-code Ævar Arnfjörð Bjarmason
  2021-03-23 16:40                       ` [PATCH v3 2/2] diff --no-index tests: test mode normalization Ævar Arnfjörð Bjarmason
@ 2021-03-23 16:47                       ` Junio C Hamano
  2 siblings, 0 replies; 262+ messages in thread
From: Junio C Hamano @ 2021-03-23 16:47 UTC (permalink / raw)
  To: Ævar Arnfjörð Bjarmason; +Cc: git, Ramsay Jones

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

> Since v2[1]: s/echo -n/printf/ (and I re-adjusted my test setup to run
> the linting..)
>
> 1. https://lore.kernel.org/git/cover.1616366036.git.avarab@gmail.com/
>
> Ævar Arnfjörð Bjarmason (2):
>   diff --no-index tests: add test for --exit-code
>   diff --no-index tests: test mode normalization
>
>  t/t4053-diff-no-index.sh | 60 ++++++++++++++++++++++++++++++++++++++++
>  1 file changed, 60 insertions(+)
>
> Range-diff:
> 1:  2dbc6c253e2 = 1:  7dd5c309a70 diff --no-index tests: add test for --exit-code
> 2:  a1ab6a323f2 ! 2:  e5bb094b783 diff --no-index tests: test mode normalization
>     @@ t/t4053-diff-no-index.sh: test_expect_success 'diff --no-index allows external d
>      +test_expect_success POSIXPERM,SYMLINKS 'diff --no-index normalizes: mode not like git mode (symlink)' '
>      +	ln -s y z &&
>      +	X_OID=$(git hash-object --stdin <x) &&
>     -+	Z_OID=$(echo -n y | git hash-object --stdin) &&
>     ++	Z_OID=$(printf "y" | git hash-object --stdin) &&
>      +	cat >expected <<-EOF &&
>      +	diff --git a/x b/x
>      +	deleted file mode 100644

Thanks for a quick turnaround, and sorry for forgetting to say
"locally munged, no need to resend".

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

* [PATCH v5 00/18] tree-walk.h: slimmed down
  2021-03-21 18:42                   ` Ævar Arnfjörð Bjarmason
@ 2021-03-31 19:09                     ` Ævar Arnfjörð Bjarmason
  2021-03-31 19:09                       ` [PATCH v5 01/18] cache.h: add a comment to object_type() Ævar Arnfjörð Bjarmason
                                         ` (17 more replies)
  0 siblings, 18 replies; 262+ messages in thread
From: Ævar Arnfjörð Bjarmason @ 2021-03-31 19:09 UTC (permalink / raw)
  To: git; +Cc: Junio C Hamano, Elijah Newren, Ævar Arnfjörð Bjarmason

These are preparatory changes to the tree-walk.h API to eventually fix
long-broken git-fsck mode checks.

Per http://lore.kernel.org/git/xmqqtup5cnlu.fsf@gitster.g I think the
previous round of this was too big.

So here's a slimmed-down version which stops short of migrating
anything to "enum object_type". There's just:

 * Tests
 * Renaming relevant API *() to *_mode() (the next series will propose a *_type())
 * Adding *_path() API for those users that don't need the "mode" the
   *_mode() function provides
 * Comment updates, fixes to comments.
 * Whitespace changes that would be needed by the next series, but
   which are a good idea anyway while we're at it, e.g. aligning
   function declarations.

Ævar Arnfjörð Bjarmason (18):
  cache.h: add a comment to object_type()
  merge-ort: correct reference to test in 62fdec17a11
  cache.h: have base_name_compare() take "is tree?", not "mode"
  fast-import tests: test for sorting dir/file foo v.s. foo.txt
  mktree tests: test that "mode" is passed when sorting
  diff tests: test that "mode" is passed when sorting
  merge-tree tests: test for the mode comparison in same_entry()
  blame: emit a better error on 'git blame directory'
  notes & match-trees: use name_entry's "pathlen" member
  tree-walk.h users: use temporary variable(s) for "mode"
  match-trees: use "tmp" for mode in shift_tree_by()
  tree.h: format argument lists of read_tree() users
  tree-walk.h API: formatting changes for subsequent commit
  tree-walk.h API doc: improve documentation of get_tree_entry()
  tree-walk.h API: rename get_tree_entry() to get_tree_entry_mode()
  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()

 archive.c                       | 21 ++++----
 blame.c                         |  6 +--
 builtin/checkout.c              |  4 +-
 builtin/fast-import.c           | 12 +++--
 builtin/log.c                   |  5 +-
 builtin/ls-tree.c               |  4 +-
 builtin/merge-tree.c            | 12 +++--
 builtin/mktree.c                |  4 +-
 builtin/rm.c                    |  2 +-
 builtin/update-index.c          |  2 +-
 cache.h                         | 11 +++--
 combine-diff.c                  |  8 +--
 fsck.c                          |  2 +-
 line-log.c                      |  2 +-
 match-trees.c                   | 44 ++++++++---------
 merge-ort.c                     | 11 +++--
 merge-recursive.c               | 29 ++++++-----
 notes.c                         | 10 ++--
 object-name.c                   |  7 ++-
 read-cache.c                    | 16 +++---
 t/t1450-fsck.sh                 | 66 +++++++++++++++++++++++++
 t/t4300-merge-tree.sh           | 44 +++++++++++++++++
 t/t8004-blame-with-conflicts.sh | 21 ++++++++
 t/t9300-fast-import.sh          | 87 +++++++++++++++++++++++++++++++++
 tree-diff.c                     | 24 +++++----
 tree-walk.c                     | 30 ++++++++----
 tree-walk.h                     | 35 +++++++++----
 tree.h                          |  5 +-
 unpack-trees.c                  | 18 ++++---
 29 files changed, 410 insertions(+), 132 deletions(-)

Range-diff:
 1:  c307eb53331 <  -:  ----------- show tests: add test for "git show <tree>"
 2:  f37d7705cf0 <  -:  ----------- ls-files tests: add meaningful --with-tree tests
 3:  6291d8a1b5e <  -:  ----------- tree.c API: move read_tree() into builtin/ls-files.c
 4:  466b518e915 <  -:  ----------- ls-files: don't needlessly pass around stage variable
 5:  30c3abfe9b9 <  -:  ----------- ls-files: refactor away read_tree()
 6:  02c42be9249 <  -:  ----------- archive: stop passing "stage" through read_tree_recursive()
 7:  d55e8d4042b <  -:  ----------- tree.h API: expose read_tree_1() as read_tree_at()
 8:  fa157d8baee <  -:  ----------- tree.h API: simplify read_tree_recursive() signature
10:  186f7a7a44b =  1:  a74e02ff0ba cache.h: add a comment to object_type()
24:  092472f3c8d =  2:  57092359bbb merge-ort: correct reference to test in 62fdec17a11
16:  1b6a10f814c !  3:  44c3fdd0085 cache.h: have base_name_compare() take "is tree?", not "mode"
    @@ Commit message
         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".
    +    This introduces no functional change, but makes later (not part of
    +    this series) changes to abstract away "object_type" from "mode" more
    +    readable.
     
         The API being modified here was originally added way back in
         958ba6c96eb (Introduce "base_name_compare()" helper function,
    @@ 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 istree_a = (a->object_type == OBJ_TREE);
    -+	int istree_b = (b->object_type == OBJ_TREE);
    ++	int istree_a = S_ISDIR(a->mode);
    ++	int istree_b = S_ISDIR(b->mode);
     +	return base_name_compare(a->path, tree_entry_len(a), istree_a,
     +				 b->path, tree_entry_len(b), istree_b);
      }
    @@ tree-diff.c: static int tree_entry_pathcmp(struct tree_desc *t1, struct tree_des
      		return -1;
      
      	e1 = &t1->entry;
    -+	istree_e1 = (e1->object_type == OBJ_TREE);
    ++	istree_e1 = S_ISDIR(e1->mode);
      	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);
    ++	istree_e2 = S_ISDIR(e2->mode);
     +	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 do_compare_entry(const struct cache_entry *ce,
      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 istree = S_ISDIR(n->mode);
     +	int cmp = do_compare_entry(ce, info, n->path, n->pathlen, istree);
      	if (cmp)
      		return cmp;
13:  7016008554a =  4:  2ff35f410cd fast-import tests: test for sorting dir/file foo v.s. foo.txt
14:  b0546197b1b =  5:  b3289f7bbe5 mktree tests: test that "mode" is passed when sorting
15:  73e92ac187d =  6:  0be013e47c4 diff tests: test that "mode" is passed when sorting
23:  592fecb7abc !  7:  3367850559b merge-tree tests: test for the mode comparison in same_entry()
    @@ Commit message
         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 ##
36:  81da5490221 !  8:  3c2ca98716d blame: emit a better error on 'git blame directory'
    @@ Commit message
         something uniquely bad when in a conflicted merge. See
         cd8ae20195 (git-blame shouldn't crash if run in an unmerged tree,
         2007-10-18) and 9aeaab6811 (blame: allow "blame file" in the middle of
    -    a conflicted merge, 2012-09-11) for the bug the t8004 test was
    -    originally meant to address.
    +    a conflicted merge, 2012-09-11) for the bug the test was originally
    +    meant to address.
     
         But when extending it let's grep out the specific error message for
         good measure. Having to change it in the future (e.g. as part of my
    @@ Commit message
     
      ## blame.c ##
     @@ blame.c: static void verify_working_tree_path(struct repository *r,
    + 		struct object_id blob_oid;
    + 		unsigned short mode;
      
    - 	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);
    --
    --		if (!ret && oid_object_info(r, &blob_oid, NULL) == OBJ_BLOB)
    -+		struct object_id oid;
    -+		if (!get_tree_entry_path(r, commit_oid, path, &oid))
    +-		if (!get_tree_entry(r, commit_oid, path, &blob_oid, &mode) &&
    +-		    oid_object_info(r, &blob_oid, NULL) == OBJ_BLOB)
    ++		if (!get_tree_entry(r, commit_oid, path, &blob_oid, &mode))
      			return;
      	}
      
 9:  0390b1e9ded =  9:  749be26bf8e notes & match-trees: use name_entry's "pathlen" member
11:  4fed508f3cb <  -:  ----------- tree-walk.h: add object_type member to name_entry
12:  c557b67231b <  -:  ----------- tree-walk.c: migrate to using new "object_type" field when possible
17:  f8912a409b5 <  -:  ----------- tree-walk.h users: switch object_type(...) to new .object_type
26:  4babecb7855 ! 10:  5c0a49c188f tree-walk.h users: use temporary variable(s) for "mode"
    @@ Commit message
         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
    +    This will make those later 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: static struct merge_list *link_entry(unsigned stage, const
      	struct merge_list *link;
     +	unsigned int link_mode;
      
    - 	if (n->object_type == OBJ_NONE)
    + 	if (!n->mode)
      		return entry;
     @@ builtin/merge-tree.c: static struct merge_list *link_entry(unsigned stage, const struct traverse_info
      		path = entry->path;
29:  40f37e99cd9 ! 11:  e190ed39754 match-trees: use "tmp" for mode in shift_tree_by()
    @@ match-trees.c: 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_mode(r, hash1, shift_prefix, &sub1, &mode1) &&
    +-	if (!get_tree_entry(r, hash1, shift_prefix, &sub1, &mode1) &&
     -	    S_ISDIR(mode1))
    -+	if (!get_tree_entry_mode(r, hash1, shift_prefix, &sub1, &tmp) &&
    ++	if (!get_tree_entry(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) &&
    +-	if (!get_tree_entry(r, hash2, shift_prefix, &sub2, &mode2) &&
     -	    S_ISDIR(mode2))
    -+	if (!get_tree_entry_mode(r, hash2, shift_prefix, &sub2, &tmp) &&
    ++	if (!get_tree_entry(r, hash2, shift_prefix, &sub2, &tmp) &&
     +	    S_ISDIR(tmp))
      		candidate |= 2;
      
18:  df43f1a76ac ! 12:  960e15bc7d5 tree.h: format argument lists of read_tree_recursive() users
    @@ Metadata
     Author: Ævar Arnfjörð Bjarmason <avarab@gmail.com>
     
      ## Commit message ##
    -    tree.h: format argument lists of read_tree_recursive() users
    +    tree.h: format argument lists of read_tree() users
     
    -    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
    +    Re-indent and format the argument list of read_tree() 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.
    +    This is a whitespace-only change to make changes in a later series
    +    easier to read. In that series I'll be adding a new argument on the
    +    "mode" line, so leave space on it for a new argument.
     
         Signed-off-by: Ævar Arnfjörð Bjarmason <avarab@gmail.com>
     
19:  152c6d88542 <  -:  ----------- tree.h API: make read_tree_fn_t take an "enum object_type"
20:  1c2f65cb674 <  -:  ----------- tree-walk.h users: migrate "p->mode &&" pattern
21:  163922d427c <  -:  ----------- tree-walk.h users: refactor chained "mode" if/else into switch
22:  21df7c668be <  -:  ----------- tree-walk.h users: migrate miscellaneous "mode" to "object_type"
25:  685da1abbdc <  -:  ----------- fsck.c: switch on "object_type" in fsck_walk_tree()
27:  7251654dd52 ! 13:  9c96d472472 tree-walk.h API: formatting changes for subsequent commit
    @@ Commit message
     
         Signed-off-by: Ævar Arnfjörð Bjarmason <avarab@gmail.com>
     
    - ## blame.c ##
    -@@ blame.c: 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;
    - 	}
    - 
    -
      ## tree-walk.c ##
     @@ tree-walk.c: static int find_tree_entry(struct repository *r, struct tree_desc *t,
      			oidcpy(result, &oid);
30:  7f699bf2d5c ! 14:  44f16d74426 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 doc: improve documentation of get_tree_entry()
     
    -    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.
    +    Change a mention of sha1 to OID and change the comment to a listing of
    +    functions discussed below, right now there's only one function, but
    +    subsequent commits will add more.
     
         Signed-off-by: Ævar Arnfjörð Bjarmason <avarab@gmail.com>
     
    - ## archive.c ##
    -@@ archive.c: 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);
    -
    - ## match-trees.c ##
    -@@ match-trees.c: 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) {
    -
    - ## 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)
    -+			   unsigned short *mode,
    -+			   enum object_type *object_type)
    - {
    - 	int namelen = strlen(name);
    - 	while (t->size) {
    -@@ tree-walk.c: 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;
    -@@ tree-walk.c: 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
    -@@ tree-walk.c: 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;
    -@@ tree-walk.c: 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;
    - 		}
    -
      ## tree-walk.h ##
     @@ tree-walk.h: struct traverse_info {
    -  * Find an entry in a tree given a pathname and the sha1 of a tree to
    + };
    + 
    + /**
    +- * Find an entry in a tree given a pathname and the sha1 of a tree to
    ++ * Find an entry in a tree given a pathname and the OID 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!):
    ++ * You always need a pointer to an appropriate variable to fill in
    ++ * (NULL won't do!). That variable is:
     + *
    -+ * get_tree_entry_mode(): unsigned int mode
    -+ * get_tree_entry_type(): enum object_type
    ++ * get_tree_entry(): unsigned short mode
       */
    - 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
    + int get_tree_entry(struct repository *, const struct object_id *, const char *,
    + 		   struct object_id *,
28:  9e521a3cbf2 ! 15:  adbada0ade8 tree-walk.h API: rename get_tree_entry() to get_tree_entry_mode()
    @@ Commit message
         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.
    +    Subsequent commits will add another get_tree_entry_*() function. Those
    +    changes will be much easier to read if we do this rename first.
     
         Signed-off-by: Ævar Arnfjörð Bjarmason <avarab@gmail.com>
     
    @@ blame.c: 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)
    +-
    +-		if (!get_tree_entry(r, commit_oid, path, &blob_oid, &mode))
    ++		if (!get_tree_entry_mode(r, commit_oid, path, &blob_oid, &mode))
      			return;
    + 	}
    + 
     @@ blame.c: static int fill_blob_sha1_and_mode(struct repository *r,
      {
      	if (!is_null_oid(&origin->blob_oid))
    @@ match-trees.c: 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))
    +-	if (!get_tree_entry(r, hash1, shift_prefix, &sub1, &tmp) &&
    ++	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(r, hash2, shift_prefix, &sub2, &mode2) &&
    -+	if (!get_tree_entry_mode(r, hash2, shift_prefix, &sub2, &mode2) &&
    - 	    S_ISDIR(mode2))
    +-	if (!get_tree_entry(r, hash2, shift_prefix, &sub2, &tmp) &&
    ++	if (!get_tree_entry_mode(r, hash2, shift_prefix, &sub2, &tmp) &&
    + 	    S_ISDIR(tmp))
      		candidate |= 2;
      
     
    @@ tree-walk.c: static int find_tree_entry(struct repository *r, struct tree_desc *
     
      ## tree-walk.h ##
     @@ tree-walk.h: struct traverse_info {
    -  * The third and fourth parameters are set to the entry's sha1 and
    -  * mode respectively.
    +  * You always need a pointer to an appropriate variable to fill in
    +  * (NULL won't do!). That variable is:
    +  *
    +- * get_tree_entry(): unsigned short mode
    ++ * get_tree_entry_mode(): unsigned short mode
       */
     -int get_tree_entry(struct repository *, const struct object_id *, const char *,
     -		   struct object_id *,
35:  a2a34fd3e2d ! 16:  3ba77fd3a47 tree-walk.h API: add a get_tree_entry_path() function
    @@ Commit message
         tree-walk.h API: add a get_tree_entry_path() function
     
         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.
    +    get_tree_entry_path_mode(). This is for those callers that don't need
    +    the "mode" filled for them.
     
    -    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.
    +    There are callers here which don't need the "struct object_id" filled
    +    either, but let's leave that for now. I'm focusing downstream code
    +    that depends on "mode" (or "enum object_type").
     
    -    See the following commits for the introduction of such code that's
    -    being modified here:
    +    The code being modified here was introduced in:
     
          - shift_tree(): 68faf68938e (A new merge stragety[sic] 'subtree'.,
             2007-02-15) for the shift_tree()
    @@ Commit message
          - 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 ##
    @@ object-name.c: static void diagnose_invalid_oid_path(struct repository *r,
      			    fullname,
     
      ## tree-walk.c ##
    -@@ tree-walk.c: int get_tree_entry_all(struct repository *r,
    +@@ tree-walk.c: int get_tree_entry_mode(struct repository *r,
      	return retval;
      }
      
    @@ tree-walk.c: int get_tree_entry_all(struct repository *r,
     +			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);
    ++	return get_tree_entry_mode(r, tree_oid, name, oid, &mode);
     +}
     +
    - int get_tree_entry_mode(struct repository *r,
    - 			const struct object_id *tree_oid,
    - 			const char *name,
    + /*
    +  * 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
     
      ## tree-walk.h ##
     @@ tree-walk.h: 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!):
    +  * You always need a pointer to an appropriate variable to fill in
    +  * (NULL won't do!). That variable is:
       *
     + * 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
    +  * get_tree_entry_mode(): unsigned short mode
       */
     +int get_tree_entry_path(struct repository *, const struct object_id *, const char *,
     +			struct object_id *);
31:  7ab7576cb16 ! 17:  dc895822828 tree-walk.h API: document and format tree_entry_extract()
    @@ Commit message
         tree-walk.h API: document and format tree_entry_extract()
     
         Document and format the argument list of the tree_entry_extract()
    -    function in preparation for adding a sister function.
    +    function in preparation for eventually adding a sister function.
     
         Signed-off-by: Ævar Arnfjörð Bjarmason <avarab@gmail.com>
     
    @@ tree-walk.h: struct tree_desc {
     + * "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
    ++ * tree_entry_extract(): 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,
32:  a1bd81d64aa ! 18:  e961a0e8b5b 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 {
    +  * "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
    +- * tree_entry_extract(): const char *path, unsigned int mode
    ++ * 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,
33:  ce7c19ad39c <  -:  ----------- tree-walk.h API: add a tree_entry_extract_all() function
34:  95eec961be8 <  -:  ----------- tree-walk.h API: add get_tree_entry_all()
37:  4d51da4ea39 <  -:  ----------- tree-walk.h API: add a tree_entry_extract_type() function
-- 
2.31.1.474.g72d45d12706


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

* [PATCH v5 01/18] cache.h: add a comment to object_type()
  2021-03-31 19:09                     ` [PATCH v5 00/18] tree-walk.h: slimmed down Ævar Arnfjörð Bjarmason
@ 2021-03-31 19:09                       ` Ævar Arnfjörð Bjarmason
  2021-03-31 22:33                         ` Junio C Hamano
  2021-03-31 19:09                       ` [PATCH v5 02/18] merge-ort: correct reference to test in 62fdec17a11 Ævar Arnfjörð Bjarmason
                                         ` (16 subsequent siblings)
  17 siblings, 1 reply; 262+ messages in thread
From: Ævar Arnfjörð Bjarmason @ 2021-03-31 19:09 UTC (permalink / raw)
  To: git; +Cc: Junio C Hamano, Elijah Newren, Æ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 57f2285bba9..41e99bd9c63 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.1.474.g72d45d12706


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

* [PATCH v5 02/18] merge-ort: correct reference to test in 62fdec17a11
  2021-03-31 19:09                     ` [PATCH v5 00/18] tree-walk.h: slimmed down Ævar Arnfjörð Bjarmason
  2021-03-31 19:09                       ` [PATCH v5 01/18] cache.h: add a comment to object_type() Ævar Arnfjörð Bjarmason
@ 2021-03-31 19:09                       ` Ævar Arnfjörð Bjarmason
  2021-03-31 19:09                       ` [PATCH v5 03/18] cache.h: have base_name_compare() take "is tree?", not "mode" Ævar Arnfjörð Bjarmason
                                         ` (15 subsequent siblings)
  17 siblings, 0 replies; 262+ messages in thread
From: Ævar Arnfjörð Bjarmason @ 2021-03-31 19:09 UTC (permalink / raw)
  To: git; +Cc: Junio C Hamano, Elijah Newren, Æ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 ba35600d4e0..dd1f38e3c32 100644
--- a/merge-ort.c
+++ b/merge-ort.c
@@ -1073,7 +1073,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.1.474.g72d45d12706


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

* [PATCH v5 03/18] cache.h: have base_name_compare() take "is tree?", not "mode"
  2021-03-31 19:09                     ` [PATCH v5 00/18] tree-walk.h: slimmed down Ævar Arnfjörð Bjarmason
  2021-03-31 19:09                       ` [PATCH v5 01/18] cache.h: add a comment to object_type() Ævar Arnfjörð Bjarmason
  2021-03-31 19:09                       ` [PATCH v5 02/18] merge-ort: correct reference to test in 62fdec17a11 Ævar Arnfjörð Bjarmason
@ 2021-03-31 19:09                       ` Ævar Arnfjörð Bjarmason
  2021-03-31 22:55                         ` Junio C Hamano
  2021-03-31 19:09                       ` [PATCH v5 04/18] fast-import tests: test for sorting dir/file foo v.s. foo.txt Ævar Arnfjörð Bjarmason
                                         ` (14 subsequent siblings)
  17 siblings, 1 reply; 262+ messages in thread
From: Ævar Arnfjörð Bjarmason @ 2021-03-31 19:09 UTC (permalink / raw)
  To: git; +Cc: Junio C Hamano, Elijah Newren, Æ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 introduces no functional change, but makes later (not part of
this series) changes to abstract away "object_type" from "mode" more
readable.

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

None of these comparison functions used to have tests, but with
preceding commits some of them now do. I thought the remainder was
trivial enough to review without tests, and didn't want to spend more
time on them.

Signed-off-by: Ævar Arnfjörð Bjarmason <avarab@gmail.com>
---
 builtin/fast-import.c | 12 ++++++++----
 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, 47 insertions(+), 35 deletions(-)

diff --git a/builtin/fast-import.c b/builtin/fast-import.c
index 3afa81cf9ac..2fb56d6e9b7 100644
--- a/builtin/fast-import.c
+++ b/builtin/fast-import.c
@@ -1287,18 +1287,22 @@ 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);
+	int istree_a = S_ISDIR(a->versions[0].mode);
+	int istree_b = S_ISDIR(b->versions[0].mode);
 	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, istree_a,
+		b->name->str_dat, b->name->str_len, istree_b);
 }
 
 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);
+	int istree_a = S_ISDIR(a->versions[1].mode);
+	int istree_b = S_ISDIR(b->versions[1].mode);
 	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, istree_a,
+		b->name->str_dat, b->name->str_len, istree_b);
 }
 
 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 41e99bd9c63..3bcea022ad2 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 06635f91bc2..155d52971e6 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 f6c194c1cca..48f3e0ed526 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 = S_ISDIR(a->mode);
+	int istree_b = S_ISDIR(b->mode);
+	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 dd1f38e3c32..97b8670c0a5 100644
--- a/merge-ort.c
+++ b/merge-ort.c
@@ -2257,8 +2257,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 ed31f9496cb..97520a88646 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 5a907af2fb5..6e0b41ed175 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..644b4656421 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 = S_ISDIR(e1->mode);
 	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 = S_ISDIR(e2->mode);
+	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 29029f34ed6..23c1640ae9a 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 = S_ISDIR(n->mode);
+	int cmp = do_compare_entry(ce, info, n->path, n->pathlen, istree);
 	if (cmp)
 		return cmp;
 
-- 
2.31.1.474.g72d45d12706


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

* [PATCH v5 04/18] fast-import tests: test for sorting dir/file foo v.s. foo.txt
  2021-03-31 19:09                     ` [PATCH v5 00/18] tree-walk.h: slimmed down Ævar Arnfjörð Bjarmason
                                         ` (2 preceding siblings ...)
  2021-03-31 19:09                       ` [PATCH v5 03/18] cache.h: have base_name_compare() take "is tree?", not "mode" Ævar Arnfjörð Bjarmason
@ 2021-03-31 19:09                       ` Ævar Arnfjörð Bjarmason
  2021-03-31 19:09                       ` [PATCH v5 05/18] mktree tests: test that "mode" is passed when sorting Ævar Arnfjörð Bjarmason
                                         ` (13 subsequent siblings)
  17 siblings, 0 replies; 262+ messages in thread
From: Ævar Arnfjörð Bjarmason @ 2021-03-31 19:09 UTC (permalink / raw)
  To: git; +Cc: Junio C Hamano, Elijah Newren, Ævar Arnfjörð Bjarmason

Add a missing test for the sorting of "foo" v.s. "foo.txt" where "foo"
can be either a file or a directory. If it's a file then "foo" should
sort before "foo.txt", and the other way around if "foo" is a
directory.

See [1] for a reply to a patch of mine introducing such a
regression. We now finally have a test for this code added back in
463acbe1c6 (Added tree and commit writing to fast-import.,
2006-08-14).

This tests both the tecmp1() and tecmp0() functions introduced inn
4cabf8583f (Implemented tree delta compression in fast-import.,
2006-08-28).

This will catch cases where the "mode" is the same, or reversed
between a & b in both functions.

There was an existing test for the tecmp1() function(s) just above
this one added here.

That existing test was added in e741130386 (New fast-import test case
for valid tree sorting, 2007-03-12) and would catch cases where
entries were reversed, but not if their mode (or rather, type) was the
the same or otherwise wrong value.

There were no tests at all for the tecmp0() function. As with the
tecmp1() test the new test will catch cases where the "mode" is the
same (e.g. "1"), or if the two are reversed. It won't catch a "return
0" from the function (i.e. already sorted), that case requires
tecmp1() to also be broken.

1. https://lore.kernel.org/git/CABPp-BEZfG_pNNTWsnxEa1xG+kgpQfpXj=KHBkCBAMikrXj-aA@mail.gmail.com/

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

diff --git a/t/t9300-fast-import.sh b/t/t9300-fast-import.sh
index 5c47ac4465c..8bafb8cc515 100755
--- a/t/t9300-fast-import.sh
+++ b/t/t9300-fast-import.sh
@@ -955,6 +955,93 @@ test_expect_success 'L: verify internal tree sorting' '
 	test_cmp expect actual
 '
 
+test_expect_success 'L: verify internal tree sorting on bad input (tecmp1)' '
+	test_create_repo L1-0 &&
+
+	cat >input <<-INPUT_END &&
+	blob
+	mark :1
+	data 0
+
+	reset refs/heads/L1-0
+	commit refs/heads/L1-0
+	committer $GIT_COMMITTER_NAME <$GIT_COMMITTER_EMAIL> $GIT_COMMITTER_DATE
+	data <<COMMIT
+	create L1-0
+	COMMIT
+	M 100644 :1 x.txt
+	M 100644 :1 x/y.txt
+	M 100644 :1 z.txt
+	M 100644 :1 z
+	INPUT_END
+
+	cat >expected <<-EXPECT_END &&
+	x.txt
+	x
+	z
+	z.txt
+	EXPECT_END
+
+	git -C L1-0 fast-import <input &&
+	git -C L1-0 ls-tree L1-0 >tmp &&
+	cut -f 2 <tmp >actual &&
+	test_cmp expected actual &&
+	git -C L1-0 fsck 2>err &&
+	# Would happen if tecmp1() were broken
+	! grep "error in tree .*: treeNotSorted: " err
+'
+
+test_expect_success 'L: verify internal tree sorting on bad input (tecmp0)' '
+
+	test_create_repo L1-1 &&
+
+	cat >input <<-INPUT_END &&
+	blob
+	mark :1
+	data <<EOF
+	some data
+	EOF
+
+	reset refs/heads/L1-1
+	commit refs/heads/L1-1
+	committer $GIT_COMMITTER_NAME <$GIT_COMMITTER_EMAIL> $GIT_COMMITTER_DATE
+	data <<COMMIT
+	create L1-1
+	COMMIT
+	M 100644 :1 x.txt
+	M 100644 :1 x/y.txt
+	M 100644 :1 z.txt
+	M 100644 :1 z
+
+	commit refs/heads/L1-1
+	committer $GIT_COMMITTER_NAME <$GIT_COMMITTER_EMAIL> $GIT_COMMITTER_DATE
+	data <<COMMIT
+	update L1-1
+	COMMIT
+	M 100644 :1 another.txt
+	M 100644 :1 x.txt
+	M 100644 :1 x/y.txt
+	M 100644 :1 z.txt
+	M 100644 :1 z
+	INPUT_END
+
+	cat >expected <<-EXPECT_END &&
+	another.txt
+	x.txt
+	x
+	z
+	z.txt
+	EXPECT_END
+
+	git -C L1-1 fast-import <input &&
+	git -C L1-1 ls-tree L1-1 >tmp 2>err &&
+	# Would happen if tecmp0() passed a fixed mode
+	! grep "fatal: not a tree object" err &&
+	cut -f 2 <tmp >actual &&
+	test_cmp expected actual &&
+	git -C L1-1 fsck
+'
+
 test_expect_success 'L: nested tree copy does not corrupt deltas' '
 	cat >input <<-INPUT_END &&
 	blob
-- 
2.31.1.474.g72d45d12706


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

* [PATCH v5 05/18] mktree tests: test that "mode" is passed when sorting
  2021-03-31 19:09                     ` [PATCH v5 00/18] tree-walk.h: slimmed down Ævar Arnfjörð Bjarmason
                                         ` (3 preceding siblings ...)
  2021-03-31 19:09                       ` [PATCH v5 04/18] fast-import tests: test for sorting dir/file foo v.s. foo.txt Ævar Arnfjörð Bjarmason
@ 2021-03-31 19:09                       ` Ævar Arnfjörð Bjarmason
  2021-03-31 23:04                         ` Junio C Hamano
  2021-03-31 19:09                       ` [PATCH v5 06/18] diff " Ævar Arnfjörð Bjarmason
                                         ` (12 subsequent siblings)
  17 siblings, 1 reply; 262+ messages in thread
From: Ævar Arnfjörð Bjarmason @ 2021-03-31 19:09 UTC (permalink / raw)
  To: git; +Cc: Junio C Hamano, Elijah Newren, Ævar Arnfjörð Bjarmason

Add a test for the mode being passed to ent_compare(). That code dates
back to 83f50539a9 (git-mktree: reverse of git-ls-tree., 2006-02-20)
and there's never been a test for that particular edge case. Now we
have one.

I don't see how anything could run into this in practice. In order for
that mode sorting to matter as a tiebreaker we need to have a
duplicate entry in the tree, i.e. two "foo" entries, one a blob and
one a tree. This asserts that if that happens we'll sort on the modes
we encounter in such an invalid entry, i.e. we expect the tree entry
before the blob.

As shown here we'd need to disable the fsck.duplicateEntries error to
get to the point of running "mktree", so I doubt anyone's pushing this
sort of data around.

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

diff --git a/t/t1450-fsck.sh b/t/t1450-fsck.sh
index 5071ac63a5b..46125190b45 100755
--- a/t/t1450-fsck.sh
+++ b/t/t1450-fsck.sh
@@ -318,6 +318,50 @@ test_expect_success 'tree entry with type mismatch' '
 	test_i18ngrep ! "dangling blob" out
 '
 
+test_expect_success 'tree entry with duplicate type mismatching objects' '
+	test_create_repo duplicate-entry &&
+	(
+		cd duplicate-entry &&
+		blob="$(printf "foo" | git hash-object -w --stdin)" &&
+		tree="$(printf "100644 blob $blob\tfoo" | git mktree)" &&
+		commit="$(git commit-tree $tree -m "first commit")" &&
+		git cat-file commit $commit >good-commit &&
+
+		# First bad commit, wrong type, but in the right order
+		printf "40000 A\0$(echo $tree | hex2oct)" >broken-tree-A &&
+		printf "100644 A\0$(echo $blob | hex2oct)" >broken-tree-B &&
+		cat broken-tree-A broken-tree-B >broken-tree.1 &&
+		broken_tree1="$(git hash-object -w --literally -t tree broken-tree.1)" &&
+		bad_commit1="$(git commit-tree $broken_tree1 -m "bad commit 1")" &&
+		git cat-file commit $bad_commit1 >bad-commit.1 &&
+		git update-ref refs/heads/broken-commit-1 $bad_commit1 &&
+
+		test_must_fail git fsck &&
+		git -c fsck.duplicateEntries=warn fsck 2>err &&
+		grep " in tree .*$broken_tree1: duplicateEntries" err &&
+
+		# Second bad commits, wrong types and order
+		cat broken-tree-B broken-tree-A >broken-tree.2 &&
+		broken_tree2="$(git hash-object -w --literally -t tree broken-tree.2)" &&
+		bad_commit2="$(git commit-tree $broken_tree2 -m "bad commit 2")" &&
+		git cat-file commit $bad_commit2 >bad-commit.2 &&
+		git update-ref refs/heads/broken-commit-2 $bad_commit2 &&
+
+		test_must_fail git fsck &&
+		git -c fsck.duplicateEntries=warn fsck 2>err &&
+		grep " in tree .*$broken_tree2: duplicateEntries" err &&
+
+		# git mktree should "fix" the order of this already broken data
+		git ls-tree broken-commit-1 >broken-tree-1-ls &&
+		git ls-tree broken-commit-2 >broken-tree-2-ls &&
+		! test_cmp broken-tree-1-ls broken-tree-2-ls &&
+
+		git mktree <broken-tree-1-ls >broken-mktree-1 &&
+		git mktree <broken-tree-2-ls >broken-mktree-2 &&
+		test_cmp broken-mktree-1 broken-mktree-2
+	)
+'
+
 test_expect_success 'tag pointing to nonexistent' '
 	badoid=$(test_oid deadbeef) &&
 	cat >invalid-tag <<-EOF &&
-- 
2.31.1.474.g72d45d12706


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

* [PATCH v5 06/18] diff tests: test that "mode" is passed when sorting
  2021-03-31 19:09                     ` [PATCH v5 00/18] tree-walk.h: slimmed down Ævar Arnfjörð Bjarmason
                                         ` (4 preceding siblings ...)
  2021-03-31 19:09                       ` [PATCH v5 05/18] mktree tests: test that "mode" is passed when sorting Ævar Arnfjörð Bjarmason
@ 2021-03-31 19:09                       ` Ævar Arnfjörð Bjarmason
  2021-03-31 23:07                         ` Junio C Hamano
  2021-03-31 19:09                       ` [PATCH v5 07/18] merge-tree tests: test for the mode comparison in same_entry() Ævar Arnfjörð Bjarmason
                                         ` (11 subsequent siblings)
  17 siblings, 1 reply; 262+ messages in thread
From: Ævar Arnfjörð Bjarmason @ 2021-03-31 19:09 UTC (permalink / raw)
  To: git; +Cc: Junio C Hamano, Elijah Newren, Ævar Arnfjörð Bjarmason

Piggy-back on the recently added fsck tests for mode comparisons in
mktree and assert that diff-tree also does the right thing in this
implausible scenario.

As with the other tests I've added in preceding commits, these tests
will fail if the mode is the same or reversed, respectively.

The diff-tree code being tested here was originally added back in
.9174026cfe (Add "diff-tree" program to show which files have changed
between two trees., 2005-04-09).

Unlike the other tests I've added there are existing tests for both of
these scenarios. Breaking that function as described above will make
tests in t4002-diff-basic.sh, t6409-merge-subtree.sh and
t4037-diff-r-t-dirs.sh fail.

I think it's good to have tests for this regardless, so let's add
these.

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

diff --git a/t/t1450-fsck.sh b/t/t1450-fsck.sh
index 46125190b45..5dd842bb82c 100755
--- a/t/t1450-fsck.sh
+++ b/t/t1450-fsck.sh
@@ -362,6 +362,28 @@ test_expect_success 'tree entry with duplicate type mismatching objects' '
 	)
 '
 
+test_expect_success 'diff-tree stressing tree-diff.c::tree_entry_pathcmp(), not the same type' '
+	zero=$(test_oid zero) &&
+	git -C duplicate-entry diff-tree broken-commit-1 broken-commit-2 >1-to-2 &&
+	grep "$zero" 1-to-2 >lines &&
+	test_line_count = 2 lines &&
+
+	git -C duplicate-entry diff-tree broken-commit-2 broken-commit-1 >2-to-1 &&
+	grep "$zero" 2-to-1 >lines &&
+	test_line_count = 2 lines
+'
+
+test_expect_success 'diff-tree stressing tree-diff.c::tree_entry_pathcmp(), types not reversed' '
+	blob_ok=$(git -C duplicate-entry rev-parse broken-commit-2:A) &&
+	git -C duplicate-entry diff-tree --diff-filter=A broken-commit-1 broken-commit-2 >1-to-2 &&
+	grep "$blob_ok" 1-to-2 &&
+	test_line_count = 1 1-to-2 &&
+
+	git -C duplicate-entry diff-tree --diff-filter=A broken-commit-2 broken-commit-1 >2-to-1 &&
+	grep "$blob_ok" 2-to-1 &&
+	test_line_count = 1 2-to-1
+'
+
 test_expect_success 'tag pointing to nonexistent' '
 	badoid=$(test_oid deadbeef) &&
 	cat >invalid-tag <<-EOF &&
-- 
2.31.1.474.g72d45d12706


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

* [PATCH v5 07/18] merge-tree tests: test for the mode comparison in same_entry()
  2021-03-31 19:09                     ` [PATCH v5 00/18] tree-walk.h: slimmed down Ævar Arnfjörð Bjarmason
                                         ` (5 preceding siblings ...)
  2021-03-31 19:09                       ` [PATCH v5 06/18] diff " Ævar Arnfjörð Bjarmason
@ 2021-03-31 19:09                       ` Ævar Arnfjörð Bjarmason
  2021-03-31 23:12                         ` Junio C Hamano
  2021-03-31 19:09                       ` [PATCH v5 08/18] blame: emit a better error on 'git blame directory' Ævar Arnfjörð Bjarmason
                                         ` (10 subsequent siblings)
  17 siblings, 1 reply; 262+ messages in thread
From: Ævar Arnfjörð Bjarmason @ 2021-03-31 19:09 UTC (permalink / raw)
  To: git; +Cc: Junio C Hamano, Elijah Newren, Æ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().

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.1.474.g72d45d12706


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

* [PATCH v5 08/18] blame: emit a better error on 'git blame directory'
  2021-03-31 19:09                     ` [PATCH v5 00/18] tree-walk.h: slimmed down Ævar Arnfjörð Bjarmason
                                         ` (6 preceding siblings ...)
  2021-03-31 19:09                       ` [PATCH v5 07/18] merge-tree tests: test for the mode comparison in same_entry() Ævar Arnfjörð Bjarmason
@ 2021-03-31 19:09                       ` Ævar Arnfjörð Bjarmason
  2021-03-31 23:26                         ` Junio C Hamano
  2021-03-31 19:09                       ` [PATCH v5 09/18] notes & match-trees: use name_entry's "pathlen" member Ævar Arnfjörð Bjarmason
                                         ` (9 subsequent siblings)
  17 siblings, 1 reply; 262+ messages in thread
From: Ævar Arnfjörð Bjarmason @ 2021-03-31 19:09 UTC (permalink / raw)
  To: git; +Cc: Junio C Hamano, Elijah Newren, Æ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

The main point of this test is to assert that we're not doing
something uniquely bad when in a conflicted merge. See
cd8ae20195 (git-blame shouldn't crash if run in an unmerged tree,
2007-10-18) and 9aeaab6811 (blame: allow "blame file" in the middle of
a conflicted merge, 2012-09-11) for the bug the test was originally
meant to address.

But when extending it let's grep out the specific error message for
good measure. Having to change it in the future (e.g. as part of my
parallel series to improve such 'OID does not match type' messages) is
a small price for ensuring it doesn't regress.

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

diff --git a/blame.c b/blame.c
index 5018bb8fb2c..d1fa3821a08 100644
--- a/blame.c
+++ b/blame.c
@@ -103,8 +103,7 @@ static void verify_working_tree_path(struct repository *r,
 		struct object_id blob_oid;
 		unsigned short mode;
 
-		if (!get_tree_entry(r, commit_oid, path, &blob_oid, &mode) &&
-		    oid_object_info(r, &blob_oid, NULL) == OBJ_BLOB)
+		if (!get_tree_entry(r, commit_oid, path, &blob_oid, &mode))
 			return;
 	}
 
diff --git a/t/t8004-blame-with-conflicts.sh b/t/t8004-blame-with-conflicts.sh
index 35414a53363..5e3dea35a50 100755
--- a/t/t8004-blame-with-conflicts.sh
+++ b/t/t8004-blame-with-conflicts.sh
@@ -73,4 +73,25 @@ test_expect_success 'blame does not crash with conflicted file in stages 1,3' '
 	git blame file1
 '
 
+test_expect_success 'setup second case' '
+	git merge --abort
+'
+
+test_expect_success 'blame on directory/file conflict' '
+	mkdir d &&
+	test_commit second &&
+	test_commit d/file &&
+	test_must_fail git blame d 2>expected &&
+	grep "unsupported file type d" expected &&
+
+	git reset --hard second &&
+	>d &&
+	git add d &&
+	git commit -m"a not-a-dir" &&
+	test_must_fail git merge d/file &&
+
+	test_must_fail git blame d 2>actual &&
+	test_cmp expected actual
+'
+
 test_done
-- 
2.31.1.474.g72d45d12706


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

* [PATCH v5 09/18] notes & match-trees: use name_entry's "pathlen" member
  2021-03-31 19:09                     ` [PATCH v5 00/18] tree-walk.h: slimmed down Ævar Arnfjörð Bjarmason
                                         ` (7 preceding siblings ...)
  2021-03-31 19:09                       ` [PATCH v5 08/18] blame: emit a better error on 'git blame directory' Ævar Arnfjörð Bjarmason
@ 2021-03-31 19:09                       ` Ævar Arnfjörð Bjarmason
  2021-03-31 23:32                         ` Junio C Hamano
  2021-03-31 19:09                       ` [PATCH v5 10/18] tree-walk.h users: use temporary variable(s) for "mode" Ævar Arnfjörð Bjarmason
                                         ` (8 subsequent siblings)
  17 siblings, 1 reply; 262+ messages in thread
From: Ævar Arnfjörð Bjarmason @ 2021-03-31 19:09 UTC (permalink / raw)
  To: git; +Cc: Junio C Hamano, Elijah Newren, Æ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 48f3e0ed526..4ad0ca18256 100644
--- a/match-trees.c
+++ b/match-trees.c
@@ -199,9 +199,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,
@@ -216,9 +217,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 a19e4ad7943..e2fec12a39e 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.1.474.g72d45d12706


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

* [PATCH v5 10/18] tree-walk.h users: use temporary variable(s) for "mode"
  2021-03-31 19:09                     ` [PATCH v5 00/18] tree-walk.h: slimmed down Ævar Arnfjörð Bjarmason
                                         ` (8 preceding siblings ...)
  2021-03-31 19:09                       ` [PATCH v5 09/18] notes & match-trees: use name_entry's "pathlen" member Ævar Arnfjörð Bjarmason
@ 2021-03-31 19:09                       ` Ævar Arnfjörð Bjarmason
  2021-03-31 19:09                       ` [PATCH v5 11/18] match-trees: use "tmp" for mode in shift_tree_by() Ævar Arnfjörð Bjarmason
                                         ` (7 subsequent siblings)
  17 siblings, 0 replies; 262+ messages in thread
From: Ævar Arnfjörð Bjarmason @ 2021-03-31 19:09 UTC (permalink / raw)
  To: git; +Cc: Junio C Hamano, Elijah Newren, Æ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 those later 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 de8520778d2..c03353b5457 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->mode)
 		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 4ad0ca18256..a6796de442d 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 97b8670c0a5..de565a1f12e 100644
--- a/merge-ort.c
+++ b/merge-ort.c
@@ -538,11 +538,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 e2fec12a39e..00aa7d4115a 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 644b4656421..b7a76cc2620 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 23c1640ae9a..e804c7919b7 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.1.474.g72d45d12706


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

* [PATCH v5 11/18] match-trees: use "tmp" for mode in shift_tree_by()
  2021-03-31 19:09                     ` [PATCH v5 00/18] tree-walk.h: slimmed down Ævar Arnfjörð Bjarmason
                                         ` (9 preceding siblings ...)
  2021-03-31 19:09                       ` [PATCH v5 10/18] tree-walk.h users: use temporary variable(s) for "mode" Ævar Arnfjörð Bjarmason
@ 2021-03-31 19:09                       ` Ævar Arnfjörð Bjarmason
  2021-03-31 23:35                         ` Junio C Hamano
  2021-03-31 19:09                       ` [PATCH v5 12/18] tree.h: format argument lists of read_tree() users Ævar Arnfjörð Bjarmason
                                         ` (6 subsequent siblings)
  17 siblings, 1 reply; 262+ messages in thread
From: Ævar Arnfjörð Bjarmason @ 2021-03-31 19:09 UTC (permalink / raw)
  To: git; +Cc: Junio C Hamano, Elijah Newren, Æ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 a6796de442d..bdd16adb70a 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(r, hash1, shift_prefix, &sub1, &mode1) &&
-	    S_ISDIR(mode1))
+	if (!get_tree_entry(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(r, hash2, shift_prefix, &sub2, &mode2) &&
-	    S_ISDIR(mode2))
+	if (!get_tree_entry(r, hash2, shift_prefix, &sub2, &tmp) &&
+	    S_ISDIR(tmp))
 		candidate |= 2;
 
 	if (candidate == 3) {
-- 
2.31.1.474.g72d45d12706


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

* [PATCH v5 12/18] tree.h: format argument lists of read_tree() users
  2021-03-31 19:09                     ` [PATCH v5 00/18] tree-walk.h: slimmed down Ævar Arnfjörð Bjarmason
                                         ` (10 preceding siblings ...)
  2021-03-31 19:09                       ` [PATCH v5 11/18] match-trees: use "tmp" for mode in shift_tree_by() Ævar Arnfjörð Bjarmason
@ 2021-03-31 19:09                       ` Ævar Arnfjörð Bjarmason
  2021-03-31 19:09                       ` [PATCH v5 13/18] tree-walk.h API: formatting changes for subsequent commit Ævar Arnfjörð Bjarmason
                                         ` (5 subsequent siblings)
  17 siblings, 0 replies; 262+ messages in thread
From: Ævar Arnfjörð Bjarmason @ 2021-03-31 19:09 UTC (permalink / raw)
  To: git; +Cc: Junio C Hamano, Elijah Newren, Ævar Arnfjörð Bjarmason

Re-indent and format the argument list of read_tree() callbacks, and
the relevant functions they call.

This is a whitespace-only change to make changes in a later series
easier to read. In that series I'll be adding a new argument on the
"mode" line, so leave space on it for a new argument.

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 295615580d7..6af35a66b56 100644
--- a/archive.c
+++ b/archive.c
@@ -134,8 +134,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,
-		void *context)
+			       int baselen, const char *filename,
+			       unsigned mode,
+			       void *context)
 {
 	static struct strbuf path = STRBUF_INIT;
 	struct archiver_context *c = context;
@@ -225,8 +226,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;
 
@@ -372,7 +374,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 97520a88646..57198b29fe7 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 6efff003e21..10c8637ab3e 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, struct strbuf *base,
-- 
2.31.1.474.g72d45d12706


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

* [PATCH v5 13/18] tree-walk.h API: formatting changes for subsequent commit
  2021-03-31 19:09                     ` [PATCH v5 00/18] tree-walk.h: slimmed down Ævar Arnfjörð Bjarmason
                                         ` (11 preceding siblings ...)
  2021-03-31 19:09                       ` [PATCH v5 12/18] tree.h: format argument lists of read_tree() users Ævar Arnfjörð Bjarmason
@ 2021-03-31 19:09                       ` Ævar Arnfjörð Bjarmason
  2021-03-31 19:09                       ` [PATCH v5 14/18] tree-walk.h API doc: improve documentation of get_tree_entry() Ævar Arnfjörð Bjarmason
                                         ` (4 subsequent siblings)
  17 siblings, 0 replies; 262+ messages in thread
From: Ævar Arnfjörð Bjarmason @ 2021-03-31 19:09 UTC (permalink / raw)
  To: git; +Cc: Junio C Hamano, Elijah Newren, Æ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>
---
 tree-walk.c |  9 ++++++---
 tree-walk.h | 12 ++++++++----
 2 files changed, 14 insertions(+), 7 deletions(-)

diff --git a/tree-walk.c b/tree-walk.c
index 2d6226d5f18..fc2ce547c4e 100644
--- a/tree-walk.c
+++ b/tree-walk.c
@@ -589,7 +589,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;
 }
@@ -620,7 +621,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;
@@ -746,7 +748,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 a5058469e9b..09e40d9221d 100644
--- a/tree-walk.h
+++ b/tree-walk.h
@@ -167,10 +167,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.1.474.g72d45d12706


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

* [PATCH v5 14/18] tree-walk.h API doc: improve documentation of get_tree_entry()
  2021-03-31 19:09                     ` [PATCH v5 00/18] tree-walk.h: slimmed down Ævar Arnfjörð Bjarmason
                                         ` (12 preceding siblings ...)
  2021-03-31 19:09                       ` [PATCH v5 13/18] tree-walk.h API: formatting changes for subsequent commit Ævar Arnfjörð Bjarmason
@ 2021-03-31 19:09                       ` Ævar Arnfjörð Bjarmason
  2021-04-01 20:30                         ` Junio C Hamano
  2021-03-31 19:09                       ` [PATCH v5 15/18] tree-walk.h API: rename get_tree_entry() to get_tree_entry_mode() Ævar Arnfjörð Bjarmason
                                         ` (3 subsequent siblings)
  17 siblings, 1 reply; 262+ messages in thread
From: Ævar Arnfjörð Bjarmason @ 2021-03-31 19:09 UTC (permalink / raw)
  To: git; +Cc: Junio C Hamano, Elijah Newren, Ævar Arnfjörð Bjarmason

Change a mention of sha1 to OID and change the comment to a listing of
functions discussed below, right now there's only one function, but
subsequent commits will add more.

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

diff --git a/tree-walk.h b/tree-walk.h
index 09e40d9221d..cd8da84f56c 100644
--- a/tree-walk.h
+++ b/tree-walk.h
@@ -166,11 +166,13 @@ struct traverse_info {
 };
 
 /**
- * Find an entry in a tree given a pathname and the sha1 of a tree to
+ * Find an entry in a tree given a pathname and the OID 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.
+ * You always need a pointer to an appropriate variable to fill in
+ * (NULL won't do!). That variable is:
+ *
+ * get_tree_entry(): unsigned short mode
  */
 int get_tree_entry(struct repository *, const struct object_id *, const char *,
 		   struct object_id *,
-- 
2.31.1.474.g72d45d12706


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

* [PATCH v5 15/18] tree-walk.h API: rename get_tree_entry() to get_tree_entry_mode()
  2021-03-31 19:09                     ` [PATCH v5 00/18] tree-walk.h: slimmed down Ævar Arnfjörð Bjarmason
                                         ` (13 preceding siblings ...)
  2021-03-31 19:09                       ` [PATCH v5 14/18] tree-walk.h API doc: improve documentation of get_tree_entry() Ævar Arnfjörð Bjarmason
@ 2021-03-31 19:09                       ` Ævar Arnfjörð Bjarmason
  2021-03-31 19:09                       ` [PATCH v5 16/18] tree-walk.h API: add a get_tree_entry_path() function Ævar Arnfjörð Bjarmason
                                         ` (2 subsequent siblings)
  17 siblings, 0 replies; 262+ messages in thread
From: Ævar Arnfjörð Bjarmason @ 2021-03-31 19:09 UTC (permalink / raw)
  To: git; +Cc: Junio C Hamano, Elijah Newren, Æ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.

Subsequent commits will add another get_tree_entry_*() function. 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                |  5 ++---
 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            |  8 ++++----
 11 files changed, 36 insertions(+), 37 deletions(-)

diff --git a/archive.c b/archive.c
index 6af35a66b56..fa07fb442b4 100644
--- a/archive.c
+++ b/archive.c
@@ -475,10 +475,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 d1fa3821a08..462809095be 100644
--- a/blame.c
+++ b/blame.c
@@ -102,8 +102,7 @@ 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;
-
-		if (!get_tree_entry(r, commit_oid, path, &blob_oid, &mode))
+		if (!get_tree_entry_mode(r, commit_oid, path, &blob_oid, &mode))
 			return;
 	}
 
@@ -1237,7 +1236,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 51d93310a4d..d8ba9229212 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 bdd16adb70a..d4457eba997 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, &tmp) &&
+	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(r, hash2, shift_prefix, &sub2, &tmp) &&
+	if (!get_tree_entry_mode(r, hash2, shift_prefix, &sub2, &tmp) &&
 	    S_ISDIR(tmp))
 		candidate |= 2;
 
diff --git a/merge-recursive.c b/merge-recursive.c
index 57198b29fe7..c2e9f5d22d0 100644
--- a/merge-recursive.c
+++ b/merge-recursive.c
@@ -485,7 +485,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;
@@ -1884,9 +1884,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);
 }
 
 /*
@@ -2538,11 +2538,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 00aa7d4115a..e6244624055 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 fc2ce547c4e..30e3bb64e49 100644
--- a/tree-walk.c
+++ b/tree-walk.c
@@ -589,17 +589,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 cd8da84f56c..a01f2f226ec 100644
--- a/tree-walk.h
+++ b/tree-walk.h
@@ -172,11 +172,11 @@ struct traverse_info {
  * You always need a pointer to an appropriate variable to fill in
  * (NULL won't do!). That variable is:
  *
- * get_tree_entry(): unsigned short mode
+ * get_tree_entry_mode(): unsigned short mode
  */
-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.1.474.g72d45d12706


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

* [PATCH v5 16/18] tree-walk.h API: add a get_tree_entry_path() function
  2021-03-31 19:09                     ` [PATCH v5 00/18] tree-walk.h: slimmed down Ævar Arnfjörð Bjarmason
                                         ` (14 preceding siblings ...)
  2021-03-31 19:09                       ` [PATCH v5 15/18] tree-walk.h API: rename get_tree_entry() to get_tree_entry_mode() Ævar Arnfjörð Bjarmason
@ 2021-03-31 19:09                       ` Ævar Arnfjörð Bjarmason
  2021-04-01 20:41                         ` Junio C Hamano
  2021-03-31 19:09                       ` [PATCH v5 17/18] tree-walk.h API: document and format tree_entry_extract() Ævar Arnfjörð Bjarmason
  2021-03-31 19:09                       ` [PATCH v5 18/18] tree-entry.h API: rename tree_entry_extract() to tree_entry_extract_mode() Ævar Arnfjörð Bjarmason
  17 siblings, 1 reply; 262+ messages in thread
From: Ævar Arnfjörð Bjarmason @ 2021-03-31 19:09 UTC (permalink / raw)
  To: git; +Cc: Junio C Hamano, Elijah Newren, Ævar Arnfjörð Bjarmason

Add a get_tree_entry_path() variant in addition to
get_tree_entry_path_mode(). This is for those callers that don't need
the "mode" filled for them.

There are callers here which don't need the "struct object_id" filled
either, but let's leave that for now. I'm focusing downstream code
that depends on "mode" (or "enum object_type").

The code being modified here was introduced in:

 - shift_tree(): 68faf68938e (A new merge stragety[sic] '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)

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       | 9 +++++++++
 tree-walk.h       | 3 +++
 6 files changed, 17 insertions(+), 11 deletions(-)

diff --git a/match-trees.c b/match-trees.c
index d4457eba997..240922f7080 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 c2e9f5d22d0..28ed69ddfaa 100644
--- a/merge-recursive.c
+++ b/merge-recursive.c
@@ -1882,11 +1882,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 e6244624055..6766b1b478f 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 30e3bb64e49..d0dc0c35318 100644
--- a/tree-walk.c
+++ b/tree-walk.c
@@ -628,6 +628,15 @@ int get_tree_entry_mode(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;
+	return get_tree_entry_mode(r, tree_oid, name, oid, &mode);
+}
+
 /*
  * 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
diff --git a/tree-walk.h b/tree-walk.h
index a01f2f226ec..c60667cba8f 100644
--- a/tree-walk.h
+++ b/tree-walk.h
@@ -172,8 +172,11 @@ struct traverse_info {
  * You always need a pointer to an appropriate variable to fill in
  * (NULL won't do!). That variable is:
  *
+ * get_tree_entry_path(): <no extra argument, just get the common 'path'>
  * get_tree_entry_mode(): unsigned short mode
  */
+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.1.474.g72d45d12706


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

* [PATCH v5 17/18] tree-walk.h API: document and format tree_entry_extract()
  2021-03-31 19:09                     ` [PATCH v5 00/18] tree-walk.h: slimmed down Ævar Arnfjörð Bjarmason
                                         ` (15 preceding siblings ...)
  2021-03-31 19:09                       ` [PATCH v5 16/18] tree-walk.h API: add a get_tree_entry_path() function Ævar Arnfjörð Bjarmason
@ 2021-03-31 19:09                       ` Ævar Arnfjörð Bjarmason
  2021-04-01 20:46                         ` Junio C Hamano
  2021-03-31 19:09                       ` [PATCH v5 18/18] tree-entry.h API: rename tree_entry_extract() to tree_entry_extract_mode() Ævar Arnfjörð Bjarmason
  17 siblings, 1 reply; 262+ messages in thread
From: Ævar Arnfjörð Bjarmason @ 2021-03-31 19:09 UTC (permalink / raw)
  To: git; +Cc: Junio C Hamano, Elijah Newren, Ævar Arnfjörð Bjarmason

Document and format the argument list of the tree_entry_extract()
function in preparation for eventually 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 c60667cba8f..52eb0d6b5b3 100644
--- a/tree-walk.h
+++ b/tree-walk.h
@@ -38,11 +38,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(): 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.1.474.g72d45d12706


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

* [PATCH v5 18/18] tree-entry.h API: rename tree_entry_extract() to tree_entry_extract_mode()
  2021-03-31 19:09                     ` [PATCH v5 00/18] tree-walk.h: slimmed down Ævar Arnfjörð Bjarmason
                                         ` (16 preceding siblings ...)
  2021-03-31 19:09                       ` [PATCH v5 17/18] tree-walk.h API: document and format tree_entry_extract() Ævar Arnfjörð Bjarmason
@ 2021-03-31 19:09                       ` Ævar Arnfjörð Bjarmason
  2021-04-01 20:49                         ` Junio C Hamano
  17 siblings, 1 reply; 262+ messages in thread
From: Ævar Arnfjörð Bjarmason @ 2021-03-31 19:09 UTC (permalink / raw)
  To: git; +Cc: Junio C Hamano, Elijah Newren, Æ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   | 8 ++++----
 5 files changed, 10 insertions(+), 10 deletions(-)

diff --git a/fsck.c b/fsck.c
index e3030f3b358..b1d802cc30a 100644
--- a/fsck.c
+++ b/fsck.c
@@ -673,7 +673,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 240922f7080..23ff89be2b2 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 b7a76cc2620..31f8a9331b1 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 d0dc0c35318..533cb6a26b4 100644
--- a/tree-walk.c
+++ b/tree-walk.c
@@ -567,7 +567,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 52eb0d6b5b3..ec1d6927205 100644
--- a/tree-walk.h
+++ b/tree-walk.h
@@ -44,11 +44,11 @@ struct tree_desc {
  * "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(): const char *path, unsigned int mode
+ * 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.1.474.g72d45d12706


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

* Re: [PATCH v5 01/18] cache.h: add a comment to object_type()
  2021-03-31 19:09                       ` [PATCH v5 01/18] cache.h: add a comment to object_type() Ævar Arnfjörð Bjarmason
@ 2021-03-31 22:33                         ` Junio C Hamano
  0 siblings, 0 replies; 262+ messages in thread
From: Junio C Hamano @ 2021-03-31 22:33 UTC (permalink / raw)
  To: Ævar Arnfjörð Bjarmason; +Cc: git, Elijah Newren

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

> 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.

You are misreading Linus's comment here.

The comment is not about "S_ISLNK()" specifically.  It is about
assuming that any "S_ISx()" macros that are designed to work on
stat.st_mode would work the same way for our "mode bits in tree"
(i.e. 'internal git state' in the commit message refers to this
fact).  Platforms do not have to have 100xxx to be regular files,
but we did rely on that bit assignment.

And then we invented S_ISGITLINK() that exists on nobody's
stat.st_mode and have been assuming that would not collide
with any real S_IFMT bit assignment.

All of that has been patched with NEEDS_MODE_TRANSLATION band-aid
quite some time ago, though, with d543d9c0 (compat: convert modes to
use portable file type values, 2014-12-03).

So, no, we do not quite rely on that anymore.

> 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.

Specifically, the comment is not about symbolic links, and nobody
who reads the comment correctly would imagine that limiting BLOB
to S_ISREG.  The comment merely was lamenting that

	"If ISDIR, then tree and otherwise blob" does not hold
	anymore since we added submodules; "If ISDIR, then tree, and
	if ISGITLINK, then commit and otherwise blob" would fix it,
	but relying on ISDIR, ISGITLINK, etc. was a mistake that we
	continue to rely on even with this fix.

> Signed-off-by: Ævar Arnfjörð Bjarmason <avarab@gmail.com>
> ---

Which means that a lot of the stuff in the proposed log message is
false.  I do however think that ...

>  cache.h | 7 ++++++-
>  1 file changed, 6 insertions(+), 1 deletion(-)
>
> diff --git a/cache.h b/cache.h
> index 57f2285bba9..41e99bd9c63 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.
> + */

... this comment is correct and it is a good change to clarify what
'mode' we are talking about here.

>  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) */

For futureproofing, it might not be a bad idea to do this:

	S_ISDIR(mode) ? OBJ_TREE :
	S_ISGITLINK(mode) ? OBJ_COMMIT :
	(S_ISREG(mode) || S_ISLNK(mode)) ? OBJ_BLOB :
	OBJ_ERROR;

to anticipate new tree mode bits so that the need for a fix similar
to 4d1012c3 (Fix rev-list when showing objects involving submodules,
2007-11-11) is immediately noticed, but for now, code and comment
clarification would be sufficient.

The proposed log message needs rewriting, though.

Thanks.



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

* Re: [PATCH v5 03/18] cache.h: have base_name_compare() take "is tree?", not "mode"
  2021-03-31 19:09                       ` [PATCH v5 03/18] cache.h: have base_name_compare() take "is tree?", not "mode" Ævar Arnfjörð Bjarmason
@ 2021-03-31 22:55                         ` Junio C Hamano
  0 siblings, 0 replies; 262+ messages in thread
From: Junio C Hamano @ 2021-03-31 22:55 UTC (permalink / raw)
  To: Ævar Arnfjörð Bjarmason; +Cc: git, Elijah Newren

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

> 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 introduces no functional change, but makes later (not part of
> this series) changes to abstract away "object_type" from "mode" more
> readable.
>
> The API being modified here was originally added way back in
> 958ba6c96eb (Introduce "base_name_compare()" helper function,
> 2005-05-20).
>
> None of these comparison functions used to have tests, but with
> preceding commits some of them now do. I thought the remainder was
> trivial enough to review without tests, and didn't want to spend more
> time on them.

Puzzled.  preceeding commits?

> diff --git a/cache.h b/cache.h
> index 41e99bd9c63..3bcea022ad2 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);

Hopefully there won't be any new callers to these comparison
functions introduced while this topic is in flight.

Without seeing real users (not yet at this 3rd step in the 18 patch
series, anyway), this step feels to be a needless code churn whose
only effect is to increase risks of silent semantic conflicts that
compilers will not be able to help detecting.  It might make it
slightly less error prone to add

	if (istree1 != 0 && istree1 != 1)
		BUG("%o?  unconverted caller?", istree1);
	if (istree2 != 0 && istree2 != 1)
		BUG("%o?  unconverted caller?", istree2);

in the callee while the topic is still in flight.  Or do this in a
renamed function so that such a semantic conflict will be noticed by
the linker (although that would increase the busywork workload on
the integrator).

I know steps like this in a long series (not limited to this series)
means well, and we do encourage people to move necessary preliminary
clean-up to the early part of a series, but they make me wonder "can
we get to the point without 'clean-up while we are at it' steps that
may turn out to be more-or-less irrelevant?"

In other words, we do encourage people to do necessary preliminary
clean-up before the main part of a series, but it sometimes is
unclear if an early "clean-up" patch in a long series is "necessary"
or merely "while at it" that can be omitted.

But let me hold my judgment until I reach the end of the series to
know enough to say if this step is or is not "necessary" preliminary
clean-up.

> diff --git a/unpack-trees.c b/unpack-trees.c
> index 29029f34ed6..23c1640ae9a 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)

Here, the "istree" boolean is expressed as unsigned, but in cache.h,
it is expressed as int?  Why the discrepancy?

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

* Re: [PATCH v5 05/18] mktree tests: test that "mode" is passed when sorting
  2021-03-31 19:09                       ` [PATCH v5 05/18] mktree tests: test that "mode" is passed when sorting Ævar Arnfjörð Bjarmason
@ 2021-03-31 23:04                         ` Junio C Hamano
  0 siblings, 0 replies; 262+ messages in thread
From: Junio C Hamano @ 2021-03-31 23:04 UTC (permalink / raw)
  To: Ævar Arnfjörð Bjarmason; +Cc: git, Elijah Newren

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

> Add a test for the mode being passed to ent_compare(). That code dates
> back to 83f50539a9 (git-mktree: reverse of git-ls-tree., 2006-02-20)
> and there's never been a test for that particular edge case. Now we
> have one.
>
> I don't see how anything could run into this in practice. In order for
> that mode sorting to matter as a tiebreaker we need to have a
> duplicate entry in the tree, i.e. two "foo" entries, one a blob and
> one a tree. This asserts that if that happens we'll sort on the modes
> we encounter in such an invalid entry, i.e. we expect the tree entry
> before the blob.

It is more like "in a tree with 'foo.' and 'foo0' (both of which are
blobs), a 'foo' that is a tree should appear after 'foo.' and before
'foo0', because it sorts as if it were 'foo/'.  If 'foo' is a blob,
it sorts the first before 'foo.' and 'foo0'".  

Checking a broken tree with both 'foo' (blob) and 'foo' (tree) that
does not even pass fsck is not very valuable, but the sort order of
these two trees (i.e. one with foo as tree, the other with foo as
blob) do need to be tested, as the unpack_trees merge machinery will
need to walk such pair of trees correctly.

Thanks.

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

* Re: [PATCH v5 06/18] diff tests: test that "mode" is passed when sorting
  2021-03-31 19:09                       ` [PATCH v5 06/18] diff " Ævar Arnfjörð Bjarmason
@ 2021-03-31 23:07                         ` Junio C Hamano
  0 siblings, 0 replies; 262+ messages in thread
From: Junio C Hamano @ 2021-03-31 23:07 UTC (permalink / raw)
  To: Ævar Arnfjörð Bjarmason; +Cc: git, Elijah Newren

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

> Piggy-back on the recently added fsck tests for mode comparisons in
> mktree and assert that diff-tree also does the right thing in this
> implausible scenario.

The same comment applies.  Just testing the order of "foo" (blob),
"foo." (blob), "foo/" (tree), and "foo0" (blob) in two comparisons
would be a more realistic test that has more practical value.


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

* Re: [PATCH v5 07/18] merge-tree tests: test for the mode comparison in same_entry()
  2021-03-31 19:09                       ` [PATCH v5 07/18] merge-tree tests: test for the mode comparison in same_entry() Ævar Arnfjörð Bjarmason
@ 2021-03-31 23:12                         ` Junio C Hamano
  0 siblings, 0 replies; 262+ messages in thread
From: Junio C Hamano @ 2021-03-31 23:12 UTC (permalink / raw)
  To: Ævar Arnfjörð Bjarmason; +Cc: git, Elijah Newren

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

> 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().

Good thinking.


> 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

Can we HT-indent the here text with "<<-EOF", unless existing tests
in the same script predate the more recent convention?

    ... goes and looks and realizes it is full of unindented
    expectation ...

Nah, let's keep it that way.

> +	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

Nice.  So the mode-only conflict and mode plus contents conflict are
both shown in a sensible way.

Looks good.
Thanks.

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

* Re: [PATCH v5 08/18] blame: emit a better error on 'git blame directory'
  2021-03-31 19:09                       ` [PATCH v5 08/18] blame: emit a better error on 'git blame directory' Ævar Arnfjörð Bjarmason
@ 2021-03-31 23:26                         ` Junio C Hamano
  2021-04-02  9:26                           ` Ævar Arnfjörð Bjarmason
  0 siblings, 1 reply; 262+ messages in thread
From: Junio C Hamano @ 2021-03-31 23:26 UTC (permalink / raw)
  To: Ævar Arnfjörð Bjarmason; +Cc: git, Elijah Newren

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

> 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

Sorry, but I fail to see why "unsupported file type t" is quite an
improvement.  Is this one of these irrelevant clean-up while at it
whose benefit is unclear until much later, I have to wonder.

> The main point of this test is to assert that we're not doing
> something uniquely bad when in a conflicted merge. See

"this test" refers to the logic "it is OK to skip the check if one
of the parents does have it as a blob", introduced in 9aeaab68
(blame: allow "blame file" in the middle of a conflicted merge,
2012-09-11)?


> -		if (!get_tree_entry(r, commit_oid, path, &blob_oid, &mode) &&
> -		    oid_object_info(r, &blob_oid, NULL) == OBJ_BLOB)
> +		if (!get_tree_entry(r, commit_oid, path, &blob_oid, &mode))
>  			return;
>  	}

At least, the original logic makes sense to me in that if an early
parent has the path as a directory we do not declare it is OK but
keep going until we find a blob in a later parent before deciding to
short-cut.  I am not sure what the updated "in this case we can
bypass the real check" condition even means.  Mechanically, it says
"if any parent has the path as any filesystem entity, even if it
were a directory, then it is OK", but why?

Thanks.

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

* Re: [PATCH v5 09/18] notes & match-trees: use name_entry's "pathlen" member
  2021-03-31 19:09                       ` [PATCH v5 09/18] notes & match-trees: use name_entry's "pathlen" member Ævar Arnfjörð Bjarmason
@ 2021-03-31 23:32                         ` Junio C Hamano
  0 siblings, 0 replies; 262+ messages in thread
From: Junio C Hamano @ 2021-03-31 23:32 UTC (permalink / raw)
  To: Ævar Arnfjörð Bjarmason; +Cc: git, Elijah Newren

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

>  	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 &&

Makes sense.

> @@ -216,9 +217,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);

So does this.  The original using desc.entry.path even though it
called extract to learn the name does not make much sense.

>  			break;
>  		}
>  		update_tree_entry(&desc);
> diff --git a/notes.c b/notes.c
> index a19e4ad7943..e2fec12a39e 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;

OK.

>  		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);

OK.

>  			add_non_note(t, strbuf_detach(&non_note_path, NULL),
>  				     entry.mode, entry.oid.hash);
>  		}

Looking good.
Thanks.

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

* Re: [PATCH v5 11/18] match-trees: use "tmp" for mode in shift_tree_by()
  2021-03-31 19:09                       ` [PATCH v5 11/18] match-trees: use "tmp" for mode in shift_tree_by() Ævar Arnfjörð Bjarmason
@ 2021-03-31 23:35                         ` Junio C Hamano
  0 siblings, 0 replies; 262+ messages in thread
From: Junio C Hamano @ 2021-03-31 23:35 UTC (permalink / raw)
  To: Ævar Arnfjörð Bjarmason; +Cc: git, Elijah Newren

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

> 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.

OK.

>
> 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 a6796de442d..bdd16adb70a 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(r, hash1, shift_prefix, &sub1, &mode1) &&
> -	    S_ISDIR(mode1))
> +	if (!get_tree_entry(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(r, hash2, shift_prefix, &sub2, &mode2) &&
> -	    S_ISDIR(mode2))
> +	if (!get_tree_entry(r, hash2, shift_prefix, &sub2, &tmp) &&
> +	    S_ISDIR(tmp))
>  		candidate |= 2;
>  
>  	if (candidate == 3) {

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

* Re: [PATCH v5 14/18] tree-walk.h API doc: improve documentation of get_tree_entry()
  2021-03-31 19:09                       ` [PATCH v5 14/18] tree-walk.h API doc: improve documentation of get_tree_entry() Ævar Arnfjörð Bjarmason
@ 2021-04-01 20:30                         ` Junio C Hamano
  2021-04-02  9:27                           ` Ævar Arnfjörð Bjarmason
  0 siblings, 1 reply; 262+ messages in thread
From: Junio C Hamano @ 2021-04-01 20:30 UTC (permalink / raw)
  To: Ævar Arnfjörð Bjarmason; +Cc: git, Elijah Newren

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

> Change a mention of sha1 to OID and change the comment to a listing of
> functions discussed below, right now there's only one function, but
> subsequent commits will add more.
>
> Signed-off-by: Ævar Arnfjörð Bjarmason <avarab@gmail.com>
> ---
>  tree-walk.h | 8 +++++---
>  1 file changed, 5 insertions(+), 3 deletions(-)
>
> diff --git a/tree-walk.h b/tree-walk.h
> index 09e40d9221d..cd8da84f56c 100644
> --- a/tree-walk.h
> +++ b/tree-walk.h
> @@ -166,11 +166,13 @@ struct traverse_info {
>  };
>  
>  /**
> - * Find an entry in a tree given a pathname and the sha1 of a tree to
> + * Find an entry in a tree given a pathname and the OID 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.
> + * You always need a pointer to an appropriate variable to fill in
> + * (NULL won't do!). That variable is:
> + *
> + * get_tree_entry(): unsigned short mode

The last part after "That variable is:" makes no sense.  Sent before
completing?

The function takes a repository, tree object name, a path in that
tree as input, and find the entry in the tree at the given path.
Its finding is returned in the fourth and fifth parameters as

    struct object_id *oid
    unsigned short *mode

By the way, I think somebody forgot to update the description while
inserting the "struct repository *" as the first parameter and that
is where the "third and fourth" in the original comes from.


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

* Re: [PATCH v5 16/18] tree-walk.h API: add a get_tree_entry_path() function
  2021-03-31 19:09                       ` [PATCH v5 16/18] tree-walk.h API: add a get_tree_entry_path() function Ævar Arnfjörð Bjarmason
@ 2021-04-01 20:41                         ` Junio C Hamano
  2021-04-02  9:41                           ` Ævar Arnfjörð Bjarmason
  0 siblings, 1 reply; 262+ messages in thread
From: Junio C Hamano @ 2021-04-01 20:41 UTC (permalink / raw)
  To: Ævar Arnfjörð Bjarmason; +Cc: git, Elijah Newren

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

> -		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));

The observation that many "get_tree_entry()" users do not need the
mode bits and the code can be simplified by taking advantage of
that fact is good.

It does not automatically follow that it is a good implementation of
that simplification to introduce a variant that does not take the
mode pointer.  The original function could have just been taught to
accept NULL in the field the caller is not interested in, as in many
other functions do.

Besides, get_tree_entry_mode() vs get_tree_entry_path() does not
make any sense as pair of functions with contrasting names.  If it
were that unlike the former that returns mode, the latter returns
path instead, it would have made sense, but that is not what is
going on.  The former returns object name and mode, the latter only
returns object name without mode.

In any case, at this point in the series, it is highly dubious that
an extra function is an improvement.  Teaching get_tree_entry() (do
not even rename it) to take NULL in *mode pointer would make a lot
more sense.

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

* Re: [PATCH v5 17/18] tree-walk.h API: document and format tree_entry_extract()
  2021-03-31 19:09                       ` [PATCH v5 17/18] tree-walk.h API: document and format tree_entry_extract() Ævar Arnfjörð Bjarmason
@ 2021-04-01 20:46                         ` Junio C Hamano
  0 siblings, 0 replies; 262+ messages in thread
From: Junio C Hamano @ 2021-04-01 20:46 UTC (permalink / raw)
  To: Ævar Arnfjörð Bjarmason; +Cc: git, Elijah Newren

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

> Document and format the argument list of the tree_entry_extract()
> function in preparation for eventually 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 c60667cba8f..52eb0d6b5b3 100644
> --- a/tree-walk.h
> +++ b/tree-walk.h
> @@ -38,11 +38,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!):

There aren't.  At least not yet.  So if you want to build a series
like this that does many little things in each step, stop this step
at updating SHA-1 to OID and do nothing else, until you introduce
different variant.

What is missing in the current description that is more worth
describing for those who are new to the codebase is probably the
fact that this is meant to be used in pairs with update_tree_entry().
You call extract, which does not change the entry at all, and when
you are done, update knows (from the data kept in the entry) where
the next entry is in memory and the entry is updated to point there.

Thanks.

> + *
> + * tree_entry_extract(): 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;

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

* Re: [PATCH v5 18/18] tree-entry.h API: rename tree_entry_extract() to tree_entry_extract_mode()
  2021-03-31 19:09                       ` [PATCH v5 18/18] tree-entry.h API: rename tree_entry_extract() to tree_entry_extract_mode() Ævar Arnfjörð Bjarmason
@ 2021-04-01 20:49                         ` Junio C Hamano
  0 siblings, 0 replies; 262+ messages in thread
From: Junio C Hamano @ 2021-04-01 20:49 UTC (permalink / raw)
  To: Ævar Arnfjörð Bjarmason; +Cc: git, Elijah Newren

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

> 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.

I do not see a value in this approach over optionally accepting
NULL, for the same reason why splitting get_tree_entry() does not
show a value over optionally accepting NULL.  At least at this point
in the series.

There might be future changes that would benefit from having
separate functions, but I do not see how they cannot work with an
updated version of existing helper functions that optionally can
take NULL as "don't care" when they can with a different function
with one fewer parameter.

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

* Re: [PATCH v5 08/18] blame: emit a better error on 'git blame directory'
  2021-03-31 23:26                         ` Junio C Hamano
@ 2021-04-02  9:26                           ` Ævar Arnfjörð Bjarmason
  2021-04-02 21:08                             ` Junio C Hamano
  0 siblings, 1 reply; 262+ messages in thread
From: Ævar Arnfjörð Bjarmason @ 2021-04-02  9:26 UTC (permalink / raw)
  To: Junio C Hamano; +Cc: git, Elijah Newren


On Thu, Apr 01 2021, Junio C Hamano wrote:

> Ævar Arnfjörð Bjarmason  <avarab@gmail.com> writes:
>
>> 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
>
> Sorry, but I fail to see why "unsupported file type t" is quite an
> improvement.  Is this one of these irrelevant clean-up while at it
> whose benefit is unclear until much later, I have to wonder.

Because "t" is directory we can stat() and which exists in the index, so
it makes more sense to fall through to the stat() codepath.

I think the "unsupported file type" message is a bit odd, but it's the
existing one, perhaps changing it while we're at it to something like:

    fatal: cannot 'blame' a directory

Would be better, but in any case I think saying "no such path X in HEAD"
when you can "git show HEAD:t" to see that there is such a path doesn't
make sense.

I don't have a test for it here, but this change also makes this error
better:

    rm -rf contrib
    git blame contrib

Before we'd say:

    fatal: no such path 'contrib' in HEAD

But now we'll fall back to:

    fatal: Cannot lstat 'contrib': No such file or directory

Which could also be reworded, but aside from the specific wording I
think not aborting early when we see "this is not a blob" is better.

>> The main point of this test is to assert that we're not doing
>> something uniquely bad when in a conflicted merge. See
>
> "this test" refers to the logic "it is OK to skip the check if one
> of the parents does have it as a blob", introduced in 9aeaab68
> (blame: allow "blame file" in the middle of a conflicted merge,
> 2012-09-11)?

Yes, will clarify.

>> -		if (!get_tree_entry(r, commit_oid, path, &blob_oid, &mode) &&
>> -		    oid_object_info(r, &blob_oid, NULL) == OBJ_BLOB)
>> +		if (!get_tree_entry(r, commit_oid, path, &blob_oid, &mode))
>>  			return;
>>  	}
>
> At least, the original logic makes sense to me in that if an early
> parent has the path as a directory we do not declare it is OK but
> keep going until we find a blob in a later parent before deciding to
> short-cut.  I am not sure what the updated "in this case we can
> bypass the real check" condition even means.  Mechanically, it says
> "if any parent has the path as any filesystem entity, even if it
> were a directory, then it is OK", but why?

Because we'll fall down to code that's better at doing the rest of that
check.

Looking at this again, another thing this changes is the behavior of
--contents, which I again think is an improvement. Let's say you:

    rm Makefile &&
    mkdir Makefile &&
    touch Makefile/foo &&
    git add Makefile &&
    git commit -m"foo"

I.e. turn a random file into a directory, then:

    git show origin/master:Makefile | git blame --contents - Makefile

We'll now say:

    fatal: no such path 'Makefile' in HEAD

With my patch we'll do what the user asked (and I think consistently
with the documentation) and pretend as though the stream on stdin was
the contents at the "Makefile" path.

The blame we show doesn't make much sense, it's all the lines in the
file with "Not Committed Yet", but that's another matter to do with the
blame algorithm in general, e.g. if you flip Makefile back & forth
between a file->dir->file it won't traverse past the dir->file move.

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

* Re: [PATCH v5 14/18] tree-walk.h API doc: improve documentation of get_tree_entry()
  2021-04-01 20:30                         ` Junio C Hamano
@ 2021-04-02  9:27                           ` Ævar Arnfjörð Bjarmason
  0 siblings, 0 replies; 262+ messages in thread
From: Ævar Arnfjörð Bjarmason @ 2021-04-02  9:27 UTC (permalink / raw)
  To: Junio C Hamano; +Cc: git, Elijah Newren


On Thu, Apr 01 2021, Junio C Hamano wrote:

> Ævar Arnfjörð Bjarmason  <avarab@gmail.com> writes:
>
>> Change a mention of sha1 to OID and change the comment to a listing of
>> functions discussed below, right now there's only one function, but
>> subsequent commits will add more.
>>
>> Signed-off-by: Ævar Arnfjörð Bjarmason <avarab@gmail.com>
>> ---
>>  tree-walk.h | 8 +++++---
>>  1 file changed, 5 insertions(+), 3 deletions(-)
>>
>> diff --git a/tree-walk.h b/tree-walk.h
>> index 09e40d9221d..cd8da84f56c 100644
>> --- a/tree-walk.h
>> +++ b/tree-walk.h
>> @@ -166,11 +166,13 @@ struct traverse_info {
>>  };
>>  
>>  /**
>> - * Find an entry in a tree given a pathname and the sha1 of a tree to
>> + * Find an entry in a tree given a pathname and the OID 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.
>> + * You always need a pointer to an appropriate variable to fill in
>> + * (NULL won't do!). That variable is:
>> + *
>> + * get_tree_entry(): unsigned short mode
>
> The last part after "That variable is:" makes no sense.  Sent before
> completing?

It's meant to refer to the "unsigned short mode", but I'll rephrase.

> The function takes a repository, tree object name, a path in that
> tree as input, and find the entry in the tree at the given path.
> Its finding is returned in the fourth and fifth parameters as
>
>     struct object_id *oid
>     unsigned short *mode
>
> By the way, I think somebody forgot to update the description while
> inserting the "struct repository *" as the first parameter and that
> is where the "third and fourth" in the original comes from.

Also as a fix for this...

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

* Re: [PATCH v5 16/18] tree-walk.h API: add a get_tree_entry_path() function
  2021-04-01 20:41                         ` Junio C Hamano
@ 2021-04-02  9:41                           ` Ævar Arnfjörð Bjarmason
  0 siblings, 0 replies; 262+ messages in thread
From: Ævar Arnfjörð Bjarmason @ 2021-04-02  9:41 UTC (permalink / raw)
  To: Junio C Hamano; +Cc: git, Elijah Newren


On Thu, Apr 01 2021, Junio C Hamano wrote:

> Ævar Arnfjörð Bjarmason  <avarab@gmail.com> writes:
>
>> -		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));
>
> The observation that many "get_tree_entry()" users do not need the
> mode bits and the code can be simplified by taking advantage of
> that fact is good.
>
> It does not automatically follow that it is a good implementation of
> that simplification to introduce a variant that does not take the
> mode pointer.  The original function could have just been taught to
> accept NULL in the field the caller is not interested in, as in many
> other functions do.
>
> Besides, get_tree_entry_mode() vs get_tree_entry_path() does not
> make any sense as pair of functions with contrasting names.  If it
> were that unlike the former that returns mode, the latter returns
> path instead, it would have made sense, but that is not what is
> going on.  The former returns object name and mode, the latter only
> returns object name without mode.
>
> In any case, at this point in the series, it is highly dubious that
> an extra function is an improvement.  Teaching get_tree_entry() (do
> not even rename it) to take NULL in *mode pointer would make a lot
> more sense.

Thanks. Yes that makes a lot more sense.

This whole path of introducing multiple functions is an oversight of
mine. I did it because in 7146e66f086 (tree-walk: finally switch over
tree descriptors to contain a pre-parsed entry, 2014-02-06) we removed
canon_mode() from the inline function to make it trivially inline-able.

So I assumed without testing that introducing conditionals in that
function would matter to a compiler, and wanted to not introduce any
performance regressions (however small) in this series.

But looking at the generated *.s code under GCC -O3 it makes no
difference if you've got an "if (ptr) *ptr = xyz" there. The compiler
sees that and produces the same machine code.

So I'll re-roll this to do as you suggested, thanks.

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

* Re: [PATCH v5 08/18] blame: emit a better error on 'git blame directory'
  2021-04-02  9:26                           ` Ævar Arnfjörð Bjarmason
@ 2021-04-02 21:08                             ` Junio C Hamano
  0 siblings, 0 replies; 262+ messages in thread
From: Junio C Hamano @ 2021-04-02 21:08 UTC (permalink / raw)
  To: Ævar Arnfjörð Bjarmason; +Cc: git, Elijah Newren

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

> On Thu, Apr 01 2021, Junio C Hamano wrote:
>
>> Ævar Arnfjörð Bjarmason  <avarab@gmail.com> writes:
>>
>>> 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
>>
>> Sorry, but I fail to see why "unsupported file type t" is quite an
>> improvement.  Is this one of these irrelevant clean-up while at it
>> whose benefit is unclear until much later, I have to wonder.
>
> Because "t" is directory we can stat() and which exists in the index, so
> it makes more sense to fall through to the stat() codepath.

't' is not in the index, even though many things with 't/' prefix
may.

But my understanding of the point of that loop is to catch cases
where one side may have 't' as a directory, the other side may have
it as a blob, and we have a 't' regular file during a process of
resolving a conflicted merge (perhaps the tentative resolution has
already been "git add"ed to the index).  So "git blame t" would want
to start from the "working tree state", which is made into a virtual
commit, with two "virtual" parents, one is HEAD that has 't' as a
directory but the other MERGE_HEAD may have 't' as a regular file,
so "blame" should be able to follow the history of that regular file
through the merge in progress.

If we change, like the proposed patch does, the loop to exit
immediately after we notice 't' exists in HEAD (as a tree), without
even looking at the second parent to notice that it is a regular
file there, wouldn't that change the behaviour?

> I think the "unsupported file type" message is a bit odd, but it's the
> existing one, perhaps changing it while we're at it to something like:
>
>     fatal: cannot 'blame' a directory
>
> Would be better,...

Sure.  As long as the change does not break the original use case
the loop intended to support, that is fine, and the message would be
a lot better than the "unsupported file type t".

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

end of thread, other threads:[~2021-04-02 21:08 UTC | newest]

Thread overview: 262+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
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 22:06   ` Elijah Newren
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-09  0:10       ` Elijah Newren
2021-03-09 20:41       ` Elijah Newren
2021-03-09 21:48         ` Ævar Arnfjörð Bjarmason
2021-03-12  6:44           ` Elijah Newren
2021-03-16  2:12       ` [PATCH v2 00/29] tree-walk: mostly replace "mode" with " Ævar Arnfjörð Bjarmason
2021-03-16  7:04         ` Elijah Newren
2021-03-16  8:30           ` Ævar Arnfjörð Bjarmason
2021-03-16 15:57         ` [PATCH v3 00/32] " Ævar Arnfjörð Bjarmason
2021-03-16 17:28           ` Elijah Newren
2021-03-21  0:00           ` [PATCH v4 00/29] " Ævar Arnfjörð Bjarmason
2021-03-21  0:00             ` [PATCH v4 01/29] notes & match-trees: use name_entry's "pathlen" member Ævar Arnfjörð Bjarmason
2021-03-21  0:00             ` [PATCH v4 02/29] cache.h: add a comment to object_type() Ævar Arnfjörð Bjarmason
2021-03-21  0:00             ` [PATCH v4 03/29] tree-walk.h: add object_type member to name_entry Ævar Arnfjörð Bjarmason
2021-03-21  0:00             ` [PATCH v4 04/29] tree-walk.c: migrate to using new "object_type" field when possible Ævar Arnfjörð Bjarmason
2021-03-21  0:00             ` [PATCH v4 05/29] fast-import tests: test for sorting dir/file foo v.s. foo.txt Ævar Arnfjörð Bjarmason
2021-03-21  0:00             ` [PATCH v4 06/29] mktree tests: test that "mode" is passed when sorting Ævar Arnfjörð Bjarmason
2021-03-21  0:00             ` [PATCH v4 07/29] diff " Ævar Arnfjörð Bjarmason
2021-03-21  0:00             ` [PATCH v4 08/29] cache.h: have base_name_compare() take "is tree?", not "mode" Ævar Arnfjörð Bjarmason
2021-03-21  0:00             ` [PATCH v4 09/29] tree-walk.h users: switch object_type(...) to new .object_type Ævar Arnfjörð Bjarmason
2021-03-21  0:00             ` [PATCH v4 10/29] tree.h: format argument lists of read_tree_recursive() users Ævar Arnfjörð Bjarmason
2021-03-21  0:00             ` [PATCH v4 11/29] tree.h API: make read_tree_fn_t take an "enum object_type" Ævar Arnfjörð Bjarmason
2021-03-21  0:00             ` [PATCH v4 12/29] tree-walk.h users: migrate "p->mode &&" pattern Ævar Arnfjörð Bjarmason
2021-03-21  0:00             ` [PATCH v4 13/29] tree-walk.h users: refactor chained "mode" if/else into switch Ævar Arnfjörð Bjarmason
2021-03-21  0:00             ` [PATCH v4 14/29] tree-walk.h users: migrate miscellaneous "mode" to "object_type" Ævar Arnfjörð Bjarmason
2021-03-21  0:00             ` [PATCH v4 15/29] merge-tree tests: test for the mode comparison in same_entry() Ævar Arnfjörð Bjarmason
2021-03-21  0:00             ` [PATCH v4 16/29] merge-ort: correct reference to test in 62fdec17a11 Ævar Arnfjörð Bjarmason
2021-03-21  0:00             ` [PATCH v4 17/29] fsck.c: switch on "object_type" in fsck_walk_tree() Ævar Arnfjörð Bjarmason
2021-03-21  0:00             ` [PATCH v4 18/29] tree-walk.h users: use temporary variable(s) for "mode" Ævar Arnfjörð Bjarmason
2021-03-21  0:00             ` [PATCH v4 19/29] tree-walk.h API: formatting changes for subsequent commit Ævar Arnfjörð Bjarmason
2021-03-21  0:00             ` [PATCH v4 20/29] tree-walk.h API: rename get_tree_entry() to get_tree_entry_mode() Ævar Arnfjörð Bjarmason
2021-03-21  0:00             ` [PATCH v4 21/29] match-trees: use "tmp" for mode in shift_tree_by() Ævar Arnfjörð Bjarmason
2021-03-21  0:00             ` [PATCH v4 22/29] tree-walk.h API: add get_tree_entry_type() Ævar Arnfjörð Bjarmason
2021-03-21  0:00             ` [PATCH v4 23/29] tree-walk.h API: document and format tree_entry_extract() Ævar Arnfjörð Bjarmason
2021-03-21  0:00             ` [PATCH v4 24/29] tree-entry.h API: rename tree_entry_extract() to tree_entry_extract_mode() Ævar Arnfjörð Bjarmason
2021-03-21  0:00             ` [PATCH v4 25/29] tree-walk.h API: add a tree_entry_extract_all() function Ævar Arnfjörð Bjarmason
2021-03-21  0:00             ` [PATCH v4 26/29] tree-walk.h API: add get_tree_entry_all() Ævar Arnfjörð Bjarmason
2021-03-21  0:01             ` [PATCH v4 27/29] tree-walk.h API: add a get_tree_entry_path() function Ævar Arnfjörð Bjarmason
2021-03-21  0:01             ` [PATCH v4 28/29] blame: emit a better error on 'git blame directory' Ævar Arnfjörð Bjarmason
2021-03-21  0:01             ` [PATCH v4 29/29] tree-walk.h API: add a tree_entry_extract_type() function Ævar Arnfjörð Bjarmason
2021-03-21  1:16             ` [PATCH v4 00/29] tree-walk: mostly replace "mode" with "enum object_type" Junio C Hamano
2021-03-21 12:26               ` Ævar Arnfjörð Bjarmason
2021-03-21 12:39                 ` [PATCH 0/2] diff --no-index: fix test blind spots Ævar Arnfjörð Bjarmason
2021-03-21 12:39                   ` [PATCH 1/2] diff --no-index tests: add test for --exit-code Ævar Arnfjörð Bjarmason
2021-03-21 18:33                     ` Ramsay Jones
2021-03-21 21:33                       ` Junio C Hamano
2021-03-21 22:44                         ` Ævar Arnfjörð Bjarmason
2021-03-21 12:39                   ` [PATCH 2/2] diff --no-index tests: test mode normalization Ævar Arnfjörð Bjarmason
2021-03-21 22:36                   ` [PATCH v2 0/2] diff --no-index: fix test blind spots Ævar Arnfjörð Bjarmason
2021-03-21 22:36                     ` [PATCH v2 1/2] diff --no-index tests: add test for --exit-code Ævar Arnfjörð Bjarmason
2021-03-21 22:36                     ` [PATCH v2 2/2] diff --no-index tests: test mode normalization Ævar Arnfjörð Bjarmason
2021-03-22 19:22                       ` Junio C Hamano
2021-03-22  4:27                     ` [PATCH v2 0/2] diff --no-index: fix test blind spots Junio C Hamano
2021-03-23 16:40                     ` [PATCH v3 " Ævar Arnfjörð Bjarmason
2021-03-23 16:40                       ` [PATCH v3 1/2] diff --no-index tests: add test for --exit-code Ævar Arnfjörð Bjarmason
2021-03-23 16:40                       ` [PATCH v3 2/2] diff --no-index tests: test mode normalization Ævar Arnfjörð Bjarmason
2021-03-23 16:47                       ` [PATCH v3 0/2] diff --no-index: fix test blind spots Junio C Hamano
2021-03-21 17:13                 ` [PATCH v4 00/29] tree-walk: mostly replace "mode" with "enum object_type" Junio C Hamano
2021-03-21 18:42                   ` Ævar Arnfjörð Bjarmason
2021-03-31 19:09                     ` [PATCH v5 00/18] tree-walk.h: slimmed down Ævar Arnfjörð Bjarmason
2021-03-31 19:09                       ` [PATCH v5 01/18] cache.h: add a comment to object_type() Ævar Arnfjörð Bjarmason
2021-03-31 22:33                         ` Junio C Hamano
2021-03-31 19:09                       ` [PATCH v5 02/18] merge-ort: correct reference to test in 62fdec17a11 Ævar Arnfjörð Bjarmason
2021-03-31 19:09                       ` [PATCH v5 03/18] cache.h: have base_name_compare() take "is tree?", not "mode" Ævar Arnfjörð Bjarmason
2021-03-31 22:55                         ` Junio C Hamano
2021-03-31 19:09                       ` [PATCH v5 04/18] fast-import tests: test for sorting dir/file foo v.s. foo.txt Ævar Arnfjörð Bjarmason
2021-03-31 19:09                       ` [PATCH v5 05/18] mktree tests: test that "mode" is passed when sorting Ævar Arnfjörð Bjarmason
2021-03-31 23:04                         ` Junio C Hamano
2021-03-31 19:09                       ` [PATCH v5 06/18] diff " Ævar Arnfjörð Bjarmason
2021-03-31 23:07                         ` Junio C Hamano
2021-03-31 19:09                       ` [PATCH v5 07/18] merge-tree tests: test for the mode comparison in same_entry() Ævar Arnfjörð Bjarmason
2021-03-31 23:12                         ` Junio C Hamano
2021-03-31 19:09                       ` [PATCH v5 08/18] blame: emit a better error on 'git blame directory' Ævar Arnfjörð Bjarmason
2021-03-31 23:26                         ` Junio C Hamano
2021-04-02  9:26                           ` Ævar Arnfjörð Bjarmason
2021-04-02 21:08                             ` Junio C Hamano
2021-03-31 19:09                       ` [PATCH v5 09/18] notes & match-trees: use name_entry's "pathlen" member Ævar Arnfjörð Bjarmason
2021-03-31 23:32                         ` Junio C Hamano
2021-03-31 19:09                       ` [PATCH v5 10/18] tree-walk.h users: use temporary variable(s) for "mode" Ævar Arnfjörð Bjarmason
2021-03-31 19:09                       ` [PATCH v5 11/18] match-trees: use "tmp" for mode in shift_tree_by() Ævar Arnfjörð Bjarmason
2021-03-31 23:35                         ` Junio C Hamano
2021-03-31 19:09                       ` [PATCH v5 12/18] tree.h: format argument lists of read_tree() users Ævar Arnfjörð Bjarmason
2021-03-31 19:09                       ` [PATCH v5 13/18] tree-walk.h API: formatting changes for subsequent commit Ævar Arnfjörð Bjarmason
2021-03-31 19:09                       ` [PATCH v5 14/18] tree-walk.h API doc: improve documentation of get_tree_entry() Ævar Arnfjörð Bjarmason
2021-04-01 20:30                         ` Junio C Hamano
2021-04-02  9:27                           ` Ævar Arnfjörð Bjarmason
2021-03-31 19:09                       ` [PATCH v5 15/18] tree-walk.h API: rename get_tree_entry() to get_tree_entry_mode() Ævar Arnfjörð Bjarmason
2021-03-31 19:09                       ` [PATCH v5 16/18] tree-walk.h API: add a get_tree_entry_path() function Ævar Arnfjörð Bjarmason
2021-04-01 20:41                         ` Junio C Hamano
2021-04-02  9:41                           ` Ævar Arnfjörð Bjarmason
2021-03-31 19:09                       ` [PATCH v5 17/18] tree-walk.h API: document and format tree_entry_extract() Ævar Arnfjörð Bjarmason
2021-04-01 20:46                         ` Junio C Hamano
2021-03-31 19:09                       ` [PATCH v5 18/18] tree-entry.h API: rename tree_entry_extract() to tree_entry_extract_mode() Ævar Arnfjörð Bjarmason
2021-04-01 20:49                         ` Junio C Hamano
2021-03-16 15:57         ` [PATCH v3 01/32] diff.c: remove redundant canon_mode() call Ævar Arnfjörð Bjarmason
2021-03-16 15:57         ` [PATCH v3 02/32] notes & match-trees: use name_entry's "pathlen" member Ævar Arnfjörð Bjarmason
2021-03-16 15:58         ` [PATCH v3 03/32] cache.h: add a comment to object_type() Ævar Arnfjörð Bjarmason
2021-03-16 15:58         ` [PATCH v3 04/32] tree-walk.h: add object_type member to name_entry Ævar Arnfjörð Bjarmason
2021-03-16 15:58         ` [PATCH v3 05/32] tree-walk.c: migrate to using new "object_type" field when possible Ævar Arnfjörð Bjarmason
2021-03-16 15:58         ` [PATCH v3 06/32] fast-import tests: test for sorting dir/file foo v.s. foo.txt Ævar Arnfjörð Bjarmason
2021-03-16 15:58         ` [PATCH v3 07/32] mktree tests: test that "mode" is passed when sorting Ævar Arnfjörð Bjarmason
2021-03-16 15:58         ` [PATCH v3 08/32] diff " Ævar Arnfjörð Bjarmason
2021-03-16 15:58         ` [PATCH v3 09/32] cache.h: have base_name_compare() take "is tree?", not "mode" Ævar Arnfjörð Bjarmason
2021-03-16 15:58         ` [PATCH v3 10/32] tree-walk.h users: switch object_type(...) to new .object_type Ævar Arnfjörð Bjarmason
2021-03-16 15:58         ` [PATCH v3 11/32] tree.h: format argument lists of read_tree_recursive() users Ævar Arnfjörð Bjarmason
2021-03-16 15:58         ` [PATCH v3 12/32] tree.h users: format argument lists in archive.c Ævar Arnfjörð Bjarmason
2021-03-16 15:58         ` [PATCH v3 13/32] archive: get rid of 'stage' parameter Ævar Arnfjörð Bjarmason
2021-03-16 15:58         ` [PATCH v3 14/32] tree.h API: make read_tree_fn_t take an "enum object_type" Ævar Arnfjörð Bjarmason
2021-03-16 15:58         ` [PATCH v3 15/32] tree-walk.h users: migrate "p->mode &&" pattern Ævar Arnfjörð Bjarmason
2021-03-16 15:58         ` [PATCH v3 16/32] tree-walk.h users: refactor chained "mode" if/else into switch Ævar Arnfjörð Bjarmason
2021-03-16 15:58         ` [PATCH v3 17/32] tree-walk.h users: migrate miscellaneous "mode" to "object_type" Ævar Arnfjörð Bjarmason
2021-03-16 15:58         ` [PATCH v3 18/32] merge-tree tests: test for the mode comparison in same_entry() Ævar Arnfjörð Bjarmason
2021-03-16 15:58         ` [PATCH v3 19/32] merge-ort: correct reference to test in 62fdec17a11 Ævar Arnfjörð Bjarmason
2021-03-16 15:58         ` [PATCH v3 20/32] fsck.c: switch on "object_type" in fsck_walk_tree() Ævar Arnfjörð Bjarmason
2021-03-16 15:58         ` [PATCH v3 21/32] tree-walk.h users: use temporary variable(s) for "mode" Ævar Arnfjörð Bjarmason
2021-03-16 15:58         ` [PATCH v3 22/32] tree-walk.h API: formatting changes for subsequent commit Ævar Arnfjörð Bjarmason
2021-03-16 15:58         ` [PATCH v3 23/32] tree-walk.h API: rename get_tree_entry() to get_tree_entry_mode() Ævar Arnfjörð Bjarmason
2021-03-16 15:58         ` [PATCH v3 24/32] match-trees: use "tmp" for mode in shift_tree_by() Ævar Arnfjörð Bjarmason
2021-03-16 15:58         ` [PATCH v3 25/32] tree-walk.h API: add get_tree_entry_type() Ævar Arnfjörð Bjarmason
2021-03-16 15:58         ` [PATCH v3 26/32] tree-walk.h API: document and format tree_entry_extract() Ævar Arnfjörð Bjarmason
2021-03-16 15:58         ` [PATCH v3 27/32] tree-entry.h API: rename tree_entry_extract() to tree_entry_extract_mode() Ævar Arnfjörð Bjarmason
2021-03-16 15:58         ` [PATCH v3 28/32] tree-walk.h API: add a tree_entry_extract_all() function Ævar Arnfjörð Bjarmason
2021-03-16 15:58         ` [PATCH v3 29/32] tree-walk.h API: add get_tree_entry_all() Ævar Arnfjörð Bjarmason
2021-03-16 15:58         ` [PATCH v3 30/32] tree-walk.h API: add a get_tree_entry_path() function Ævar Arnfjörð Bjarmason
2021-03-16 15:58         ` [PATCH v3 31/32] blame: emit a better error on 'git blame directory' Ævar Arnfjörð Bjarmason
2021-03-16 15:58         ` [PATCH v3 32/32] tree-walk.h API: add a tree_entry_extract_type() function Ævar Arnfjörð Bjarmason
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       ` [PATCH v2 02/29] notes & match-trees: use name_entry's "pathlen" member Æ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
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       ` [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       ` [PATCH v2 06/29] cache.h: have base_name_compare() take "is tree?", not "mode" Æ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
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       ` [PATCH v2 09/29] tree.h users: format argument lists in archive.c Ævar Arnfjörð Bjarmason
2021-03-16  2:12       ` [PATCH v2 10/29] archive: get rid of 'stage' parameter Æ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
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       ` [PATCH v2 13/29] tree-walk.h users: refactor chained "mode" if/else into switch Æ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
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       ` [PATCH v2 16/29] merge-ort: correct reference to test in 62fdec17a11 Æ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
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       ` [PATCH v2 19/29] tree-walk.h API: formatting changes for subsequent commit Æ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
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  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
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       ` [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       ` [PATCH v2 25/29] tree-walk.h API: add a tree_entry_extract_all() function Æ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
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  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  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
2021-03-08 15:06     ` [PATCH 01/30] diff.c: remove redundant canon_mode() call Æ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
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
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     ` [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
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
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     ` [PATCH 08/30] tree.h: format argument lists of read_tree_recursive() users Æ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
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
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     ` [PATCH 12/30] tree-walk.h users: migrate "p->mode &&" pattern Æ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
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
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
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
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     ` [PATCH 18/30] tree-walk.h users: use temporary variable(s) for "mode" Æ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
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     ` [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
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
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
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
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     ` [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
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     ` [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
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
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
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     ` [PATCH v3 0/9] read_tree() and read_tree_recursive() refactoring Ævar Arnfjörð Bjarmason
2021-03-16  5:37       ` Elijah Newren
2021-03-16 15:52       ` [PATCH v4 " Ævar Arnfjörð Bjarmason
2021-03-16 15:52       ` [PATCH v4 1/9] ls-files tests: add meaningful --with-tree tests Ævar Arnfjörð Bjarmason
2021-03-16 15:52       ` [PATCH v4 2/9] tree.c API: move read_tree() into builtin/ls-files.c Ævar Arnfjörð Bjarmason
2021-03-16 15:52       ` [PATCH v4 3/9] ls-files: don't needlessly pass around stage variable Ævar Arnfjörð Bjarmason
2021-03-16 15:52       ` [PATCH v4 4/9] ls-files: refactor away read_tree() Ævar Arnfjörð Bjarmason
2021-03-16 15:52       ` [PATCH v4 5/9] tree.h API: remove support for starting at prefix != "" Ævar Arnfjörð Bjarmason
2021-03-16 15:52       ` [PATCH v4 6/9] tree.h API: remove "stage" parameter from read_tree_recursive() Ævar Arnfjörð Bjarmason
2021-03-16 15:52       ` [PATCH v4 7/9] tree.h API: rename read_tree_recursive() to read_tree() Ævar Arnfjörð Bjarmason
2021-03-16 15:52       ` [PATCH v4 8/9] show tests: add test for "git show <tree>" Ævar Arnfjörð Bjarmason
2021-03-16 15:52       ` [PATCH v4 9/9] tree.h API: expose read_tree_1() as read_tree_at() Ævar Arnfjörð Bjarmason
2021-03-17 17:38       ` [PATCH v3 0/9] read_tree() and read_tree_recursive() refactoring Junio C Hamano
2021-03-20 22:37         ` [PATCH v5 0/8] " Ævar Arnfjörð Bjarmason
2021-03-20 22:37           ` [PATCH v5 1/8] show tests: add test for "git show <tree>" Ævar Arnfjörð Bjarmason
2021-03-20 22:37           ` [PATCH v5 2/8] ls-files tests: add meaningful --with-tree tests Ævar Arnfjörð Bjarmason
2021-03-20 22:37           ` [PATCH v5 3/8] tree.c API: move read_tree() into builtin/ls-files.c Ævar Arnfjörð Bjarmason
2021-03-20 22:37           ` [PATCH v5 4/8] ls-files: don't needlessly pass around stage variable Ævar Arnfjörð Bjarmason
2021-03-20 22:37           ` [PATCH v5 5/8] ls-files: refactor away read_tree() Ævar Arnfjörð Bjarmason
2021-03-20 22:37           ` [PATCH v5 6/8] archive: stop passing "stage" through read_tree_recursive() Ævar Arnfjörð Bjarmason
2021-03-20 22:37           ` [PATCH v5 7/8] tree.h API: expose read_tree_1() as read_tree_at() Ævar Arnfjörð Bjarmason
2021-03-20 22:37           ` [PATCH v5 8/8] tree.h API: simplify read_tree_recursive() signature Ævar Arnfjörð Bjarmason
2021-03-20 23:08           ` [PATCH v5 0/8] read_tree() and read_tree_recursive() refactoring Junio C Hamano
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     ` [PATCH v3 2/9] tree.c API: move read_tree() into builtin/ls-files.c Æ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
2021-03-15 23:43     ` [PATCH v3 4/9] ls-files: refactor away read_tree() Æ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
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     ` [PATCH v3 7/9] tree.h API: rename read_tree_recursive() to read_tree() Æ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-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
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   ` [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
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
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
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
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 ` [PATCH 2/7] ls-files: don't needlessly pass around stage variable Ævar Arnfjörð Bjarmason
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
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 ` [PATCH 5/7] ls-files: refactor read_one_entry_quick() to use a strbuf Æ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 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

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).