Git development
 help / color / mirror / Atom feed
* Re: [PATCH v2 14/16] fsmonitor: support case-insensitive events
From: Junio C Hamano @ 2024-02-23 18:14 UTC (permalink / raw)
  To: Jeff Hostetler via GitGitGadget
  Cc: git, Patrick Steinhardt, Jeff Hostetler, Jeff Hostetler
In-Reply-To: <288f3f4e54e98a68d72e97125b1520605c138c3c.1708658300.git.gitgitgadget@gmail.com>

"Jeff Hostetler via GitGitGadget" <gitgitgadget@gmail.com> writes:

> +/*
> + * Use the name-hash to do a case-insensitive cache-entry lookup with
> + * the pathname and invalidate the cache-entry.
> + *
> + * Returns the number of cache-entries that we invalidated.
> + */
> +static size_t handle_using_name_hash_icase(
> +	struct index_state *istate, const char *name)
> +{
> +	struct cache_entry *ce = NULL;
> +
> +	ce = index_file_exists(istate, name, strlen(name), 1);
> +	if (!ce)
> +		return 0;
> +
> +	/*
> +	 * A case-insensitive search in the name-hash using the
> +	 * observed pathname found a cache-entry, so the observed path
> +	 * is case-incorrect.  Invalidate the cache-entry and use the
> +	 * correct spelling from the cache-entry to invalidate the
> +	 * untracked-cache.  Since we now have sparse-directories in
> +	 * the index, the observed pathname may represent a regular
> +	 * file or a sparse-index directory.
> +	 *
> +	 * Note that we should not have seen FSEvents for a
> +	 * sparse-index directory, but we handle it just in case.
> +	 *
> +	 * Either way, we know that there are not any cache-entries for
> +	 * children inside the cone of the directory, so we don't need to
> +	 * do the usual scan.
> +	 */
> +	trace_printf_key(&trace_fsmonitor,
> +			 "fsmonitor_refresh_callback MAP: '%s' '%s'",
> +			 name, ce->name);
> +
> +	untracked_cache_invalidate_trimmed_path(istate, ce->name, 0);
> +	ce->ce_flags &= ~CE_FSMONITOR_VALID;
> +	return 1;
> +}

You first ask the name-hash to turn the incoming "name" into the
case variant that we know about, i.e. ce->name, and use that to
access the untracked cache.  Clever and makes sense.  But if we have
ce->name, doesn't it mean the name is tracked?  Do we find anything
useful to do in the untracked cache invalidation codepath in that
case?

An FSmonitor event with case-incorrect pathname for a directory may
not be this trivial, I presume, and I expect that is what the
remainder of this patch is about.

> +
> +/*
> + * Use the dir-name-hash to find the correct-case spelling of the
> + * directory.  Use the canonical spelling to invalidate all of the
> + * cache-entries within the matching cone.
> + *
> + * Returns the number of cache-entries that we invalidated.
> + */
> +static size_t handle_using_dir_name_hash_icase(
> +	struct index_state *istate, const char *name)

It is a bit unfortunate that here on the name-hash side we contrast
the two helper function variants as "dir-name" vs "name", while the
original handle_path side use "without_slash" vs "with_slash".

If I understand correctly, it is not like there are two distinct
hashes, "name-hash" vs "dir-name-hash".  Both of these helpers use
the same "name-hash" mechanism, and this function differs from the
previous one in that it is about a directory, which is why it has
"dir" in its name.  I wonder if we renamed the other one with
"nondir" in its name, and the other without_slash and with_slash
pair to match, e.g., handle_nondir_path() vs handle_dir_path(), or
something like that, the resulting names for these four functions
become easier to contrast and understand?

> +{
> +	struct strbuf canonical_path = STRBUF_INIT;
> +	int pos;
> +	size_t len = strlen(name);
> +	size_t nr_in_cone;
> +
> +	if (name[len - 1] == '/')
> +		len--;
> +
> +	if (!index_dir_find(istate, name, len, &canonical_path))
> +		return 0; /* name is untracked */
> +
> +	if (!memcmp(name, canonical_path.buf, canonical_path.len)) {
> +		strbuf_release(&canonical_path);
> +		/*
> +		 * NEEDSWORK: Our caller already tried an exact match
> +		 * and failed to find one.  They called us to do an
> +		 * ICASE match, so we should never get an exact match,
> +		 * so we could promote this to a BUG() here if we
> +		 * wanted to.  It doesn't hurt anything to just return
> +		 * 0 and go on becaus we should never get here.  Or we
> +		 * could just get rid of the memcmp() and this "if"
> +		 * clause completely.
> +		 */
> +		return 0; /* should not happen */
> +	}

"becaus" -> "because".

If we should never get here, having BUG("we should never get here")
would not hurt anything, either.  On the other hand, silently
returning 0 will hide the bug under the carpet, and I am not sure it
is fair to call it "doesn't hurt anything".

> +
> +	trace_printf_key(&trace_fsmonitor,
> +			 "fsmonitor_refresh_callback MAP: '%s' '%s'",
> +			 name, canonical_path.buf);
> +
> +	/*
> +	 * The dir-name-hash only tells us the corrected spelling of
> +	 * the prefix.  We have to use this canonical path to do a
> +	 * lookup in the cache-entry array so that we repeat the
> +	 * original search using the case-corrected spelling.
> +	 */
> +	strbuf_addch(&canonical_path, '/');
> +	pos = index_name_pos(istate, canonical_path.buf,
> +			     canonical_path.len);
> +	nr_in_cone = handle_path_with_trailing_slash(
> +		istate, canonical_path.buf, pos);
> +	strbuf_release(&canonical_path);
> +	return nr_in_cone;
> +}

Nice.  Do we need to give this corrected name to help untracked
cache invalidation from the caller that called us?

> @@ -319,6 +416,19 @@ static void fsmonitor_refresh_callback(struct index_state *istate, char *name)
>  	else
>  		nr_in_cone = handle_path_without_trailing_slash(istate, name, pos);
>  
> +	/*
> +	 * If we did not find an exact match for this pathname or any
> +	 * cache-entries with this directory prefix and we're on a
> +	 * case-insensitive file system, try again using the name-hash
> +	 * and dir-name-hash.
> +	 */
> +	if (!nr_in_cone && ignore_case) {
> +		nr_in_cone = handle_using_name_hash_icase(istate, name);
> +		if (!nr_in_cone)
> +			nr_in_cone = handle_using_dir_name_hash_icase(
> +				istate, name);
> +	}

It might be interesting to learn how often we go through these
"fallback" code paths by tracing.  Maybe it will become too noisy?
I dunno.

>  	if (nr_in_cone)
>  		trace_printf_key(&trace_fsmonitor,
>  				 "fsmonitor_refresh_callback CNT: %d",

^ permalink raw reply

* Re: [PATCH v2 13/16] fsmonitor: trace the new invalidated cache-entry count
From: Junio C Hamano @ 2024-02-23 17:53 UTC (permalink / raw)
  To: Jeff Hostetler via GitGitGadget
  Cc: git, Patrick Steinhardt, Jeff Hostetler, Jeff Hostetler
In-Reply-To: <58b36673e151ad15eb44c9ca1c03cfef51657d11.1708658300.git.gitgitgadget@gmail.com>

"Jeff Hostetler via GitGitGadget" <gitgitgadget@gmail.com> writes:

> From: Jeff Hostetler <jeffhostetler@github.com>
>
> Consolidate the directory/non-directory calls to the refresh handler
> code.  Log the resulting count of invalidated cache-entries.

OK.  Again, there is nothing surprising in the changes in the patch.
Looking good.

> The nr_in_cone value will be used in a later commit to decide if
> we also need to try to do case-insensitive lookups.
>
> Signed-off-by: Jeff Hostetler <jeffhostetler@github.com>
> ---
>  fsmonitor.c | 15 ++++++++++-----
>  1 file changed, 10 insertions(+), 5 deletions(-)

> diff --git a/fsmonitor.c b/fsmonitor.c
> index c16ed5d8758..739ddbf7aca 100644
> --- a/fsmonitor.c
> +++ b/fsmonitor.c
> @@ -308,16 +308,21 @@ static void fsmonitor_refresh_callback(struct index_state *istate, char *name)
>  {
>  	int len = strlen(name);
>  	int pos = index_name_pos(istate, name, len);
> +	size_t nr_in_cone;
>  
>  	trace_printf_key(&trace_fsmonitor,
>  			 "fsmonitor_refresh_callback '%s' (pos %d)",
>  			 name, pos);
>  
> -	if (name[len - 1] == '/') {
> -		handle_path_with_trailing_slash(istate, name, pos);
> -	} else {
> -		handle_path_without_trailing_slash(istate, name, pos);
> -	}
> +	if (name[len - 1] == '/')
> +		nr_in_cone = handle_path_with_trailing_slash(istate, name, pos);
> +	else
> +		nr_in_cone = handle_path_without_trailing_slash(istate, name, pos);
> +
> +	if (nr_in_cone)
> +		trace_printf_key(&trace_fsmonitor,
> +				 "fsmonitor_refresh_callback CNT: %d",
> +				 (int)nr_in_cone);
>  }
>  
>  /*

^ permalink raw reply

* Re: [PATCH v2 12/16] fsmonitor: return invalided cache-entry count on non-directory event
From: Junio C Hamano @ 2024-02-23 17:51 UTC (permalink / raw)
  To: Jeff Hostetler via GitGitGadget
  Cc: git, Patrick Steinhardt, Jeff Hostetler, Jeff Hostetler
In-Reply-To: <f77d68c78ada02bfb4b96759f6ad82ebff00b35b.1708658300.git.gitgitgadget@gmail.com>

"Jeff Hostetler via GitGitGadget" <gitgitgadget@gmail.com> writes:

> From: Jeff Hostetler <jeffhostetler@github.com>
>
> Teah the refresh callback helper function for unqualified FSEvents

Teach?

> (pathnames without a trailing slash) to return the number of
> cache-entries that were invalided in response to the event.
>
> This will be used in a later commit to help determine if the observed
> pathname was (possibly) case-incorrect when (on a case-insensitive
> file system).
>
> Signed-off-by: Jeff Hostetler <jeffhostetler@github.com>
> ---
>  fsmonitor.c | 10 ++++++++--
>  1 file changed, 8 insertions(+), 2 deletions(-)

I do not see anything unexpected in the change to the code below.
Looking good.

Thanks.

> diff --git a/fsmonitor.c b/fsmonitor.c
> index a51c17cda70..c16ed5d8758 100644
> --- a/fsmonitor.c
> +++ b/fsmonitor.c
> @@ -196,8 +196,10 @@ static size_t handle_path_with_trailing_slash(
>   * do not know it is case-correct or -incorrect.
>   *
>   * Assume it is case-correct and try an exact match.
> + *
> + * Return the number of cache-entries that we invalidated.
>   */
> -static void handle_path_without_trailing_slash(
> +static size_t handle_path_without_trailing_slash(
>  	struct index_state *istate, const char *name, int pos)
>  {
>  	/*
> @@ -218,7 +220,9 @@ static void handle_path_without_trailing_slash(
>  		 * at that directory. (That is, assume no D/F conflicts.)
>  		 */
>  		istate->cache[pos]->ce_flags &= ~CE_FSMONITOR_VALID;
> +		return 1;
>  	} else {
> +		size_t nr_in_cone;
>  		struct strbuf work_path = STRBUF_INIT;
>  
>  		/*
> @@ -232,8 +236,10 @@ static void handle_path_without_trailing_slash(
>  		strbuf_add(&work_path, name, strlen(name));
>  		strbuf_addch(&work_path, '/');
>  		pos = index_name_pos(istate, work_path.buf, work_path.len);
> -		handle_path_with_trailing_slash(istate, work_path.buf, pos);
> +		nr_in_cone = handle_path_with_trailing_slash(
> +			istate, work_path.buf, pos);
>  		strbuf_release(&work_path);
> +		return nr_in_cone;
>  	}
>  }

^ permalink raw reply

* Re: [PATCH v2 11/16] fsmonitor: remove custom loop from non-directory path handler
From: Junio C Hamano @ 2024-02-23 17:47 UTC (permalink / raw)
  To: Jeff Hostetler via GitGitGadget
  Cc: git, Patrick Steinhardt, Jeff Hostetler, Jeff Hostetler
In-Reply-To: <1853f77d3331f7736139f686ac2efee6d68f9207.1708658300.git.gitgitgadget@gmail.com>

"Jeff Hostetler via GitGitGadget" <gitgitgadget@gmail.com> writes:

>  static void handle_path_without_trailing_slash(
>  	struct index_state *istate, const char *name, int pos)
>  {
> -	int i;
> -
>  	/*
>  	 * Mark the untracked cache dirty for this path (regardless of
>  	 * whether or not we find an exact match for it in the index).
> @@ -200,33 +212,28 @@ static void handle_path_without_trailing_slash(
>  
>  	if (pos >= 0) {
>  		/*
> -		 * We have an exact match for this path and can just
> -		 * invalidate it.
> +		 * An exact match on a tracked file. We assume that we
> +		 * do not need to scan forward for a sparse-directory
> +		 * cache-entry with the same pathname, nor for a cone
> +		 * at that directory. (That is, assume no D/F conflicts.)
>  		 */
>  		istate->cache[pos]->ce_flags &= ~CE_FSMONITOR_VALID;
>  	} else {
> +		struct strbuf work_path = STRBUF_INIT;
> +
>  		/*
> +		strbuf_add(&work_path, name, strlen(name));
> +		strbuf_addch(&work_path, '/');
> +		pos = index_name_pos(istate, work_path.buf, work_path.len);
> +		handle_path_with_trailing_slash(istate, work_path.buf, pos);
> +		strbuf_release(&work_path);
>  	}
>  }

The "with trailing slash" variant is returning a useful value to
this caller that ignores it, but we do not yet return a value from
this function, so that is OK.  The name being a name that may be in
different case from what we know in the index is not yet handled in
this step (we have "Assume it is case-correct" in the comment) and
that applies for both the main array of cache entries as well as the
untracked cache.

It will be exciting to see how these are lifted.  The main array has
some helper functions that uses name-hash features to help icase
matches, but I do not offhand recall what we have for the untracked
cache side.

^ permalink raw reply

* Re: [PATCH v2 7/8] cherry-pick: enforce `--keep-redundant-commits` incompatibility
From: Junio C Hamano @ 2024-02-23 17:41 UTC (permalink / raw)
  To: Brian Lyles; +Cc: phillip.wood, git, newren, me
In-Reply-To: <17b669c4bfe6602f.70b1dd9aae081c6e.203dcd72f6563036@zivdesk>

"Brian Lyles" <brianmlyles@gmail.com> writes:

>> Well spotted, do we really need a new test file just for this though? I 
>> wonder if the new test would be better off living in 
>> t3505-cherry-pick-empty.sh or t3507-cherry-pick-conflict.sh
>
> I was modelling this off of 't3422-rebase-incompatible-options.sh'.
> Additionally, I do feel like these tests are only tangentially related
> to the tests that actually exercise the features themselves. Notably,
> the setup requirements are drastically different (simpler) since the
> test should fail long before any setup actually matters.

It is exactly the reason why we do not want to waste a scarce
resource, the test file number, when we do not have to.

Sanity checking the command line options and failing when they do
not make sense is a small part of what a command needs to do; you
are exactly right to say "they do not really exercise the main
feature".

As these "we expect this to fail" tests do not depend on and do not
have to modify the state of the test repository, we do not even have
to do any extra set-up over what the existing test script already
establishes, no?  No additional set-up is even better than a simpler
but non-zero set-up we need to newly do, right?

^ permalink raw reply

* Re: [PATCH v2 09/16] fsmonitor: move untracked invalidation into helper functions
From: Junio C Hamano @ 2024-02-23 17:36 UTC (permalink / raw)
  To: Jeff Hostetler via GitGitGadget
  Cc: git, Patrick Steinhardt, Jeff Hostetler, Jeff Hostetler
In-Reply-To: <af6f57ab3e6d61036cd969f5fd9256200313aaa9.1708658300.git.gitgitgadget@gmail.com>

"Jeff Hostetler via GitGitGadget" <gitgitgadget@gmail.com> writes:

> From: Jeff Hostetler <jeffhostetler@github.com>
>
> Move the call to invalidate the untracked cache for the FSEvent
> pathname into the two helper functions.
>
> In a later commit in this series, we will call these helpers
> from other contexts and it safer to include the UC invalidation
> in the helper than to remember to also add it to each helper
> call-site.
>
> Signed-off-by: Jeff Hostetler <jeffhostetler@github.com>
> ---
>  fsmonitor.c | 26 +++++++++++++++++++-------
>  1 file changed, 19 insertions(+), 7 deletions(-)

Thanks.  The steps in this iteration makes this move much less
confusing to me than in the previous one.  We used to call one of
"handle path with/without trailing slash" functions and then called
the invalidation.  Now the invalidation happens in these "handle path"
functions.

The unexplained change in behaviour is that we used to do the rest
of "handle path" and invalidation was done at the end.  Now we do it
upfront.  I think the "rest" works solely based on what is in the
main in-core index array (i.e. the_index.cache[] aka active_cache[])
and affects only what is in the in-core index array, while
untracked_cache_invalidate*() works solely based on what is in the
untracked cache extension (i.e. the_index.untracked) and affects
only what is in there, so the order of these two does not matter.

Am I correct?

Or does it affect correctness or performance or whatever in any way?
IOW, is there a reason why it is better to do the invalidation first
and then doing the "rest" after (hence this patch flips the order of
two to _improve_ something)?

Thanks.

^ permalink raw reply

* Re: [PATCH v3 4/5] Always check `parse_tree*()`'s return value
From: Junio C Hamano @ 2024-02-23 17:17 UTC (permalink / raw)
  To: Johannes Schindelin
  Cc: Johannes Schindelin via GitGitGadget, git, Patrick Steinhardt,
	Eric Sunshine
In-Reply-To: <883087b8-b013-7b30-5485-719a1c310608@gmx.de>

Johannes Schindelin <Johannes.Schindelin@gmx.de> writes:

> Right. I had used
>
>   $ git grep 'unable to read tree .*%s' | sed -n 's/.*_("\([^"]*\).*/\1/p' | sort | uniq -c
>        11 unable to read tree %s
>         3 unable to read tree (%s)
>
> only to realize that the 11 were the ones I added.🤦 Re-running the same
> command on v2.43.0 reports only the 3 parenthesized ones.

I think we probably should discuss what format is the easiest to
understand and most logical to readers, and unify to such a format,
not necessarily the current majority, in the longer term.  But for
now, let's pick one that costs less to unify to.

We may also want to cast a wider net to make things consistent.  For
example, we learn that the parenthesized one is not necessarily more
prevalent in a larger picture.

Let me annotate the output from this command:

    $ git grep -h -E \
      -e '(unable to|not) (read|find|acccess) (blob|tree|commit|tag) .*%s' master po/ |
      sort -u

1. msgid "cannot find commit %s (%s)"

   The first one is a textual refname, the next one is oid-to-hex.

2. msgid "cannot read blob %s for path %s"

   The first one is oid-to-hex, the other is a pathname.

3. msgid "could not find commit %s"

   oid-to-hex (in commit-graph.c)

4. msgid "could not read commit message of %s"

   oid-to-hex (in sequencer.c)

5. msgid "could not read commit message: %s"

   This is irrelevant to the topic, as %s is for strerror().

6. msgid "unable to access commit %s"

   oid-to-hex (in builtin/pull.c)

7. msgid "unable to read commit message from '%s'"

   This message is in po/ but it seems that it no longer is used
   anywhere in the source.

8. msgid "unable to read tree %s"
9. msgid "unable to read tree (%s)"

   We know about these two already.

We seem to just use unadorned %s for many messages when talking
about commit objects, some are inside a pair of 'single quotes',
When we are giving a long hexadecimal string, especially without
doing any abbreviation, I personally think it is a waste to enclose
it in any punctuation pair, so if I were to vote today, I would
probably support standardizing on "tree %s", "blob %s", etc., but I
think that is just a personal preference (not even a "taste" thing).

In any case, all of the above is clearly outside the scope of this
series.

^ permalink raw reply

* [ANNOUNCE] Git v2.44.0
From: Junio C Hamano @ 2024-02-23 17:17 UTC (permalink / raw)
  To: git; +Cc: Linux Kernel, git-packagers

The latest feature release Git v2.44.0 is now available at the
usual places.  It is comprised of 503 non-merge commits since
v2.43.0, contributed by 85 people, 34 of which are new faces [*].

The tarballs are found at:

    https://www.kernel.org/pub/software/scm/git/

The following public repositories all have a copy of the 'v2.44.0'
tag and the 'master' branch that the tag points at:

  url = https://git.kernel.org/pub/scm/git/git
  url = https://kernel.googlesource.com/pub/scm/git/git
  url = git://repo.or.cz/alt-git.git
  url = https://github.com/gitster/git

New contributors whose contributions weren't in v2.43.0 are as follows.
Welcome to the Git development community!

  Achu Luma, Antonin Delpeuch, Benjamin Lehmann, Britton Leo Kerin,
  Carlos Andrés Ramírez Cataño, Chandra Pratap, Ghanshyam
  Thakkar, Illia Bobyr, James Touton, Janik Haag, Joanna Wang,
  Josh Brobst, Julian Prein, Justin Tobler, Kyle Lippincott,
  lumynou5, Maarten van der Schrieck, Marcel Krause, Marcelo
  Roberto Jimenez, Michael Lohmann, moti sd, Nikolay Borisov,
  Nikolay Edigaryev, Ondrej Pohorelsky, Sam Delmerico, Sergey
  Kosukhin, Shreyansh Paliwal, Sören Krecker, Stan Hu, Tamino
  Bauknecht, Wilfred Hughes, Willem Verstraeten, Xiaoguang WANG,
  and Zach FettersMoore.

Returning contributors who helped this release are as follows.
Thanks for your continued support.

  Alexander Shopov, Andy Koppe, Arkadii Yakovets, Arthur Chan,
  Bagas Sanjaya, Calvin Wan, Carlo Marcelo Arenas Belón, Christian
  Couder, Dragan Simic, Elijah Newren, Emir SARI, Eric Sunshine,
  Glen Choo, Han-Wen Nienhuys, Jean-Noël Avila, Jeff Hostetler,
  Jeff King, Jiang Xin, Johannes Schindelin, John Cai, Jonathan
  Tan, Jordi Mas, Josh Soref, Josh Steadmon, Josip Sokcevic, Junio
  C Hamano, Kate Golovanova, Konstantin Ryabitsev, Kristoffer
  Haugsbakk, Linus Arver, Matthias Aßhauer, M Hickford, Orgad
  Shaneh, Oswald Buddenhagen, Patrick Steinhardt, Peter Krefting,
  Philippe Blain, Phillip Wood, Ralf Thielow, Randall S. Becker,
  René Scharfe, Rubén Justo, Simon Ser, SZEDER Gábor, Taylor
  Blau, Teng Long, Todd Zullinger, Toon Claes, Vegard Nossum,
  Victoria Dye, and Yi-Jyun Pan.

[*] We are counting not just the authorship contribution but issue
    reporting, mentoring, helping and reviewing that are recorded in
    the commit trailers.

----------------------------------------------------------------

Git v2.44 Release Notes
=======================

Backward Compatibility Notes

 * "git checkout -B <branch>" used to allow switching to a branch that
   is in use on another worktree, but this was by mistake.  The users
   need to use "--ignore-other-worktrees" option.


UI, Workflows & Features

 * "git add" and "git stash" learned to support the ":(attr:...)"
   magic pathspec.

 * "git rebase --autosquash" is now enabled for non-interactive rebase,
   but it is still incompatible with the apply backend.

 * Introduce "git replay", a tool meant on the server side without
   working tree to recreate a history.

 * "git merge-file" learned to take the "--diff-algorithm" option to
   use algorithm different from the default "myers" diff.

 * Command line completion (in contrib/) learned to complete path
   arguments to the "add/set" subcommands of "git sparse-checkout"
   better.

 * "git checkout -B <branch> [<start-point>]" allowed a branch that is
   in use in another worktree to be updated and checked out, which
   might be a bit unexpected.  The rule has been tightened, which is a
   breaking change.  "--ignore-other-worktrees" option is required to
   unbreak you, if you are used to the current behaviour that "-B"
   overrides the safety.

 * The builtin_objectmode attribute is populated for each path
   without adding anything in .gitattributes files, which would be
   useful in magic pathspec, e.g., ":(attr:builtin_objectmode=100755)"
   to limit to executables.

 * "git fetch" learned to pay attention to "fetch.all" configuration
   variable, which pretends as if "--all" was passed from the command
   line when no remote parameter was given.

 * In addition to (rather cryptic) Security Identifiers, show username
   and domain in the error message when we barf on mismatch between
   the Git directory and the current user on Windows.

 * The error message given when "git branch -d branch" fails due to
   commits unique to the branch has been split into an error and a new
   conditional advice message.

 * When given an existing but unreadable file as a configuration file,
   gitweb behaved as if the file did not exist at all, but now it
   errors out.  This is a change that may break backward compatibility.

 * When $HOME/.gitconfig is missing but XDG config file is available, we
   should write into the latter, not former.  "git gc" and "git
   maintenance" wrote into a wrong "global config" file, which have
   been corrected.

 * Define "special ref" as a very narrow set that consists of
   FETCH_HEAD and MERGE_HEAD, and clarify everything else that used to
   be classified as such are actually just pseudorefs.

 * All conditional "advice" messages show how to turn them off, which
   becomes repetitive.  Setting advice.* configuration explicitly on
   now omits the instruction part.

 * The "disable repository discovery of a bare repository" check,
   triggered by setting safe.bareRepository configuration variable to
   'explicit', has been loosened to exclude the ".git/" directory inside
   a non-bare repository from the check.  So you can do "cd .git &&
   git cmd" to run a Git command that works on a bare repository without
   explicitly specifying $GIT_DIR now.

 * The completion script (in contrib/) learned more options that can
   be used with "git log".

 * The labels on conflict markers for the common ancestor, our version,
   and the other version are available to custom 3-way merge driver
   via %S, %X, and %Y placeholders.

 * The write codepath for the reftable data learned to honor
   core.fsync configuration.

 * The "--fsck-objects" option of "git index-pack" now can take the
   optional parameter to tweak severity of different fsck errors.

 * The wincred credential backend has been taught to support oauth
   refresh token the same way as credential-cache and
   credential-libsecret backends.

 * Command line completion support (in contrib/) has been
   updated for "git bisect".

 * "git branch" and friends learned to use the formatted text as
   sorting key, not the underlying timestamp value, when the --sort
   option is used with author or committer timestamp with a format
   specifier (e.g., "--sort=creatordate:format:%H:%M:%S").

 * The command line completion script (in contrib/) learned to
   complete configuration variable names better.


Performance, Internal Implementation, Development Support etc.

 * Process to add some form of low-level unit tests has started.

 * Add support for GitLab CI.

 * "git for-each-ref --no-sort" still sorted the refs alphabetically
   which paid non-trivial cost.  It has been redefined to show output
   in an unspecified order, to allow certain optimizations to take
   advantage of.

 * Simplify API implementation to delete references by eliminating
   duplication.

 * Subject approxidate() and show_date() machinery to OSS-Fuzz.

 * A new helper to let us pretend that we called lstat() when we know
   our cache_entry is up-to-date via fsmonitor.

 * The optimization based on fsmonitor in the "diff --cached"
   codepath is resurrected with the "fake-lstat" introduced earlier.

 * Test balloon to use C99 "bool" type from <stdbool.h> has been
   added.

 * "git clone" has been prepared to allow cloning a repository with
   non-default hash function into a repository that uses the reftable
   backend.

 * Streaming spans of packfile data used to be done only from a
   single, primary, pack in a repository with multiple packfiles.  It
   has been extended to allow reuse from other packfiles, too.

 * Comment updates to help developers not to attempt to modify
   messages from plumbing commands that must stay constant.

   It might make sense to reassess the plumbing needs every few years,
   but that should be done as a separate effort.

 * Move test-ctype helper to the unit-test framework.

 * Instead of manually creating refs/ hierarchy on disk upon a
   creation of a secondary worktree, which is only usable via the
   files backend, use the refs API to populate it.

 * CI for GitLab learned to drive macOS jobs.

 * A few tests to "git commit -o <pathspec>" and "git commit -i
   <pathspec>" has been added.

 * Tests on ref API are moved around to prepare for reftable.

 * The Makefile often had to say "-L$(path) -R$(path)" that repeats
   the path to the same library directory for link time and runtime.
   A Makefile template is used to reduce such repetition.

 * The priority queue test has been migrated to the unit testing
   framework.

 * Setting `feature.experimental` opts the user into multi-pack reuse
   experiment

 * Squelch node.js 16 deprecation warnings from GitHub Actions CI
   by updating actions/github-script and actions/checkout that use
   node.js 20.

 * The mechanism to report the filename in the source code, used by
   the unit-test machinery, assumed that the compiler expanded __FILE__
   to the path to the source given to the $(CC), but some compilers
   give full path, breaking the output.  This has been corrected.


Fixes since v2.43
-----------------

 * The way CI testing used "prove" could lead to running the test
   suite twice needlessly, which has been corrected.

 * Update ref-related tests.

 * "git format-patch --encode-email-headers" ignored the option when
   preparing the cover letter, which has been corrected.

 * Newer versions of Getopt::Long started giving warnings against our
   (ab)use of it in "git send-email".  Bump the minimum version
   requirement for Perl to 5.8.1 (from September 2002) to allow
   simplifying our implementation.

 * Earlier we stopped relying on commit-graph that (still) records
   information about commits that are lost from the object store,
   which has negative performance implications.  The default has been
   flipped to disable this pessimization.

 * Stale URLs have been updated to their current counterparts (or
   archive.org) and HTTP links are replaced with working HTTPS links.

 * trace2 streams used to record the URLs that potentially embed
   authentication material, which has been corrected.

 * The sample pre-commit hook that tries to catch introduction of new
   paths that use potentially non-portable characters did not notice
   an existing path getting renamed to such a problematic path, when
   rename detection was enabled.

 * The command line parser for the "log" family of commands was too
   loose when parsing certain numbers, e.g., silently ignoring the
   extra 'q' in "git log -n 1q" without complaining, which has been
   tightened up.

 * "git $cmd --end-of-options --rev -- --path" for some $cmd failed
   to interpret "--rev" as a rev, and "--path" as a path.  This was
   fixed for many programs like "reset" and "checkout".

 * "git bisect reset" has been taught to clean up state files and refs
   even when BISECT_START file is gone.

 * Some codepaths did not correctly parse configuration variables
   specified with valueless "true", which has been corrected.

 * Code clean-up for sanity checking of command line options for "git
   show-ref".

 * The code to parse the From e-mail header has been updated to avoid
   recursion.

 * "git fetch --atomic" issued an unnecessary empty error message,
   which has been corrected.

 * Command line completion script (in contrib/) learned to work better
   with the reftable backend.

 * "git status" is taught to show both the branch being bisected and
   being rebased when both are in effect at the same time.

 * "git archive --list extra garbage" silently ignored excess command
   line parameters, which has been corrected.

 * "git sparse-checkout set" added default patterns even when the
   patterns are being fed from the standard input, which has been
   corrected.

 * "git sparse-checkout (add|set) --[no-]cone --end-of-options" did
   not handle "--end-of-options" correctly after a recent update.

 * Unlike other environment variables that took the usual
   true/false/yes/no as well as 0/1, GIT_FLUSH only understood 0/1,
   which has been corrected.

 * Clearing in-core repository (happens during e.g., "git fetch
   --recurse-submodules" with commit graph enabled) made in-core
   commit object in an inconsistent state by discarding the necessary
   data from commit-graph too early, which has been corrected.

 * Update to a new feature recently added, "git show-ref --exists".

 * oss-fuzz tests are built and run in CI.
   (merge c4a9cf1df3 js/oss-fuzz-build-in-ci later to maint).

 * Rename detection logic ignored the final line of a file if it is an
   incomplete line.

 * GitHub CI update.
   (merge 0188b2c8e0 pb/ci-github-skip-logs-for-broken-tests later to maint).

 * "git diff --no-rename A B" did not disable rename detection but did
   not trigger an error from the command line parser.

 * "git archive --remote=<remote>" learned to talk over the smart
   http (aka stateless) transport.
   (merge 176cd68634 jx/remote-archive-over-smart-http later to maint).

 * Fetching via protocol v0 over Smart HTTP transport sometimes failed
   to correctly auto-follow tags.
   (merge fba732c462 jk/fetch-auto-tag-following-fix later to maint).

 * The documentation for the --exclude-per-directory option marked it
   as deprecated, which confused readers into thinking there may be a
   plan to remove it in the future, which was not our intention.
   (merge 0009542cab jc/ls-files-doc-update later to maint).

 * "git diff --no-index file1 file2" segfaulted while invoking the
   external diff driver, which has been corrected.

 * Rewrite //-comments to /* comments */ in files whose comments
   prevalently use the latter.

 * Cirrus CI jobs started breaking because we specified version of
   FreeBSD that is no longer available, which has been corrected.
   (merge 81fffb66d3 cb/use-freebsd-13-2-at-cirrus-ci later to maint).

 * A caller called index_file_exists() that takes a string expressed
   as <ptr, length> with a wrong length, which has been corrected.
   (merge 156e28b36d jh/sparse-index-expand-to-path-fix later to maint).

 * A failed "git tag -s" did not necessarily result in an error
   depending on the crypto backend, which has been corrected.

 * "git stash" sometimes was silent even when it failed due to
   unwritable index file, which has been corrected.

 * "git show-ref --verify" did not show things like "CHERRY_PICK_HEAD",
   which has been corrected.

 * Recent conversion to allow more than 0/1 in GIT_FLUSH broke the
   mechanism by flipping what yes/no means by mistake, which has been
   corrected.

 * The sequencer machinery does not use the ref API and instead
   records names of certain objects it needs for its correct operation
   in temporary files, which makes these objects susceptible to loss
   by garbage collection.  These temporary files have been added as
   starting points for reachability analysis to fix this.
   (merge bc7f5db896 pw/gc-during-rebase later to maint).

 * "git cherry-pick" invoked during "git rebase -i" session lost
   the authorship information, which has been corrected.
   (merge e4301f73ff vn/rebase-with-cherry-pick-authorship later to maint).

 * The code paths that call repo_read_object_file() have been
   tightened to react to errors.
   (merge 568459bf5e js/check-null-from-read-object-file later to maint).

 * Other code cleanup, docfix, build fix, etc.
   (merge 5aea3955bc rj/clarify-branch-doc-m later to maint).
   (merge 9cce3be2df bk/bisect-doc-fix later to maint).
   (merge 8430b438f6 vd/fsck-submodule-url-test later to maint).
   (merge 3cb4384683 jc/t0091-with-unknown-git later to maint).
   (merge 020456cb74 rs/receive-pack-remove-find-header later to maint).
   (merge bc47139f4f la/trailer-cleanups later to maint).

----------------------------------------------------------------

Changes since v2.43.0 are as follows:

Achu Luma (2):
      unit-tests: rewrite t/helper/test-ctype.c as a unit test
      t2400: avoid losing exit status to pipes

Alexander Shopov (1):
      l10n: bg.po: Updated Bulgarian translation (5610t)

Andy Koppe (3):
      rebase: fully ignore rebase.autoSquash without -i
      rebase: support --autosquash without -i
      rebase: rewrite --(no-)autosquash documentation

Antonin Delpeuch (2):
      merge-file: add --diff-algorithm option
      merge-ll: expose revision names to custom drivers

Arkadii Yakovets (3):
      l10n: uk: v2.44 localization update
      l10n: uk: v2.44 update (round 2)
      l10n: uk: v2.44 update (round 3)

Arthur Chan (1):
      fuzz: add new oss-fuzz fuzzer for date.c / date.h

Bagas Sanjaya (1):
      l10n: po-id for 2.44 (round 1)

Britton Leo Kerin (9):
      doc: use singular form of repeatable path arg
      doc: refer to pathspec instead of path
      completion: tests: always use 'master' for default initial branch name
      completion: bisect: complete bad, new, old, and help subcommands
      completion: bisect: complete custom terms and related options
      completion: bisect: complete missing --first-parent and - -no-checkout options
      completion: new function __git_complete_log_opts
      completion: bisect: complete log opts for visualize subcommand
      completion: bisect: recognize but do not complete view subcommand

Carlo Marcelo Arenas Belón (1):
      ci: update FreeBSD cirrus job

Chandra Pratap (4):
      sideband.c: remove redundant 'NEEDSWORK' tag
      write-or-die: make GIT_FLUSH a Boolean environment variable
      t4129: prevent loss of exit code due to the use of pipes
      tests: move t0009-prio-queue.sh to the new unit testing framework

Elijah Newren (32):
      t6429: remove switching aspects of fast-rebase
      replay: introduce new builtin
      replay: start using parse_options API
      replay: die() instead of failing assert()
      replay: introduce pick_regular_commit()
      replay: change rev walking options
      replay: add an important FIXME comment about gpg signing
      replay: remove progress and info output
      replay: remove HEAD related sanity check
      replay: make it a minimal server side command
      replay: use standard revision ranges
      replay: add --advance or 'cherry-pick' mode
      replay: add --contained to rebase contained branches
      replay: stop assuming replayed branches do not diverge
      completion: squelch stray errors in sparse-checkout completion
      completion: fix logic for determining whether cone mode is active
      completion: avoid misleading completions in cone mode
      completion: avoid user confusion in non-cone mode
      treewide: remove unnecessary includes from header files
      treewide: remove unnecessary includes in source files
      archive.h: remove unnecessary include
      blame.h: remove unnecessary includes
      fsmonitor--daemon.h: remove unnecessary includes
      http.h: remove unnecessary include
      line-log.h: remove unnecessary include
      pkt-line.h: remove unnecessary include
      submodule-config.h: remove unnecessary include
      trace2/tr2_tls.h: remove unnecessary include
      treewide: add direct includes currently only pulled in transitively
      treewide: remove unnecessary includes in source files
      sparse-checkout: be consistent with end of options markers
      diffcore-delta: avoid ignoring final 'line' of file

Emir SARI (1):
      l10n: tr: Update Turkish translations for 2.44

Eric Sunshine (1):
      git-add.txt: add missing short option -A to synopsis

Ghanshyam Thakkar (4):
      t7501: add tests for --include and --only
      t7501: add tests for --amend --signoff
      t0024: avoid losing exit status to pipes
      t0024: style fix

Illia Bobyr (1):
      rebase: clarify --reschedule-failed-exec default

James Touton (1):
      git-p4: use raw string literals for regular expressions

Jean-Noël Avila (3):
      doc: enforce dashes in placeholders
      doc: enforce placeholders in documentation
      l10n: fr.po: v2.44.0 round 3

Jeff Hostetler (4):
      trace2: fix signature of trace2_def_param() macro
      t0211: test URL redacting in PERF format
      t0212: test URL redacting in EVENT format
      sparse-index: pass string length to index_file_exists()

Jeff King (39):
      commit-graph: handle overflow in chunk_size checks
      midx: check consistency of fanout table
      commit-graph: drop redundant call to "lite" verification
      commit-graph: clarify missing-chunk error messages
      commit-graph: abort as soon as we see a bogus chunk
      commit-graph: use fanout value for graph size
      commit-graph: check order while reading fanout chunk
      commit-graph: drop verify_commit_graph_lite()
      commit-graph: mark chunk error messages for translation
      parse-options: decouple "--end-of-options" and "--"
      bisect: always clean on reset
      config: handle NULL value when parsing non-bools
      setup: handle NULL value when parsing extensions
      trace2: handle NULL values in tr2_sysenv config callback
      help: handle NULL value for alias.* config
      submodule: handle NULL value when parsing submodule.*.branch
      trailer: handle NULL value when parsing trailer-specific config
      fsck: handle NULL value when parsing message config
      config: reject bogus values for core.checkstat
      git_xmerge_config(): prefer error() to die()
      imap-send: don't use git_die_config() inside callback
      config: use config_error_nonbool() instead of custom messages
      diff: give more detailed messages for bogus diff.* config
      config: use git_config_string() for core.checkRoundTripEncoding
      push: drop confusing configset/callback redundancy
      gpg-interface: drop pointless config_error_nonbool() checks
      sequencer: simplify away extra git_config_string() call
      mailinfo: fix out-of-bounds memory reads in unquote_quoted_pair()
      t5100: make rfc822 comment test more careful
      mailinfo: avoid recursion when unquoting From headers
      t1006: add tests for %(objectsize:disk)
      commit-graph: retain commit slab when closing NULL commit_graph
      index-pack: spawn threads atomically
      transport-helper: re-examine object dir after fetching
      diff: handle NULL meta-info when spawning external diff
      Makefile: use mkdir_p_parent_template for UNIT_TEST_BIN
      Makefile: remove UNIT_TEST_BIN directory with "make clean"
      t/Makefile: get UNIT_TESTS list from C sources
      trailer: fix comment/cut-line regression with opts->no_divider

Jiang Xin (14):
      t5574: test porcelain output of atomic fetch
      fetch: no redundant error message for atomic fetch
      test-pkt-line: add option parser for unpack-sideband
      pkt-line: memorize sideband fragment in reader
      pkt-line: do not chomp newlines for sideband messages
      transport-helper: no connection restriction in connect_helper
      remote-curl: supports git-upload-archive service
      transport-helper: protocol v2 supports upload-archive
      http-backend: new rpc-service for git-upload-archive
      transport-helper: call do_take_over() in connect_helper
      transport-helper: call do_take_over() in process_connect
      diff: mark param1 and param2 as placeholders
      l10n: ci: remove unused param for add-pr-comment@v2
      l10n: ci: disable cache for setup-go to suppress warnings

Joanna Wang (2):
      attr: enable attr pathspec magic for git-add and git-stash
      attr: add builtin objectmode values support

Johannes Schindelin (15):
      artifacts-tar: when including `.dll` files, don't forget the unit-tests
      cmake: fix typo in variable name
      cmake: also build unit tests
      cmake: use test names instead of full paths
      unit-tests: do not mistake `.pdb` files for being executable
      cmake: handle also unit tests
      unit-tests: do show relative file paths
      ci: avoid running the test suite _twice_
      packfile.c: fix a typo in `each_file_in_pack_dir_fn()`'s declaration
      trace2: redact passwords from https:// URLs by default
      win32: special-case `ENOSPC` when writing to a pipe
      Always check the return value of `repo_read_object_file()`
      l10n: bump Actions versions in l10n.yml
      ci: bump remaining outdated Actions versions
      ci(linux32): add a note about Actions that must not be updated

John Cai (15):
      t3210: move to t0601
      remove REFFILES prerequisite for some tests in t1405 and t2017
      t1414: convert test to use Git commands instead of writing refs manually
      t1404: move reffiles specific tests to t0600
      t1405: move reffiles specific tests to t0601
      t1406: move reffiles specific tests to t0600
      t1410: move reffiles specific tests to t0600
      t1415: move reffiles specific tests to t0601
      t1503: move reffiles specific tests to t0600
      t3903: make drop stash test ref backend agnostic
      t4202: move reffiles specific tests to t0600
      t5312: move reffiles specific tests to t0601
      reftable: honor core.fsync
      index-pack: test and document --strict=<msg-id>=<severity>...
      index-pack: --fsck-objects to take an optional argument for fsck msgs

Jordi Mas (1):
      l10n: Update Catalan translation

Josh Brobst (1):
      builtin/reflog.c: fix dry-run option short name

Josh Soref (13):
      doc: update links to current pages
      doc: switch links to https
      doc: update links for andre-simon.de
      doc: refer to internet archive
      CodingGuidelines: move period inside parentheses
      CodingGuidelines: write punctuation marks
      SubmittingPatches: drop ref to "What's in git.git"
      SubmittingPatches: discourage new trailers
      SubmittingPatches: update extra tags list
      SubmittingPatches: provide tag naming advice
      SubmittingPatches: clarify GitHub visual
      SubmittingPatches: clarify GitHub artifact format
      SubmittingPatches: hyphenate non-ASCII

Josh Steadmon (4):
      unit tests: add a project plan document
      ci: run unit tests in CI
      fuzz: fix fuzz test build rules
      ci: build and run minimal fuzzers in GitHub CI

Julian Prein (1):
      hooks--pre-commit: detect non-ASCII when renaming

Junio C Hamano (58):
      cache: add fake_lstat()
      diff-lib: fix check_removed() when fsmonitor is active
      checkout: refactor die_if_checked_out() caller
      orphan/unborn: add to the glossary and use them consistently
      orphan/unborn: fix use of 'orphan' in end-user facing messages
      revision: parse integer arguments to --max-count, --skip, etc., more carefully
      Start the 2.44 cycle
      checkout: forbid "-B <branch>" from touching a branch used elsewhere
      git.txt: HEAD is not that special
      git-bisect.txt: BISECT_HEAD is not that special
      refs.h: HEAD is not that special
      docs: AUTO_MERGE is not that special
      docs: MERGE_AUTOSTASH is not that special
      doc: format.notes specify a ref under refs/notes/ hierarchy
      The second batch
      remote.h: retire CAS_OPT_NAME
      The third batch
      archive: "--list" does not take further options
      sparse-checkout: use default patterns for 'set' only !stdin
      The fourth batch
      The fifth batch
      The sixth batch
      messages: mark some strings with "up-to-date" not to touch
      The seventh batch
      The eighth batch
      The ninth batch
      Docs: majordomo@vger.kernel.org has been decomissioned
      CoC: whitespace fix
      ls-files: avoid the verb "deprecate" for individual options
      The tenth batch
      builtin/worktree: comment style fixes
      merge-ort.c: comment style fix
      reftable/pq_test: comment style fix
      The eleventh batch
      t0091: allow test in a repository without tags
      The twelfth batch
      Makefile: reduce repetitive library paths
      Makefile: simplify output of the libpath_template
      The thirteenth batch
      GitHub Actions: update to checkout@v4
      GitHub Actions: update to github-script@v7
      t/Makefile: say the default target upfront
      The fourteenth batch
      tag: fix sign_buffer() call to create a signed tag
      bisect: document "terms" subcommand more fully
      bisect: document command line arguments for "bisect start"
      ssh signing: signal an error with a negative return value
      The fifteenth batch
      Git 2.43.1
      Git 2.44-rc0
      unit-tests: do show relative file paths on non-Windows, too
      A few more topics before -rc1
      write-or-die: fix the polarity of GIT_FLUSH environment variable
      A few more fixes before -rc1
      Git 2.43.2
      Hopefully the last batch of fixes before 2.44 final
      Git 2.44-rc2
      Git 2.43.3

Justin Tobler (2):
      t1401: remove lockfile creation
      t5541: remove lockfile creation

Kristoffer Haugsbakk (5):
      config: format newlines
      config: rename global config function
      config: factor out global config file retrieval
      maintenance: use XDG config if it exists
      config: add back code comment

Kyle Lippincott (1):
      setup: allow cwd=.git w/ bareRepository=explicit

Linus Arver (4):
      commit: ignore_non_trailer computes number of bytes to ignore
      trailer: find the end of the log message
      trailer: use offsets for trailer_start/trailer_end
      strvec: use correct member name in comments

M Hickford (1):
      credential/wincred: store oauth_refresh_token

Maarten van der Schrieck (1):
      Documentation: fix statement about rebase.instructionFormat

Marcel Krause (1):
      doc: make the gitfile syntax easier to discover

Marcelo Roberto Jimenez (1):
      gitweb: die when a configuration file cannot be read

Michael Lohmann (2):
      Documentation/git-merge.txt: fix reference to synopsis
      Documentation/git-merge.txt: use backticks for command wrapping

Nikolay Borisov (1):
      rebase: fix documentation about used shell in -x

Nikolay Edigaryev (1):
      rev-list-options: fix off-by-one in '--filter=blob:limit=<n>' explainer

Patrick Steinhardt (139):
      t: allow skipping expected object ID in `ref-store update-ref`
      t: convert tests to not write references via the filesystem
      t: convert tests to not access symrefs via the filesystem
      t: convert tests to not access reflog via the filesystem
      t1450: convert tests to remove worktrees via git-worktree(1)
      t4207: delete replace references via git-update-ref(1)
      t7300: assert exact states of repo
      t7900: assert the absence of refs via git-for-each-ref(1)
      t: mark several tests that assume the files backend with REFFILES
      ci: reorder definitions for grouping functions
      ci: make grouping setup more generic
      ci: group installation of Docker dependencies
      ci: split out logic to set up failed test artifacts
      ci: unify setup of some environment variables
      ci: squelch warnings when testing with unusable Git repo
      ci: install test dependencies for linux-musl
      ci: add support for GitLab CI
      t/lib-httpd: dynamically detect httpd and modules path
      t/lib-httpd: stop using legacy crypt(3) for authentication
      t9164: fix inability to find basename(1) in Subversion hooks
      global: convert trivial usages of `test <expr> -a/-o <expr>`
      contrib/subtree: stop using `-o` to test for number of args
      contrib/subtree: convert subtree type check to use case statement
      Makefile: stop using `test -o` when unlinking duplicate executables
      t5510: ensure that the packed-refs file needs locking
      refs/files: use transactions to delete references
      refs: deduplicate code to delete references
      refs: remove `delete_refs` callback from backends
      commit-graph: disable GIT_COMMIT_GRAPH_PARANOIA by default
      t0410: mark tests to require the reffiles backend
      t1400: split up generic reflog tests from the reffile-specific ones
      t1401: stop treating FETCH_HEAD as real reference
      t1410: use test-tool to create empty reflog
      t1417: make `reflog --updateref` tests backend agnostic
      t3310: stop checking for reference existence via `test -f`
      t4013: simplify magic parsing and drop "failure"
      t5401: speed up creation of many branches
      t5551: stop writing packed-refs directly
      t6301: write invalid object ID via `test-tool ref-store`
      reftable: wrap EXPECT macros in do/while
      reftable: handle interrupted reads
      reftable: handle interrupted writes
      reftable/stack: verify that `reftable_stack_add()` uses auto-compaction
      reftable/stack: perform auto-compaction with transactional interface
      reftable/stack: reuse buffers when reloading stack
      reftable/stack: fix stale lock when dying
      reftable/stack: fix use of unseeded randomness
      reftable/merged: reuse buffer to compute record keys
      reftable/block: introduce macro to initialize `struct block_iter`
      reftable/block: reuse buffer to compute record keys
      setup: extract function to create the refdb
      setup: allow skipping creation of the refdb
      remote-curl: rediscover repository when fetching refs
      builtin/clone: fix bundle URIs with mismatching object formats
      builtin/clone: set up sparse checkout later
      builtin/clone: skip reading HEAD when retrieving remote
      builtin/clone: create the refdb with the correct object format
      wt-status: read HEAD and ORIG_HEAD via the refdb
      refs: propagate errno when reading special refs fails
      refs: complete list of special refs
      bisect: consistently write BISECT_EXPECTED_REV via the refdb
      tests: adjust whitespace in chainlint expectations
      t: introduce DEFAULT_REPO_FORMAT prereq
      worktree: skip reading HEAD when repairing worktrees
      refs: refactor logic to look up storage backends
      setup: start tracking ref storage format
      setup: set repository's formats on init
      setup: introduce "extensions.refStorage" extension
      setup: introduce GIT_DEFAULT_REF_FORMAT envvar
      t: introduce GIT_TEST_DEFAULT_REF_FORMAT envvar
      builtin/rev-parse: introduce `--show-ref-format` flag
      builtin/init: introduce `--ref-format=` value flag
      builtin/clone: introduce `--ref-format=` value flag
      t9500: write "extensions.refstorage" into config
      reftable/stack: do not overwrite errors when compacting
      reftable/stack: do not auto-compact twice in `reftable_stack_add()`
      reftable/writer: fix index corruption when writing multiple indices
      reftable/record: constify some parts of the interface
      reftable/record: store "val1" hashes as static arrays
      reftable/record: store "val2" hashes as static arrays
      reftable/merged: really reuse buffers to compute record keys
      reftable/merged: transfer ownership of records when iterating
      git-prompt: stop manually parsing HEAD with unknown ref formats
      ci: add job performing static analysis on GitLab CI
      refs: prepare `refs_init_db()` for initializing worktree refs
      setup: move creation of "refs/" into the files backend
      refs/files: skip creation of "refs/{heads,tags}" for worktrees
      builtin/worktree: move setup of commondir file earlier
      worktree: expose interface to look up worktree by name
      builtin/worktree: create refdb via ref backend
      reftable/stack: refactor stack reloading to have common exit path
      reftable/stack: refactor reloading to use file descriptor
      reftable/stack: use stat info to avoid re-reading stack list
      reftable/blocksource: refactor code to match our coding style
      reftable/blocksource: use mmap to read tables
      git-p4: stop reaching into the refdb
      commit-graph: fix memory leak when not writing graph
      completion: discover repo path in `__git_pseudoref_exists ()`
      t9902: verify that completion does not print anything
      completion: improve existence check for pseudo-refs
      completion: silence pseudoref existence check
      completion: treat dangling symrefs as existing pseudorefs
      t7527: decrease likelihood of racing with fsmonitor daemon
      Makefile: detect new Homebrew location for ARM-based Macs
      ci: handle TEST_OUTPUT_DIRECTORY when printing test failures
      ci: make p4 setup on macOS more robust
      ci: add macOS jobs to GitLab CI
      reftable/stack: unconditionally reload stack after commit
      reftable/stack: fix race in up-to-date check
      sequencer: clean up pseudo refs with REF_NO_DEREF
      sequencer: delete REBASE_HEAD in correct repo when picking commits
      refs: convert AUTO_MERGE to become a normal pseudo-ref
      sequencer: introduce functions to handle autostashes via refs
      refs: convert MERGE_AUTOSTASH to become a normal pseudo-ref
      refs: redefine special refs
      Documentation: add "special refs" to the glossary
      reftable/stack: adjust permissions of compacted tables
      t1300: make tests more robust with non-default ref backends
      t1301: mark test for `core.sharedRepository` as reffiles specific
      t1302: make tests more robust with new extensions
      t1419: mark test suite as files-backend specific
      t5526: break test submodule differently
      t: mark tests regarding git-pack-refs(1) to be backend specific
      reftable/stack: fsync "tables.list" during compaction
      reftable/reader: be more careful about errors in indexed seeks
      reftable/writer: use correct type to iterate through index entries
      reftable/writer: simplify writing index records
      reftable/writer: fix writing multi-level indices
      reftable: document reading and writing indices
      builtin/stash: report failure to write to index
      reftable: introduce macros to grow arrays
      reftable: introduce macros to allocate arrays
      reftable/stack: fix parameter validation when compacting range
      reftable/stack: index segments with `size_t`
      reftable/stack: use `size_t` to track stack slices during compaction
      reftable/stack: use `size_t` to track stack length
      reftable/merged: refactor seeking of records
      reftable/merged: refactor initialization of iterators
      reftable/record: improve semantics when initializing records

Peter Krefting (1):
      l10n: sv.po: Update Swedish translation

Philippe Blain (11):
      completion: complete missing rev-list options
      completion: complete --patch-with-raw
      completion: complete --encoding
      completion: complete missing 'git log' options
      ci(github): also skip logs of broken test cases
      imap-send: add missing "strbuf.h" include under NO_CURL
      .github/PULL_REQUEST_TEMPLATE.md: add a note about single-commit PRs
      completion: add space after config variable names also in Bash 3
      completion: complete 'submodule.*' config variables
      completion: add and use __git_compute_first_level_config_vars_for_section
      completion: add and use __git_compute_second_level_config_vars_for_section

Phillip Wood (4):
      unit tests: add TAP unit test framework
      show-ref --verify: accept pseudorefs
      t1400: use show-ref to check pseudorefs
      prune: mark rebase autostash and orig-head as reachable

Ralf Thielow (1):
      l10n: Update German translation

René Scharfe (21):
      column: release strbuf and string_list after use
      i18n: factorize even more 'incompatible options' messages
      push: use die_for_incompatible_opt4() for - -delete/--tags/--all/--mirror
      repack: use die_for_incompatible_opt3() for -A/-k/--cruft
      revision: use die_for_incompatible_opt3() for - -graph/--reverse/--walk-reflogs
      revision, rev-parse: factorize incompatibility messages about - -exclude-hidden
      clean: factorize incompatibility message
      worktree: standardize incompatibility messages
      worktree: simplify incompatibility message for --orphan and commit-ish
      show-ref: use die_for_incompatible_opt3()
      t6300: avoid hard-coding object sizes
      git-compat-util: convert skip_{prefix,suffix}{,_mem} to bool
      rebase: use strvec_pushf() for format-patch revisions
      fast-import: use mem_pool_calloc()
      mem-pool: fix big allocations
      mem-pool: simplify alignment calculation
      t1006: prefer shell loop to awk for packed object sizes
      parse-options: fully disable option abbreviation with PARSE_OPT_KEEP_UNKNOWN
      parse-options: simplify positivation handling
      receive-pack: use find_commit_header() in check_cert_push_options()
      receive-pack: use find_commit_header() in check_nonce()

Rubén Justo (10):
      status: fix branch shown when not only bisecting
      branch: clarify <oldbranch> term
      advice: sort the advice related lists
      advice: fix an unexpected leading space
      branch: make the advice to force-deleting a conditional one
      advice: allow disabling the automatic hint in advise_if_enabled()
      t5332: mark as leak-free
      t6113: mark as leak-free
      test-lib: check for TEST_PASSES_SANITIZE_LEAK
      t0080: mark as leak-free

Sam Delmerico (1):
      push: region_leave trace for negotiate_using_fetch

Shreyansh Paliwal (1):
      test-lib-functions.sh: fix test_grep fail message wording

Simon Ser (1):
      format-patch: fix ignored encode_email_headers for cover letter

Stan Hu (2):
      completion: refactor existence checks for pseudorefs
      completion: support pseudoref existence checks for reftables

Sören Krecker (1):
      mingw: give more details about unsafe directory's ownership

Tamino Bauknecht (1):
      fetch: add new config option fetch.all

Taylor Blau (29):
      pack-objects: free packing_data in more places
      pack-bitmap-write: deep-clear the `bb_commit` slab
      pack-bitmap: plug leak in find_objects()
      midx: factor out `fill_pack_info()`
      midx: implement `BTMP` chunk
      midx: implement `midx_locate_pack()`
      pack-bitmap: pass `bitmapped_pack` struct to pack-reuse functions
      ewah: implement `bitmap_is_empty()`
      pack-bitmap: simplify `reuse_partial_packfile_from_bitmap()` signature
      pack-bitmap: return multiple packs via `reuse_partial_packfile_from_bitmap()`
      pack-objects: parameterize pack-reuse routines over a single pack
      pack-objects: keep track of `pack_start` for each reuse pack
      pack-objects: pass `bitmapped_pack`'s to pack-reuse functions
      pack-objects: prepare `write_reused_pack()` for multi-pack reuse
      pack-objects: prepare `write_reused_pack_verbatim()` for multi-pack reuse
      pack-objects: include number of packs reused in output
      git-compat-util.h: implement checked size_t to uint32_t conversion
      midx: implement `midx_preferred_pack()`
      pack-revindex: factor out `midx_key_to_pack_pos()` helper
      pack-revindex: implement `midx_pair_to_pack_pos()`
      pack-bitmap: prepare to mark objects from multiple packs for reuse
      pack-objects: add tracing for various packfile metrics
      t/test-lib-functions.sh: implement `test_trace2_data` helper
      pack-objects: allow setting `pack.allowPackReuse` to "single"
      pack-bitmap: enable reuse from all bitmapped packs
      t/perf: add performance tests for multi-pack reuse
      pack-bitmap: drop unused `reuse_objects`
      t5332-multi-pack-reuse.sh: extract pack-objects helper functions
      pack-objects: enable multi-pack reuse via `feature.experimental`

Teng Long (1):
      l10n: zh_CN: for git 2.44 rounds

Todd Zullinger (3):
      perl: bump the required Perl version to 5.8.1 from 5.8.0
      send-email: avoid duplicate specification warnings
      RelNotes: minor typo fixes in 2.44.0 draft

Toon Claes (1):
      builtin/show-ref: treat directory as non-existing in --exists

Vegard Nossum (1):
      sequencer: unset GIT_CHERRY_PICK_HELP for 'exec' commands

Victoria Dye (15):
      ref-filter.c: really don't sort when using --no-sort
      ref-filter.h: add max_count and omit_empty to ref_format
      ref-filter.h: move contains caches into filter
      ref-filter.h: add functions for filter/format & format-only
      ref-filter.c: rename 'ref_filter_handler()' to 'filter_one()'
      ref-filter.c: refactor to create common helper functions
      ref-filter.c: filter & format refs in the same callback
      for-each-ref: clean up documentation of --format
      ref-filter.c: use peeled tag for '*' format fields
      t/perf: add perf tests for for-each-ref
      submodule-config.h: move check_submodule_url
      test-submodule: remove command line handling for check-name
      t7450: test submodule urls
      submodule-config.c: strengthen URL fsck check
      ref-filter.c: sort formatted dates by byte value

Yi-Jyun Pan (1):
      l10n: zh_TW: Git 2.44

Zach FettersMoore (1):
      subtree: fix split processing with multiple subtrees present


^ permalink raw reply

* [ANNOUNCE] Git v2.43.3
From: Junio C Hamano @ 2024-02-23 17:16 UTC (permalink / raw)
  To: git; +Cc: Linux Kernel, git-packagers

The latest maintenance release Git v2.43.3 is now available at
the usual places.

This is to fix another regression in previous 2.43.x release that
were not in 2.43.0 and 2.43.2 did not address.

The tarballs are found at:

    https://www.kernel.org/pub/software/scm/git/

The following public repositories all have a copy of the 'v2.43.3'
tag and the 'maint' branch that the tag points at:

  url = https://git.kernel.org/pub/scm/git/git
  url = https://kernel.googlesource.com/pub/scm/git/git
  url = git://repo.or.cz/alt-git.git
  url = https://github.com/gitster/git

----------------------------------------------------------------

Git 2.43.3 Release Notes
========================

Relative to Git 2.43.2, this release fixes one regression that
manifests while running "git commit -v --trailer".

Fixes since Git 2.43.2
----------------------

 * "git commit -v --trailer=..." was broken with recent update and
   placed the trailer _after_ the divider line, which has been
   corrected.

----------------------------------------------------------------

Changes since v2.43.2 are as follows:

Jeff King (1):
      trailer: fix comment/cut-line regression with opts->no_divider

Junio C Hamano (1):
      Git 2.43.3


^ permalink raw reply

* What's cooking in git.git (Feb 2024, #08; Thu, 22)
From: Junio C Hamano @ 2024-02-23 17:16 UTC (permalink / raw)
  To: git

Here are the topics that have been cooking in my tree.  Commits
prefixed with '+' are in 'next' (being in 'next' is a sign that a
topic is stable enough to be used and are candidate to be in a
future release).  Commits prefixed with '-' are only in 'seen', and
aren't considered "accepted" at all and may be annotated with an URL
to a message that raises issues but they are no means exhaustive.  A
topic without enough support may be discarded after a long period of
no activity (of course they can be resubmit when new interests
arise).

Git 2.44 has been tagged, after fixing a last minute regression.
Git 2.43.3 also has been tagged for the same fix.

Copies of the source code to Git live in many repositories, and the
following is a list of the ones I push into or their mirrors.  Some
repositories have only a subset of branches.

With maint, master, next, seen, todo:

	git://git.kernel.org/pub/scm/git/git.git/
	git://repo.or.cz/alt-git.git/
	https://kernel.googlesource.com/pub/scm/git/git/
	https://github.com/git/git/
	https://gitlab.com/git-vcs/git/

With all the integration branches and topics broken out:

	https://github.com/gitster/git/

Even though the preformatted documentation in HTML and man format
are not sources, they are published in these repositories for
convenience (replace "htmldocs" with "manpages" for the manual
pages):

	git://git.kernel.org/pub/scm/git/git-htmldocs.git/
	https://github.com/gitster/git-htmldocs.git/

Release tarballs are available at:

	https://www.kernel.org/pub/software/scm/git/

--------------------------------------------------
[New Topics]

* ps/difftool-dir-diff-exit-code (2024-02-20) 1 commit
  (merged to 'next' on 2024-02-21 at a7bbef5a5f)
 + git-difftool--helper: honor `--trust-exit-code` with `--dir-diff`

 "git difftool --dir-diff" learned to honor the "--trust-exit-code"
 option; it used to always exit with 0 and signalled success.

 Will cook in 'next'.
 source: <0fac668f8fc021af9f9c4df5134da59816307ccc.1708423309.git.ps@pks.im>


* ds/doc-send-email-capitalization (2024-02-20) 1 commit
  (merged to 'next' on 2024-02-21 at c4aac4b993)
 + documentation: send-email: use camel case consistently

 Doc update.

 Will cook in 'next'.
 source: <88f1fe08c3047e14090957093ee8d98b0f60cb6c.1708467601.git.dsimic@manjaro.org>


* ja/docfixes (2024-02-20) 3 commits
  (merged to 'next' on 2024-02-21 at 6d778ca672)
 + doc: end sentences with full-stop
 + doc: close unclosed angle-bracket of a placeholder in git-clone doc
 + doc: git-rev-parse: enforce command-line description syntax

 Doc update.

 Will cook in 'next'.
 source: <pull.1670.git.1708468374.gitgitgadget@gmail.com>


* hs/rebase-not-in-progress (2024-02-21) 1 commit
 - rebase: make warning less passive aggressive

 Error message update.

 Will merge to 'next'.
 source: <pull.1669.v2.git.1708537097448.gitgitgadget@gmail.com>


* jw/remote-doc-typofix (2024-02-21) 1 commit
 - git-remote.txt: fix typo

 Docfix.

 Will merge to 'next'.
 source: <20240221083554.5255-1-jwilk@jwilk.net>


* ja/doc-placeholders-markup-rules (2024-02-21) 1 commit
 - doc: clarify the format of placeholders

 The way placeholders are to be marked-up in documentation have been
 specified; use "_<placeholder>_" to typeset the word inside a pair
 of <angle-brakets> emphasized.

 Will merge to 'next'.
 source: <pull.1671.git.1708550340094.gitgitgadget@gmail.com>


* jc/doc-add-placeholder-fix (2024-02-21) 1 commit
 - doc: apply the new placeholder rules to git-add documentation

 Practice the new mark-up rule for <placeholders> with "git add"
 documentation page.

 Will merge to 'next'.
 source: <xmqqbk89molz.fsf@gitster.g>

--------------------------------------------------
[Cooking]

* as/option-names-in-messages (2024-02-16) 5 commits
 - revision.c: trivial fix to message
 - builtin/clone.c: trivial fix of message
 - builtin/remote.c: trivial fix of error message
 - transport-helper.c: trivial fix of error message
 - rebase: trivial fix of error message

 Error message updates.

 Expecting a reroll.
 source: <20240216101647.28837-1-ash@kambanaria.org>


* bb/completion-no-grep-into-awk (2024-02-16) 1 commit
  (merged to 'next' on 2024-02-19 at 8373f95424)
 + completion: use awk for filtering the config entries

 Some parts of command line completion script (in contrib/) have
 been micro-optimized.

 Will cook in 'next'.
 source: <20240216171046.927552-1-dev+git@drbeat.li>


* jb/doc-interactive-singlekey-do-not-need-perl (2024-02-19) 1 commit
  (merged to 'next' on 2024-02-19 at 9eda75497d)
 + doc: remove outdated information about interactive.singleKey

 Doc clean-up.

 Will cook in 'next'.
 source: <20240218030327.40453-1-julio.bacel@gmail.com>


* jk/t0303-clean (2024-02-19) 2 commits
  (merged to 'next' on 2024-02-19 at f57b65215f)
 + t0303: check that helper_test_clean removes all credentials
 + Merge branch 'ba/credential-test-clean-fix' into jk/t0303-clean
 (this branch uses ba/credential-test-clean-fix.)

 Test clean-up.

 Will cook in 'next'.
 source: <20240217045814.GA539459@coredump.intra.peff.net>


* km/mergetool-vimdiff-layout-fallback (2024-02-19) 1 commit
  (merged to 'next' on 2024-02-19 at bf7f086f05)
 + mergetools: vimdiff: use correct tool's name when reading mergetool config

 Variants of vimdiff learned to honor mergetool.<variant>.layout settings.

 Will cook in 'next'.
 source: <20240217162718.21272-1-kipras@kipras.org>


* mh/libsecret-empty-password-fix (2024-02-19) 1 commit
  (merged to 'next' on 2024-02-19 at b2e17695ca)
 + libsecret: retrieve empty password

 Credential helper based on libsecret (in contrib/) has been updated.

 Will cook in 'next'.
 source: <pull.1676.v2.git.git.1708375258296.gitgitgadget@gmail.com>


* ps/reflog-list (2024-02-21) 9 commits
 - builtin/reflog: introduce subcommand to list reflogs
 - refs: stop resolving ref corresponding to reflogs
 - refs: drop unused params from the reflog iterator callback
 - refs: always treat iterators as ordered
 - refs/files: sort merged worktree and common reflogs
 - refs/files: sort reflogs returned by the reflog iterator
 - dir-iterator: support iteration in sorted order
 - dir-iterator: pass name to `prepare_next_entry_data()` directly
 + Merge branch 'ps/reftable-backend' into ps/reflog-list
 (this branch uses ps/reftable-backend.)

 "git reflog" learned a "list" subcommand that enumerates known reflogs.

 Will merge to 'next'.
 source: <cover.1708518982.git.ps@pks.im>


* jh/fsmonitor-icase-corner-case-fix (2024-02-14) 11 commits
 - t7527: update case-insenstive fsmonitor test
 - fsmonitor: refactor bit invalidation in refresh callback
 - fsmonitor: support case-insensitive non-directory events
 - fsmonitor: refactor non-directory callback
 - fsmonitor: support case-insensitive directory events
 - fsmonitor: refactor untracked-cache invalidation
 - fsmonitor: clarify handling of directory events in callback
 - fsmonitor: refactor refresh callback for non-directory events
 - fsmonitor: refactor refresh callback on directory events
 - t7527: add case-insensitve test for FSMonitor
 - name-hash: add index_dir_exists2()

 FSMonitor client code was confused when FSEvents were given in a
 different case on a case-insensitive filesystem, which has been
 corrected.

 Needs review.
 source: <pull.1662.git.1707857541.gitgitgadget@gmail.com>


* mh/credential-oauth-refresh-token-with-osxkeychain (2024-02-14) 1 commit
 - credential/osxkeychain: store new attributes

 OAuth refresh tokens and password expiry timestamps are now stored
 in the osxkeychain backend , just the way libsecret and wincred
 backends of the credential subsystem do.

 Needs testing.
 cf. <CAGJzqsmSzMqEG1OU9dH6CORV6=L7qUAFNJSmi41Lqrajf9mSew@mail.gmail.com>
 source: <pull.1663.git.1707860618119.gitgitgadget@gmail.com>


* ps/reftable-iteration-perf-part2 (2024-02-14) 13 commits
 - reftable: allow inlining of a few functions
 - reftable/record: decode keys in place
 - reftable/record: reuse refname when copying
 - reftable/record: reuse refname when decoding
 - reftable/merged: avoid duplicate pqueue emptiness check
 - reftable/merged: circumvent pqueue with single subiter
 - reftable/merged: handle subiter cleanup on close only
 - reftable/merged: remove unnecessary null check for subiters
 - reftable/merged: make subiters own their records
 - reftable/merged: advance subiter on subsequent iteration
 - reftable/merged: make `merged_iter` structure private
 - reftable/pq: use `size_t` to track iterator index
 - Merge branch 'ps/reftable-iteration-perf' into ps/reftable-iteration-perf-part2
 (this branch uses ps/reftable-iteration-perf.)

 The code to iterate over refs with the reftable backend has seen
 some optimization.

 Needs review.
 source: <cover.1707895758.git.ps@pks.im>


* cp/t9146-use-test-path-helpers (2024-02-14) 1 commit
  (merged to 'next' on 2024-02-21 at 0b8356ef33)
 + t9146: replace test -d/-e/-f with appropriate test_path_is_* function

 Test script clean-up.

 Will cook in 'next'.
 source: <pull.1661.v3.git.1707933048210.gitgitgadget@gmail.com>


* rj/tag-column-fix (2024-02-14) 1 commit
  (merged to 'next' on 2024-02-19 at 9aa52b4ffb)
 + tag: error when git-column fails

 "git tag --column" failed to check the exit status of its "git
 column" invocation, which has been corrected.

 Will cook in 'next'.
 source: <59df085d-0de8-45b1-9b8b-c69e91e56a1f@gmail.com>


* jc/am-whitespace-doc (2024-02-14) 1 commit
  (merged to 'next' on 2024-02-19 at 492f0f9174)
 + doc: add shortcut to "am --whitespace=<action>"

 "git am --help" now tells readers what actions are available in
 "git am --whitespace=<action>", in addition to saying that the
 option is passed through to the underlying "git apply".

 Will cook in 'next'.
 source: <xmqqplwyvqby.fsf@gitster.g>


* ba/credential-test-clean-fix (2024-02-15) 1 commit
  (merged to 'next' on 2024-02-19 at 290708b10a)
 + t/lib-credential: clean additional credential
 (this branch is used by jk/t0303-clean.)

 Test clean-up.

 Will cook in 'next'.
 source: <pull.1664.git.1707959036807.gitgitgadget@gmail.com>


* js/cmake-with-test-tool (2024-02-15) 1 commit
 - cmake: let `test-tool` run the unit tests, too
 (this branch uses js/unit-test-suite-runner.)

 "test-tool" is now built in CMake build to also run the unit tests.

 May want to roll it into the base topic.
 source: <cover.1706921262.git.steadmon@google.com>


* ps/ref-tests-update-even-more (2024-02-15) 7 commits
  (merged to 'next' on 2024-02-15 at 064b2b4089)
 + t7003: ensure filter-branch prunes reflogs with the reftable backend
 + t2011: exercise D/F conflicts with HEAD with the reftable backend
 + t1405: remove unneeded cleanup step
 + t1404: make D/F conflict tests compatible with reftable backend
 + t1400: exercise reflog with gaps with reftable backend
 + t0410: convert tests to use DEFAULT_REPO_FORMAT prereq
 + t: move tests exercising the "files" backend

 More tests that are marked as "ref-files only" have been updated to
 improve test coverage of reftable backend.

 Will cook in 'next'.
 source: <cover.1707985173.git.ps@pks.im>


* rs/use-xstrncmpz (2024-02-12) 1 commit
  (merged to 'next' on 2024-02-12 at 37e5f0fc14)
 + use xstrncmpz()

 Code clean-up.

 Will cook in 'next'.
 source: <954b75d0-1504-4f57-b34e-e770a4b7b3ea@web.de>


* kn/for-all-refs (2024-02-12) 6 commits
 - for-each-ref: add new option to include root refs
 - ref-filter: rename 'FILTER_REFS_ALL' to 'FILTER_REFS_REGULAR'
 - refs: introduce `refs_for_each_include_root_refs()`
 - refs: extract out `loose_fill_ref_dir_regular_file()`
 - refs: introduce `is_pseudoref()` and `is_headref()`
 - Merge branch 'ps/reftable-backend' into kn/for-all-refs
 (this branch uses ps/reftable-backend.)

 "git for-each-ref" filters its output with prefixes given from the
 command line, but it did not honor an empty string to mean "pass
 everything", which has been corrected.

 Expecting a reroll?
 source: <20240211183923.131278-1-karthik.188@gmail.com>


* kh/column-reject-negative-padding (2024-02-13) 2 commits
  (merged to 'next' on 2024-02-14 at c30c08e495)
 + column: guard against negative padding
 + column: disallow negative padding

 "git column" has been taught to reject negative padding value, as
 it would lead to nonsense behaviour including division by zero.

 Will cook in 'next'.
 source: <cover.1707839454.git.code@khaugsbakk.name>


* jc/no-lazy-fetch (2024-02-16) 3 commits
 - git: extend --no-lazy-fetch to work across subprocesses
 - git: document GIT_NO_REPLACE_OBJECTS environment variable
  (merged to 'next' on 2024-02-13 at 7c7136e547)
 + git: --no-lazy-fetch option

 "git --no-lazy-fetch cmd" allows to run "cmd" while disabling lazy
 fetching of objects from the promisor remote, which may be handy
 for debugging.
 source: <xmqq1q9mmtpw.fsf@gitster.g>
 source: <xmqqv86pslos.fsf@gitster.g>


* jc/t9210-lazy-fix (2024-02-08) 1 commit
  (merged to 'next' on 2024-02-13 at fb61ca2fba)
 + t9210: do not rely on lazy fetching to fail
 (this branch is used by cc/rev-list-allow-missing-tips.)

 Adjust use of "rev-list --missing" in an existing tests so that it
 does not depend on a buggy failure mode.

 Will cook in 'next'.
 source: <xmqq7cjemttr.fsf@gitster.g>


* gt/at-is-synonym-for-head-in-add-patch (2024-02-13) 2 commits
  (merged to 'next' on 2024-02-14 at cd901555d6)
 + add -p tests: remove PERL prerequisites
 + add-patch: classify '@' as a synonym for 'HEAD'

 Teach "git checkout -p" and friends that "@" is a synonym for
 "HEAD".

 Will cook in 'next'.
 source: <20240211202035.7196-2-shyamthakkar001@gmail.com>


* js/unit-test-suite-runner (2024-02-03) 7 commits
 - t/Makefile: run unit tests alongside shell tests
 - unit tests: add rule for running with test-tool
 - test-tool run-command testsuite: support unit tests
 - test-tool run-command testsuite: remove hardcoded filter
 - test-tool run-command testsuite: get shell from env
 - t0080: turn t-basic unit test into a helper
 - Merge branch 'jk/unit-tests-buildfix' into js/unit-test-suite-runner
 (this branch is used by js/cmake-with-test-tool.)

 The "test-tool" has been taught to run testsuite tests in parallel,
 bypassing the need to use the "prove" tool.

 Expecting a reroll.
 cf. <20240207225802.GA538110@coredump.intra.peff.net>
 source: <cover.1706921262.git.steadmon@google.com>


* ps/reftable-backend (2024-02-07) 3 commits
  (merged to 'next' on 2024-02-08 at ba1c4c52bb)
 + refs/reftable: fix leak when copying reflog fails
  (merged to 'next' on 2024-02-07 at 1115200acb)
 + ci: add jobs to test with the reftable backend
 + refs: introduce reftable backend
 (this branch is used by kn/for-all-refs and ps/reflog-list.)

 Integrate the reftable code into the refs framework as a backend.

 Will cook in 'next'.
 source: <cover.1707288261.git.ps@pks.im>


* cc/rev-list-allow-missing-tips (2024-02-14) 4 commits
  (merged to 'next' on 2024-02-21 at 9b63eec23f)
 + rev-list: allow missing tips with --missing=[print|allow*]
 + t6022: fix 'test' style and 'even though' typo
 + oidset: refactor oidset_insert_from_set()
 + revision: clarify a 'return NULL' in get_reference()
 (this branch uses jc/t9210-lazy-fix.)

 "git rev-list --missing=print" has learned to optionally take
 "--allow-missing-tips", which allows the objects at the starting
 points to be missing.

 Will cook in 'next'.
 source: <20240214142513.4002639-1-christian.couder@gmail.com>


* ps/reftable-iteration-perf (2024-02-12) 7 commits
  (merged to 'next' on 2024-02-12 at 6abaf58383)
 + reftable/reader: add comments to `table_iter_next()`
 + reftable/record: don't try to reallocate ref record name
 + reftable/block: swap buffers instead of copying
 + reftable/pq: allocation-less comparison of entry keys
 + reftable/merged: skip comparison for records of the same subiter
 + reftable/merged: allocation-less dropping of shadowed records
 + reftable/record: introduce function to compare records by key
 (this branch is used by ps/reftable-iteration-perf-part2.)

 The code to iterate over refs with the reftable backend has seen
 some optimization.

 Will cook in 'next'.
 source: <cover.1707726654.git.ps@pks.im>


* js/merge-tree-3-trees (2024-02-22) 6 commits
 - cache-tree: avoid an unnecessary check
 - Always check `parse_tree*()`'s return value
 - t4301: verify that merge-tree fails on missing blob objects
 - merge-ort: do check `parse_tree()`'s return value
 - merge-tree: fail with a non-zero exit code on missing tree objects
  (merged to 'next' on 2024-01-30 at 0c77b04e59)
 + merge-tree: accept 3 trees as arguments

 "git merge-tree" has learned that the three trees involved in the
 3-way merge only need to be trees, not necessarily commits.

 Comments?
 source: <pull.1647.git.1706277694231.gitgitgadget@gmail.com>
 source: <pull.1651.v3.git.1708612605.gitgitgadget@gmail.com>


* rj/complete-reflog (2024-01-26) 4 commits
 - completion: reflog show <log-options>
 - completion: reflog with implicit "show"
 - completion: introduce __git_find_subcommand
 - completion: introduce __gitcomp_subcommand

 The command line completion script (in contrib/) learned to
 complete "git reflog" better.

 Expecting a reroll.
 cf. <dd106d87-3363-426a-90a2-16e1f2d04661@gmail.com>
 source: <98daf977-dbad-4d3b-a293-6a769895088f@gmail.com>


* ml/log-merge-with-cherry-pick-and-other-pseudo-heads (2024-02-12) 2 commits
 - revision: implement `git log --merge` also for rebase/cherry-pick/revert
 - revision: ensure MERGE_HEAD is a ref in prepare_show_merge

 "git log --merge" learned to pay attention to CHERRY_PICK_HEAD and
 other kinds of *_HEAD pseudorefs.

 Expecting a reroll.
 cf. <790a3f11-5a8c-42f2-7a35-f2900c0299b4@gmail.com>
 cf. <8384d1dc-b6c4-b853-9bf6-3d7ccee86d12@gmail.com>
 source: <20240210-ml-log-merge-with-cherry-pick-and-other-pseudo-heads-v4-0-3bc9e62808f4@gmail.com>


* bk/complete-dirname-for-am-and-format-patch (2024-01-12) 1 commit
 - completion: dir-type optargs for am, format-patch

 Command line completion support (in contrib/) has been
 updated for a few commands to complete directory names where a
 directory name is expected.

 Expecting a reroll.
 cf. <40c3a824-a961-490b-94d4-4eb23c8f713d@gmail.com>
 source: <d37781c3-6af2-409b-95a8-660a9b92d20b@smtp-relay.sendinblue.com>


* bk/complete-send-email (2024-01-12) 1 commit
 - completion: don't complete revs when --no-format-patch

 Command line completion support (in contrib/) has been taught to
 avoid offering revision names as candidates to "git send-email" when
 the command is used to send pre-generated files.

 Expecting a reroll.
 cf. <CAC4O8c88Z3ZqxH2VVaNPpEGB3moL5dJcg3cOWuLWwQ_hLrJMtA@mail.gmail.com>
 source: <a718b5ee-afb0-44bd-a299-3208fac43506@smtp-relay.sendinblue.com>


* la/trailer-api (2024-02-16) 9 commits
  (merged to 'next' on 2024-02-21 at 631e28bbbc)
 + format_trailers_from_commit(): indirectly call trailer_info_get()
 + format_trailer_info(): move "fast path" to caller
 + format_trailers(): use strbuf instead of FILE
 + trailer_info_get(): reorder parameters
 + trailer: start preparing for formatting unification
 + trailer: move interpret_trailers() to interpret-trailers.c
 + trailer: prepare to expose functions as part of API
 + shortlog: add test for de-duplicating folded trailers
 + trailer: free trailer_info _after_ all related usage

 Code clean-up.

 Will cook in 'next'.
 source: <pull.1632.v5.git.1708124950.gitgitgadget@gmail.com>


* cp/apply-core-filemode (2023-12-26) 3 commits
  (merged to 'next' on 2024-02-07 at 089a3fbb86)
 + apply: code simplification
 + apply: correctly reverse patch's pre- and post-image mode bits
 + apply: ignore working tree filemode when !core.filemode

 "git apply" on a filesystem without filemode support have learned
 to take a hint from what is in the index for the path, even when
 not working with the "--index" or "--cached" option, when checking
 the executable bit match what is required by the preimage in the
 patch.

 Will cook in 'next'.
 cf. <xmqqzfwb53a9.fsf@gitster.g>
 source: <20231226233218.472054-1-gitster@pobox.com>


* tb/path-filter-fix (2024-01-31) 16 commits
 - bloom: introduce `deinit_bloom_filters()`
 - commit-graph: reuse existing Bloom filters where possible
 - object.h: fix mis-aligned flag bits table
 - commit-graph: new Bloom filter version that fixes murmur3
 - commit-graph: unconditionally load Bloom filters
 - bloom: prepare to discard incompatible Bloom filters
 - bloom: annotate filters with hash version
 - repo-settings: introduce commitgraph.changedPathsVersion
 - t4216: test changed path filters with high bit paths
 - t/helper/test-read-graph: implement `bloom-filters` mode
 - bloom.h: make `load_bloom_filter_from_graph()` public
 - t/helper/test-read-graph.c: extract `dump_graph_info()`
 - gitformat-commit-graph: describe version 2 of BDAT
 - commit-graph: ensure Bloom filters are read with consistent settings
 - revision.c: consult Bloom filters for root commits
 - t/t4216-log-bloom.sh: harden `test_bloom_filters_not_used()`

 The Bloom filter used for path limited history traversal was broken
 on systems whose "char" is unsigned; update the implementation and
 bump the format version to 2.

 Waiting for a final ack?
 cf. <ZcFjkfbsBfk7JQIH@nand.local>
 source: <cover.1706741516.git.me@ttaylorr.com>


* eb/hash-transition (2023-10-02) 30 commits
 - t1016-compatObjectFormat: add tests to verify the conversion between objects
 - t1006: test oid compatibility with cat-file
 - t1006: rename sha1 to oid
 - test-lib: compute the compatibility hash so tests may use it
 - builtin/ls-tree: let the oid determine the output algorithm
 - object-file: handle compat objects in check_object_signature
 - tree-walk: init_tree_desc take an oid to get the hash algorithm
 - builtin/cat-file: let the oid determine the output algorithm
 - rev-parse: add an --output-object-format parameter
 - repository: implement extensions.compatObjectFormat
 - object-file: update object_info_extended to reencode objects
 - object-file-convert: convert commits that embed signed tags
 - object-file-convert: convert commit objects when writing
 - object-file-convert: don't leak when converting tag objects
 - object-file-convert: convert tag objects when writing
 - object-file-convert: add a function to convert trees between algorithms
 - object: factor out parse_mode out of fast-import and tree-walk into in object.h
 - cache: add a function to read an OID of a specific algorithm
 - tag: sign both hashes
 - commit: export add_header_signature to support handling signatures on tags
 - commit: convert mergetag before computing the signature of a commit
 - commit: write commits for both hashes
 - object-file: add a compat_oid_in parameter to write_object_file_flags
 - object-file: update the loose object map when writing loose objects
 - loose: compatibilty short name support
 - loose: add a mapping between SHA-1 and SHA-256 for loose objects
 - repository: add a compatibility hash algorithm
 - object-names: support input of oids in any supported hash
 - oid-array: teach oid-array to handle multiple kinds of oids
 - object-file-convert: stubs for converting from one object format to another

 Teach a repository to work with both SHA-1 and SHA-256 hash algorithms.

 Will merge to and cook in 'next'?
 cf. <xmqqv86z5359.fsf@gitster.g>
 source: <878r8l929e.fsf@gmail.froward.int.ebiederm.org>


* jc/rerere-cleanup (2023-08-25) 4 commits
 - rerere: modernize use of empty strbuf
 - rerere: try_merge() should use LL_MERGE_ERROR when it means an error
 - rerere: fix comment on handle_file() helper
 - rerere: simplify check_one_conflict() helper function

 Code clean-up.

 Not ready to be reviewed yet.
 source: <20230824205456.1231371-1-gitster@pobox.com>

^ permalink raw reply

* Re: [PATCH v2] Add unix domain socket support to HTTP transport
From: Junio C Hamano @ 2024-02-23 15:43 UTC (permalink / raw)
  To: Leslie Cheng via GitGitGadget; +Cc: git, Eric Wong, Leslie Cheng, Leslie Cheng
In-Reply-To: <xmqqzfvrzic9.fsf@gitster.g>

Junio C Hamano <gitster@pobox.com> writes:

> "Leslie Cheng via GitGitGadget" <gitgitgadget@gmail.com> writes:
>
>> Subject: Re: [PATCH v2] Add unix domain socket support to HTTP transport
>
> Perhaps
>
> 	Subject: [PATCH] http: enable proxying via unix-domain socket
>
> to follow the usual "<area>: <description>" format?
>
>> From: Leslie Cheng <leslie.cheng5@gmail.com>
>>
>> This changeset introduces an `http.unixSocket` option so that users can
>
> "This changeset introduces" -> "Introduce".  There may be other
> gotchas that might use help from Documentation/SubmittingPatches,
> but I didn't read too carefully.
>
> Besides, it is a single patch, not a set of changes ;-).
>
> `http.unixSocket` is a configuration variable.  It may be confusing
> to use the word "option".  Speaking of options, shouldn't there be a
> command line option that overrides the configured value?
>
> We should honor the usual http.<url>.VARIABLE convention where
> http.<url>.VARIABLE that is destination-specific overrides a more
> generic http.VARIABLE configuration variable.

Clarification.  I know the above is automatically achieved, given
the way we have laid urlmatch foundation to allow easy parsing for
configuration variables structured this way.  I did not mean that
you'd need to do anything special; rather, I meant that we should
advertise that we do in the commit log message.


^ permalink raw reply

* [PATCH v5 5/5] for-each-ref: add new option to include root refs
From: Karthik Nayak @ 2024-02-23 10:01 UTC (permalink / raw)
  To: git; +Cc: gitster, ps, phillip.wood123, Karthik Nayak
In-Reply-To: <20240223100112.44127-1-karthik.188@gmail.com>

The git-for-each-ref(1) command doesn't provide a way to print root refs
i.e pseudorefs and HEAD with the regular "refs/" prefixed refs.

This commit adds a new option "--include-root-refs" to
git-for-each-ref(1). When used this would also print pseudorefs and HEAD
for the current worktree.

Signed-off-by: Karthik Nayak <karthik.188@gmail.com>
---
 Documentation/git-for-each-ref.txt |  5 ++++-
 builtin/for-each-ref.c             | 10 +++++++---
 ref-filter.c                       | 28 +++++++++++++++++++++++++--
 ref-filter.h                       |  5 ++++-
 refs/reftable-backend.c            | 11 +++++++----
 t/t6302-for-each-ref-filter.sh     | 31 ++++++++++++++++++++++++++++++
 6 files changed, 79 insertions(+), 11 deletions(-)

diff --git a/Documentation/git-for-each-ref.txt b/Documentation/git-for-each-ref.txt
index 3a9ad91b7a..c1dd12b93c 100644
--- a/Documentation/git-for-each-ref.txt
+++ b/Documentation/git-for-each-ref.txt
@@ -10,7 +10,7 @@ SYNOPSIS
 [verse]
 'git for-each-ref' [--count=<count>] [--shell|--perl|--python|--tcl]
 		   [(--sort=<key>)...] [--format=<format>]
-		   [ --stdin | <pattern>... ]
+		   [--include-root-refs] [ --stdin | <pattern>... ]
 		   [--points-at=<object>]
 		   [--merged[=<object>]] [--no-merged[=<object>]]
 		   [--contains[=<object>]] [--no-contains[=<object>]]
@@ -105,6 +105,9 @@ TAB %(refname)`.
 	any excluded pattern(s) are shown. Matching is done using the
 	same rules as `<pattern>` above.
 
+--include-root-refs::
+	List root refs (HEAD and pseudorefs) apart from regular refs.
+
 FIELD NAMES
 -----------
 
diff --git a/builtin/for-each-ref.c b/builtin/for-each-ref.c
index 23d352e371..919282e12a 100644
--- a/builtin/for-each-ref.c
+++ b/builtin/for-each-ref.c
@@ -20,10 +20,10 @@ int cmd_for_each_ref(int argc, const char **argv, const char *prefix)
 {
 	struct ref_sorting *sorting;
 	struct string_list sorting_options = STRING_LIST_INIT_DUP;
-	int icase = 0;
+	int icase = 0, include_root_refs = 0, from_stdin = 0;
 	struct ref_filter filter = REF_FILTER_INIT;
 	struct ref_format format = REF_FORMAT_INIT;
-	int from_stdin = 0;
+	unsigned int flags = FILTER_REFS_REGULAR;
 	struct strvec vec = STRVEC_INIT;
 
 	struct option opts[] = {
@@ -53,6 +53,7 @@ int cmd_for_each_ref(int argc, const char **argv, const char *prefix)
 		OPT_NO_CONTAINS(&filter.no_commit, N_("print only refs which don't contain the commit")),
 		OPT_BOOL(0, "ignore-case", &icase, N_("sorting and filtering are case insensitive")),
 		OPT_BOOL(0, "stdin", &from_stdin, N_("read reference patterns from stdin")),
+		OPT_BOOL(0, "include-root-refs", &include_root_refs, N_("also include HEAD ref and pseudorefs")),
 		OPT_END(),
 	};
 
@@ -96,8 +97,11 @@ int cmd_for_each_ref(int argc, const char **argv, const char *prefix)
 		filter.name_patterns = argv;
 	}
 
+	if (include_root_refs)
+		flags |= FILTER_REFS_ROOT_REFS;
+
 	filter.match_as_path = 1;
-	filter_and_format_refs(&filter, FILTER_REFS_REGULAR, sorting, &format);
+	filter_and_format_refs(&filter, flags, sorting, &format);
 
 	ref_filter_clear(&filter);
 	ref_sorting_release(sorting);
diff --git a/ref-filter.c b/ref-filter.c
index acb960e35c..0ec29f7385 100644
--- a/ref-filter.c
+++ b/ref-filter.c
@@ -2628,6 +2628,12 @@ static int for_each_fullref_in_pattern(struct ref_filter *filter,
 				       each_ref_fn cb,
 				       void *cb_data)
 {
+	if (filter->kind == FILTER_REFS_KIND_MASK) {
+		/* In this case, we want to print all refs including root refs. */
+		return refs_for_each_include_root_refs(get_main_ref_store(the_repository),
+						       cb, cb_data);
+	}
+
 	if (!filter->match_as_path) {
 		/*
 		 * in this case, the patterns are applied after
@@ -2750,6 +2756,9 @@ static int ref_kind_from_refname(const char *refname)
 			return ref_kind[i].kind;
 	}
 
+	if (is_pseudoref(get_main_ref_store(the_repository), refname))
+		return FILTER_REFS_PSEUDOREFS;
+
 	return FILTER_REFS_OTHERS;
 }
 
@@ -2781,7 +2790,16 @@ static struct ref_array_item *apply_ref_filter(const char *refname, const struct
 
 	/* Obtain the current ref kind from filter_ref_kind() and ignore unwanted refs. */
 	kind = filter_ref_kind(filter, refname);
-	if (!(kind & filter->kind))
+
+	/*
+	 * Generally HEAD refs are printed with special description denoting a rebase,
+	 * detached state and so forth. This is useful when only printing the HEAD ref
+	 * But when it is being printed along with other pseudorefs, it makes sense to
+	 * keep the formatting consistent. So we mask the type to act like a pseudoref.
+	 */
+	if (filter->kind == FILTER_REFS_KIND_MASK && kind == FILTER_REFS_DETACHED_HEAD)
+		kind = FILTER_REFS_PSEUDOREFS;
+	else if (!(kind & filter->kind))
 		return NULL;
 
 	if (!filter_pattern_match(filter, refname))
@@ -3049,7 +3067,13 @@ static int do_filter_refs(struct ref_filter *filter, unsigned int type, each_ref
 			ret = for_each_fullref_in("refs/tags/", fn, cb_data);
 		else if (filter->kind & FILTER_REFS_REGULAR)
 			ret = for_each_fullref_in_pattern(filter, fn, cb_data);
-		if (!ret && (filter->kind & FILTER_REFS_DETACHED_HEAD))
+
+		/*
+		 * When printing all ref types, HEAD is already included,
+		 * so we don't want to print HEAD again.
+		 */
+		if (!ret && (filter->kind != FILTER_REFS_KIND_MASK) &&
+		    (filter->kind & FILTER_REFS_DETACHED_HEAD))
 			head_ref(fn, cb_data);
 	}
 
diff --git a/ref-filter.h b/ref-filter.h
index 5416936800..0ca28d2bba 100644
--- a/ref-filter.h
+++ b/ref-filter.h
@@ -22,7 +22,10 @@
 #define FILTER_REFS_REGULAR        (FILTER_REFS_TAGS | FILTER_REFS_BRANCHES | \
 				    FILTER_REFS_REMOTES | FILTER_REFS_OTHERS)
 #define FILTER_REFS_DETACHED_HEAD  0x0020
-#define FILTER_REFS_KIND_MASK      (FILTER_REFS_REGULAR | FILTER_REFS_DETACHED_HEAD)
+#define FILTER_REFS_PSEUDOREFS     0x0040
+#define FILTER_REFS_ROOT_REFS      (FILTER_REFS_DETACHED_HEAD | FILTER_REFS_PSEUDOREFS)
+#define FILTER_REFS_KIND_MASK      (FILTER_REFS_REGULAR | FILTER_REFS_DETACHED_HEAD | \
+				    FILTER_REFS_PSEUDOREFS)
 
 struct atom_value;
 struct ref_sorting;
diff --git a/refs/reftable-backend.c b/refs/reftable-backend.c
index a14f2ad7f4..c23a516ac2 100644
--- a/refs/reftable-backend.c
+++ b/refs/reftable-backend.c
@@ -364,12 +364,15 @@ static int reftable_ref_iterator_advance(struct ref_iterator *ref_iterator)
 			break;
 
 		/*
-		 * The files backend only lists references contained in
-		 * "refs/". We emulate the same behaviour here and thus skip
-		 * all references that don't start with this prefix.
+		 * The files backend only lists references contained in "refs/" unless
+		 * the root refs are to be included. We emulate the same behaviour here.
 		 */
-		if (!starts_with(iter->ref.refname, "refs/"))
+		if (!starts_with(iter->ref.refname, "refs/") &&
+		    !(iter->flags & DO_FOR_EACH_INCLUDE_ROOT_REFS &&
+		     (is_pseudoref(&iter->refs->base, iter->ref.refname) ||
+		      is_headref(&iter->refs->base, iter->ref.refname)))) {
 			continue;
+		}
 
 		if (iter->prefix &&
 		    strncmp(iter->prefix, iter->ref.refname, strlen(iter->prefix))) {
diff --git a/t/t6302-for-each-ref-filter.sh b/t/t6302-for-each-ref-filter.sh
index 82f3d1ea0f..948f1bb5f4 100755
--- a/t/t6302-for-each-ref-filter.sh
+++ b/t/t6302-for-each-ref-filter.sh
@@ -31,6 +31,37 @@ test_expect_success 'setup some history and refs' '
 	git update-ref refs/odd/spot main
 '
 
+test_expect_success '--include-root-refs pattern prints pseudorefs' '
+	cat >expect <<-\EOF &&
+	HEAD
+	ORIG_HEAD
+	refs/heads/main
+	refs/heads/side
+	refs/odd/spot
+	refs/tags/annotated-tag
+	refs/tags/doubly-annotated-tag
+	refs/tags/doubly-signed-tag
+	refs/tags/four
+	refs/tags/one
+	refs/tags/signed-tag
+	refs/tags/three
+	refs/tags/two
+	EOF
+	git update-ref ORIG_HEAD main &&
+	git for-each-ref --format="%(refname)" --include-root-refs >actual &&
+	test_cmp expect actual
+'
+
+test_expect_success '--include-root-refs with other patterns' '
+	cat >expect <<-\EOF &&
+	HEAD
+	ORIG_HEAD
+	EOF
+	git update-ref ORIG_HEAD main &&
+	git for-each-ref --format="%(refname)" --include-root-refs "*HEAD" >actual &&
+	test_cmp expect actual
+'
+
 test_expect_success 'filtering with --points-at' '
 	cat >expect <<-\EOF &&
 	refs/heads/main
-- 
2.43.GIT


^ permalink raw reply related

* [PATCH v5 4/5] ref-filter: rename 'FILTER_REFS_ALL' to 'FILTER_REFS_REGULAR'
From: Karthik Nayak @ 2024-02-23 10:01 UTC (permalink / raw)
  To: git; +Cc: gitster, ps, phillip.wood123, Karthik Nayak
In-Reply-To: <20240223100112.44127-1-karthik.188@gmail.com>

The flag 'FILTER_REFS_ALL' is a bit ambiguous, where ALL doesn't specify
if it means to contain refs from all worktrees or whether all types of
refs (regular, HEAD & pseudorefs) or all of the above.

Since here it is actually referring to all refs with the "refs/" prefix,
let's rename it to 'FILTER_REFS_REGULAR' to indicate that this is
specifically for regular refs.

Signed-off-by: Karthik Nayak <karthik.188@gmail.com>
---
 builtin/for-each-ref.c | 2 +-
 ref-filter.c           | 2 +-
 ref-filter.h           | 4 ++--
 3 files changed, 4 insertions(+), 4 deletions(-)

diff --git a/builtin/for-each-ref.c b/builtin/for-each-ref.c
index 3885a9c28e..23d352e371 100644
--- a/builtin/for-each-ref.c
+++ b/builtin/for-each-ref.c
@@ -97,7 +97,7 @@ int cmd_for_each_ref(int argc, const char **argv, const char *prefix)
 	}
 
 	filter.match_as_path = 1;
-	filter_and_format_refs(&filter, FILTER_REFS_ALL, sorting, &format);
+	filter_and_format_refs(&filter, FILTER_REFS_REGULAR, sorting, &format);
 
 	ref_filter_clear(&filter);
 	ref_sorting_release(sorting);
diff --git a/ref-filter.c b/ref-filter.c
index be14b56e32..acb960e35c 100644
--- a/ref-filter.c
+++ b/ref-filter.c
@@ -3047,7 +3047,7 @@ static int do_filter_refs(struct ref_filter *filter, unsigned int type, each_ref
 			ret = for_each_fullref_in("refs/remotes/", fn, cb_data);
 		else if (filter->kind == FILTER_REFS_TAGS)
 			ret = for_each_fullref_in("refs/tags/", fn, cb_data);
-		else if (filter->kind & FILTER_REFS_ALL)
+		else if (filter->kind & FILTER_REFS_REGULAR)
 			ret = for_each_fullref_in_pattern(filter, fn, cb_data);
 		if (!ret && (filter->kind & FILTER_REFS_DETACHED_HEAD))
 			head_ref(fn, cb_data);
diff --git a/ref-filter.h b/ref-filter.h
index 07cd6f6da3..5416936800 100644
--- a/ref-filter.h
+++ b/ref-filter.h
@@ -19,10 +19,10 @@
 #define FILTER_REFS_BRANCHES       0x0004
 #define FILTER_REFS_REMOTES        0x0008
 #define FILTER_REFS_OTHERS         0x0010
-#define FILTER_REFS_ALL            (FILTER_REFS_TAGS | FILTER_REFS_BRANCHES | \
+#define FILTER_REFS_REGULAR        (FILTER_REFS_TAGS | FILTER_REFS_BRANCHES | \
 				    FILTER_REFS_REMOTES | FILTER_REFS_OTHERS)
 #define FILTER_REFS_DETACHED_HEAD  0x0020
-#define FILTER_REFS_KIND_MASK      (FILTER_REFS_ALL | FILTER_REFS_DETACHED_HEAD)
+#define FILTER_REFS_KIND_MASK      (FILTER_REFS_REGULAR | FILTER_REFS_DETACHED_HEAD)
 
 struct atom_value;
 struct ref_sorting;
-- 
2.43.GIT


^ permalink raw reply related

* [PATCH v5 3/5] refs: introduce `refs_for_each_include_root_refs()`
From: Karthik Nayak @ 2024-02-23 10:01 UTC (permalink / raw)
  To: git; +Cc: gitster, ps, phillip.wood123, Karthik Nayak
In-Reply-To: <20240223100112.44127-1-karthik.188@gmail.com>

Introduce a new ref iteration flag `DO_FOR_EACH_INCLUDE_ROOT_REFS`,
which will be used to iterate over regular refs plus pseudorefs and
HEAD.

Refs which fall outside the `refs/` and aren't either pseudorefs or HEAD
are more of a grey area. This is because we don't block the users from
creating such refs but they are not officially supported.

Introduce `refs_for_each_include_root_refs()` which calls
`do_for_each_ref()` with this newly introduced flag.

In `refs/files-backend.c`, introduce a new function
`add_pseudoref_and_head_entries()` to add pseudorefs and HEAD to the
`ref_dir`. We then finally call `add_pseudoref_and_head_entries()`
whenever the `DO_FOR_EACH_INCLUDE_ROOT_REFS` flag is set. Any new ref
backend will also have to implement similar changes on its end.

Signed-off-by: Karthik Nayak <karthik.188@gmail.com>
---
 refs.c               |  7 +++++
 refs.h               |  6 ++++
 refs/files-backend.c | 65 ++++++++++++++++++++++++++++++++++++++++----
 refs/refs-internal.h |  6 ++++
 4 files changed, 79 insertions(+), 5 deletions(-)

diff --git a/refs.c b/refs.c
index 3546d90831..7d58fe1e09 100644
--- a/refs.c
+++ b/refs.c
@@ -1765,6 +1765,13 @@ int for_each_rawref(each_ref_fn fn, void *cb_data)
 	return refs_for_each_rawref(get_main_ref_store(the_repository), fn, cb_data);
 }
 
+int refs_for_each_include_root_refs(struct ref_store *refs, each_ref_fn fn,
+				    void *cb_data)
+{
+	return do_for_each_ref(refs, "", NULL, fn, 0,
+			       DO_FOR_EACH_INCLUDE_ROOT_REFS, cb_data);
+}
+
 static int qsort_strcmp(const void *va, const void *vb)
 {
 	const char *a = *(const char **)va;
diff --git a/refs.h b/refs.h
index f66cdd731c..5cfaee6229 100644
--- a/refs.h
+++ b/refs.h
@@ -398,6 +398,12 @@ int for_each_namespaced_ref(const char **exclude_patterns,
 int refs_for_each_rawref(struct ref_store *refs, each_ref_fn fn, void *cb_data);
 int for_each_rawref(each_ref_fn fn, void *cb_data);
 
+/*
+ * Iterates over all refs including root refs, i.e. pseudorefs and HEAD.
+ */
+int refs_for_each_include_root_refs(struct ref_store *refs, each_ref_fn fn,
+				    void *cb_data);
+
 /*
  * Normalizes partial refs to their fully qualified form.
  * Will prepend <prefix> to the <pattern> if it doesn't start with 'refs/'.
diff --git a/refs/files-backend.c b/refs/files-backend.c
index 65128821a8..9c1c42fe52 100644
--- a/refs/files-backend.c
+++ b/refs/files-backend.c
@@ -315,9 +315,59 @@ static void loose_fill_ref_dir(struct ref_store *ref_store,
 	add_per_worktree_entries_to_dir(dir, dirname);
 }
 
-static struct ref_cache *get_loose_ref_cache(struct files_ref_store *refs)
+/*
+ * Add pseudorefs to the ref dir by parsing the directory for any files
+ * which follow the pseudoref syntax.
+ */
+static void add_pseudoref_and_head_entries(struct ref_store *ref_store,
+					 struct ref_dir *dir,
+					 const char *dirname)
+{
+	struct files_ref_store *refs =
+		files_downcast(ref_store, REF_STORE_READ, "fill_ref_dir");
+	struct strbuf path = STRBUF_INIT, refname = STRBUF_INIT;
+	struct dirent *de;
+	size_t dirnamelen;
+	DIR *d;
+
+	files_ref_path(refs, &path, dirname);
+
+	d = opendir(path.buf);
+	if (!d) {
+		strbuf_release(&path);
+		return;
+	}
+
+	strbuf_addstr(&refname, dirname);
+	dirnamelen = refname.len;
+
+	while ((de = readdir(d)) != NULL) {
+		unsigned char dtype;
+
+		if (de->d_name[0] == '.')
+			continue;
+		if (ends_with(de->d_name, ".lock"))
+			continue;
+		strbuf_addstr(&refname, de->d_name);
+
+		dtype = get_dtype(de, &path, 1);
+		if (dtype == DT_REG && (is_pseudoref(ref_store, de->d_name) ||
+								is_headref(ref_store, de->d_name)))
+			loose_fill_ref_dir_regular_file(refs, refname.buf, dir);
+
+		strbuf_setlen(&refname, dirnamelen);
+	}
+	strbuf_release(&refname);
+	strbuf_release(&path);
+	closedir(d);
+}
+
+static struct ref_cache *get_loose_ref_cache(struct files_ref_store *refs,
+					     unsigned int flags)
 {
 	if (!refs->loose) {
+		struct ref_dir *dir;
+
 		/*
 		 * Mark the top-level directory complete because we
 		 * are about to read the only subdirectory that can
@@ -328,12 +378,17 @@ static struct ref_cache *get_loose_ref_cache(struct files_ref_store *refs)
 		/* We're going to fill the top level ourselves: */
 		refs->loose->root->flag &= ~REF_INCOMPLETE;
 
+		dir = get_ref_dir(refs->loose->root);
+
+		if (flags & DO_FOR_EACH_INCLUDE_ROOT_REFS)
+			add_pseudoref_and_head_entries(dir->cache->ref_store, dir,
+						       refs->loose->root->name);
+
 		/*
 		 * Add an incomplete entry for "refs/" (to be filled
 		 * lazily):
 		 */
-		add_entry_to_dir(get_ref_dir(refs->loose->root),
-				 create_dir_entry(refs->loose, "refs/", 5));
+		add_entry_to_dir(dir, create_dir_entry(refs->loose, "refs/", 5));
 	}
 	return refs->loose;
 }
@@ -861,7 +916,7 @@ static struct ref_iterator *files_ref_iterator_begin(
 	 * disk, and re-reads it if not.
 	 */
 
-	loose_iter = cache_ref_iterator_begin(get_loose_ref_cache(refs),
+	loose_iter = cache_ref_iterator_begin(get_loose_ref_cache(refs, flags),
 					      prefix, ref_store->repo, 1);
 
 	/*
@@ -1222,7 +1277,7 @@ static int files_pack_refs(struct ref_store *ref_store,
 
 	packed_refs_lock(refs->packed_ref_store, LOCK_DIE_ON_ERROR, &err);
 
-	iter = cache_ref_iterator_begin(get_loose_ref_cache(refs), NULL,
+	iter = cache_ref_iterator_begin(get_loose_ref_cache(refs, 0), NULL,
 					the_repository, 0);
 	while ((ok = ref_iterator_advance(iter)) == ITER_OK) {
 		/*
diff --git a/refs/refs-internal.h b/refs/refs-internal.h
index 83e0f0bba3..73a8fa18ad 100644
--- a/refs/refs-internal.h
+++ b/refs/refs-internal.h
@@ -260,6 +260,12 @@ enum do_for_each_ref_flags {
 	 * INCLUDE_BROKEN, since they are otherwise not included at all.
 	 */
 	DO_FOR_EACH_OMIT_DANGLING_SYMREFS = (1 << 2),
+
+	/*
+	 * Include root refs i.e. HEAD and pseudorefs along with the regular
+	 * refs.
+	 */
+	DO_FOR_EACH_INCLUDE_ROOT_REFS = (1 << 3),
 };
 
 /*
-- 
2.43.GIT


^ permalink raw reply related

* [PATCH v5 2/5] refs: extract out `loose_fill_ref_dir_regular_file()`
From: Karthik Nayak @ 2024-02-23 10:01 UTC (permalink / raw)
  To: git; +Cc: gitster, ps, phillip.wood123, Karthik Nayak
In-Reply-To: <20240223100112.44127-1-karthik.188@gmail.com>

Extract out the code for adding a single file to the loose ref dir as
`loose_fill_ref_dir_regular_file()` from `loose_fill_ref_dir()` in
`refs/files-backend.c`.

This allows us to use this function independently in the following
commits where we add code to also add pseudorefs to the ref dir.

Signed-off-by: Karthik Nayak <karthik.188@gmail.com>
---
 refs/files-backend.c | 62 +++++++++++++++++++++++---------------------
 1 file changed, 33 insertions(+), 29 deletions(-)

diff --git a/refs/files-backend.c b/refs/files-backend.c
index 75dcc21ecb..65128821a8 100644
--- a/refs/files-backend.c
+++ b/refs/files-backend.c
@@ -229,6 +229,38 @@ static void add_per_worktree_entries_to_dir(struct ref_dir *dir, const char *dir
 	}
 }
 
+static void loose_fill_ref_dir_regular_file(struct files_ref_store *refs,
+					    const char *refname,
+					    struct ref_dir *dir)
+{
+	struct object_id oid;
+	int flag;
+
+	if (!refs_resolve_ref_unsafe(&refs->base, refname, RESOLVE_REF_READING,
+				     &oid, &flag)) {
+		oidclr(&oid);
+		flag |= REF_ISBROKEN;
+	} else if (is_null_oid(&oid)) {
+		/*
+		 * It is so astronomically unlikely
+		 * that null_oid is the OID of an
+		 * actual object that we consider its
+		 * appearance in a loose reference
+		 * file to be repo corruption
+		 * (probably due to a software bug).
+		 */
+		flag |= REF_ISBROKEN;
+	}
+
+	if (check_refname_format(refname, REFNAME_ALLOW_ONELEVEL)) {
+		if (!refname_is_safe(refname))
+			die("loose refname is dangerous: %s", refname);
+		oidclr(&oid);
+		flag |= REF_BAD_NAME | REF_ISBROKEN;
+	}
+	add_entry_to_dir(dir, create_ref_entry(refname, &oid, flag));
+}
+
 /*
  * Read the loose references from the namespace dirname into dir
  * (without recursing).  dirname must end with '/'.  dir must be the
@@ -257,8 +289,6 @@ static void loose_fill_ref_dir(struct ref_store *ref_store,
 	strbuf_add(&refname, dirname, dirnamelen);
 
 	while ((de = readdir(d)) != NULL) {
-		struct object_id oid;
-		int flag;
 		unsigned char dtype;
 
 		if (de->d_name[0] == '.')
@@ -274,33 +304,7 @@ static void loose_fill_ref_dir(struct ref_store *ref_store,
 					 create_dir_entry(dir->cache, refname.buf,
 							  refname.len));
 		} else if (dtype == DT_REG) {
-			if (!refs_resolve_ref_unsafe(&refs->base,
-						     refname.buf,
-						     RESOLVE_REF_READING,
-						     &oid, &flag)) {
-				oidclr(&oid);
-				flag |= REF_ISBROKEN;
-			} else if (is_null_oid(&oid)) {
-				/*
-				 * It is so astronomically unlikely
-				 * that null_oid is the OID of an
-				 * actual object that we consider its
-				 * appearance in a loose reference
-				 * file to be repo corruption
-				 * (probably due to a software bug).
-				 */
-				flag |= REF_ISBROKEN;
-			}
-
-			if (check_refname_format(refname.buf,
-						 REFNAME_ALLOW_ONELEVEL)) {
-				if (!refname_is_safe(refname.buf))
-					die("loose refname is dangerous: %s", refname.buf);
-				oidclr(&oid);
-				flag |= REF_BAD_NAME | REF_ISBROKEN;
-			}
-			add_entry_to_dir(dir,
-					 create_ref_entry(refname.buf, &oid, flag));
+			loose_fill_ref_dir_regular_file(refs, refname.buf, dir);
 		}
 		strbuf_setlen(&refname, dirnamelen);
 	}
-- 
2.43.GIT


^ permalink raw reply related

* [PATCH v5 1/5] refs: introduce `is_pseudoref()` and `is_headref()`
From: Karthik Nayak @ 2024-02-23 10:01 UTC (permalink / raw)
  To: git; +Cc: gitster, ps, phillip.wood123, Karthik Nayak, Jeff King
In-Reply-To: <20240223100112.44127-1-karthik.188@gmail.com>

Introduce two new functions `is_pseudoref()` and `is_headref()`. This
provides the necessary functionality for us to add pseudorefs and HEAD
to the loose ref cache in the files backend, allowing us to build
tooling to print these refs.

The `is_pseudoref()` function internally calls `is_pseudoref_syntax()`
but adds onto it by also checking to ensure that the pseudoref either
ends with a "_HEAD" suffix or matches a list of exceptions. After which
we also parse the contents of the pseudoref to ensure that it conforms
to the ref format.

We cannot directly add the new syntax checks to `is_pseudoref_syntax()`
because the function is also used by `is_current_worktree_ref()` and
making it stricter to match only known pseudorefs might have unintended
consequences due to files like 'BISECT_START' which isn't a pseudoref
but sometimes contains object ID.

Keeping this in mind, we leave `is_pseudoref_syntax()` as is and create
`is_pseudoref()` which is stricter. Ideally we'd want to move the new
syntax checks to `is_pseudoref_syntax()` but a prerequisite for this
would be to actually remove the exception list by converting those
pseudorefs to also contain a '_HEAD' suffix and perhaps move bisect
related files like 'BISECT_START' to a new directory similar to the
'rebase-merge' directory.

Helped-by: Jeff King <peff@peff.net>
Signed-off-by: Karthik Nayak <karthik.188@gmail.com>
---
 refs.c | 41 +++++++++++++++++++++++++++++++++++++++++
 refs.h |  3 +++
 2 files changed, 44 insertions(+)

diff --git a/refs.c b/refs.c
index fff343c256..3546d90831 100644
--- a/refs.c
+++ b/refs.c
@@ -860,6 +860,47 @@ static int is_pseudoref_syntax(const char *refname)
 	return 1;
 }
 
+int is_pseudoref(struct ref_store *refs, const char *refname)
+{
+	static const char *const irregular_pseudorefs[] = {
+		"AUTO_MERGE",
+		"BISECT_EXPECTED_REV",
+		"NOTES_MERGE_PARTIAL",
+		"NOTES_MERGE_REF",
+		"MERGE_AUTOSTASH",
+	};
+	struct object_id oid;
+	size_t i;
+
+	if (!is_pseudoref_syntax(refname))
+		return 0;
+
+	if (ends_with(refname, "_HEAD")) {
+		refs_resolve_ref_unsafe(refs, refname,
+					RESOLVE_REF_READING | RESOLVE_REF_NO_RECURSE,
+					&oid, NULL);
+		return !is_null_oid(&oid);
+	}
+
+	for (i = 0; i < ARRAY_SIZE(irregular_pseudorefs); i++)
+		if (!strcmp(refname, irregular_pseudorefs[i])) {
+			refs_resolve_ref_unsafe(refs, refname,
+						RESOLVE_REF_READING | RESOLVE_REF_NO_RECURSE,
+						&oid, NULL);
+			return !is_null_oid(&oid);
+		}
+
+	return 0;
+}
+
+int is_headref(struct ref_store *refs, const char *refname)
+{
+	if (!strcmp(refname, "HEAD"))
+		return refs_ref_exists(refs, refname);
+
+	return 0;
+}
+
 static int is_current_worktree_ref(const char *ref) {
 	return is_pseudoref_syntax(ref) || is_per_worktree_ref(ref);
 }
diff --git a/refs.h b/refs.h
index 303c5fac4d..f66cdd731c 100644
--- a/refs.h
+++ b/refs.h
@@ -1023,4 +1023,7 @@ extern struct ref_namespace_info ref_namespace[NAMESPACE__COUNT];
  */
 void update_ref_namespace(enum ref_namespace namespace, char *ref);
 
+int is_pseudoref(struct ref_store *refs, const char *refname);
+int is_headref(struct ref_store *refs, const char *refname);
+
 #endif /* REFS_H */
-- 
2.43.GIT


^ permalink raw reply related

* [PATCH v5 0/5] for-each-ref: add '--include-root-refs' option
From: Karthik Nayak @ 2024-02-23 10:01 UTC (permalink / raw)
  To: git; +Cc: gitster, ps, phillip.wood123, Karthik Nayak
In-Reply-To: <20240119142705.139374-1-karthik.188@gmail.com>

This is the fifth version of my patch series to print root refs
in git-for-each-ref(1).

With the introduction of the reftable backend, it becomes ever
so important to provide the necessary tooling for printing all refs
associated with a worktree.

While regular refs stored within the "refs/" namespace are currently
supported by multiple commands like git-for-each-ref(1),
git-show-ref(1). Neither support printing root refs within the worktree.

This patch series is a follow up to the RFC/discussion we had earlier on
the list [1].

The first 4 commits add the required functionality to ensure we can print
all refs (regular, pseudo, HEAD). The 5th commit modifies the
git-for-each-ref(1) command to add the "--include-root-refs" command which
will include HEAD and pseudorefs with regular "refs/" refs.

[1]: https://lore.kernel.org/git/20231221170715.110565-1-karthik.188@gmail.com/#t

Changes from v4:
1. Fixed erratic whitespace
2. Remove braces from single line block
3. Starting the comments with a capital and also adding more context.
4. Removed a duplicate check.

Thanks for the reviews.

Range diff against v4:

1:  98130a7ad7 ! 1:  6016042965 refs: introduce `is_pseudoref()` and `is_headref()`
    @@ refs.c: static int is_pseudoref_syntax(const char *refname)
     +
     +	if (ends_with(refname, "_HEAD")) {
     +		refs_resolve_ref_unsafe(refs, refname,
    -+   					RESOLVE_REF_READING | RESOLVE_REF_NO_RECURSE,
    -+   					&oid, NULL);
    -+   		return !is_null_oid(&oid);
    ++					RESOLVE_REF_READING | RESOLVE_REF_NO_RECURSE,
    ++					&oid, NULL);
    ++		return !is_null_oid(&oid);
     +	}
     +
     +	for (i = 0; i < ARRAY_SIZE(irregular_pseudorefs); i++)
     +		if (!strcmp(refname, irregular_pseudorefs[i])) {
     +			refs_resolve_ref_unsafe(refs, refname,
    -+   						RESOLVE_REF_READING | RESOLVE_REF_NO_RECURSE,
    -+   						&oid, NULL);
    ++						RESOLVE_REF_READING | RESOLVE_REF_NO_RECURSE,
    ++						&oid, NULL);
     +			return !is_null_oid(&oid);
     +		}
     +
2:  060ab08af5 = 2:  acaa014841 refs: extract out `loose_fill_ref_dir_regular_file()`
3:  40d2375ad9 = 3:  f51c5bc307 refs: introduce `refs_for_each_include_root_refs()`
4:  b4b9435505 = 4:  7c004db6e7 ref-filter: rename 'FILTER_REFS_ALL' to 'FILTER_REFS_REGULAR'
5:  ee99ac41ae ! 5:  53f6c0a6db for-each-ref: add new option to include root refs
    @@ builtin/for-each-ref.c: int cmd_for_each_ref(int argc, const char **argv, const
      		filter.name_patterns = argv;
      	}
      
    -+	if (include_root_refs) {
    ++	if (include_root_refs)
     +		flags |= FILTER_REFS_ROOT_REFS;
    -+	}
     +
      	filter.match_as_path = 1;
     -	filter_and_format_refs(&filter, FILTER_REFS_REGULAR, sorting, &format);
    @@ ref-filter.c: static int for_each_fullref_in_pattern(struct ref_filter *filter,
      				       void *cb_data)
      {
     +	if (filter->kind == FILTER_REFS_KIND_MASK) {
    -+		/* in this case, we want to print all refs including root refs. */
    ++		/* In this case, we want to print all refs including root refs. */
     +		return refs_for_each_include_root_refs(get_main_ref_store(the_repository),
     +						       cb, cb_data);
     +	}
    @@ ref-filter.c: static struct ref_array_item *apply_ref_filter(const char *refname
      
      	/* Obtain the current ref kind from filter_ref_kind() and ignore unwanted refs. */
      	kind = filter_ref_kind(filter, refname);
    +-	if (!(kind & filter->kind))
     +
     +	/*
    -+	 * When printing HEAD with all other refs, we want to apply the same formatting
    -+	 * rules as the other refs, so we simply ask it to be treated as a pseudoref.
    ++	 * Generally HEAD refs are printed with special description denoting a rebase,
    ++	 * detached state and so forth. This is useful when only printing the HEAD ref
    ++	 * But when it is being printed along with other pseudorefs, it makes sense to
    ++	 * keep the formatting consistent. So we mask the type to act like a pseudoref.
     +	 */
     +	if (filter->kind == FILTER_REFS_KIND_MASK && kind == FILTER_REFS_DETACHED_HEAD)
     +		kind = FILTER_REFS_PSEUDOREFS;
     +	else if (!(kind & filter->kind))
    -+		return NULL;
    -+
    - 	if (!(kind & filter->kind))
      		return NULL;
      
    + 	if (!filter_pattern_match(filter, refname))
     @@ ref-filter.c: static int do_filter_refs(struct ref_filter *filter, unsigned int type, each_ref
      			ret = for_each_fullref_in("refs/tags/", fn, cb_data);
      		else if (filter->kind & FILTER_REFS_REGULAR)


Karthik Nayak (5):
  refs: introduce `is_pseudoref()` and `is_headref()`
  refs: extract out `loose_fill_ref_dir_regular_file()`
  refs: introduce `refs_for_each_include_root_refs()`
  ref-filter: rename 'FILTER_REFS_ALL' to 'FILTER_REFS_REGULAR'
  for-each-ref: add new option to include root refs

 Documentation/git-for-each-ref.txt |   5 +-
 builtin/for-each-ref.c             |  10 ++-
 ref-filter.c                       |  30 ++++++-
 ref-filter.h                       |   7 +-
 refs.c                             |  48 +++++++++++
 refs.h                             |   9 ++
 refs/files-backend.c               | 127 +++++++++++++++++++++--------
 refs/refs-internal.h               |   6 ++
 refs/reftable-backend.c            |  11 ++-
 t/t6302-for-each-ref-filter.sh     |  31 +++++++
 10 files changed, 237 insertions(+), 47 deletions(-)

-- 
2.43.GIT


^ permalink raw reply

* Re: [PATCH v2] Add unix domain socket support to HTTP transport
From: Junio C Hamano @ 2024-02-23  8:37 UTC (permalink / raw)
  To: Leslie Cheng via GitGitGadget; +Cc: git, Eric Wong, Leslie Cheng, Leslie Cheng
In-Reply-To: <pull.1681.v2.git.git.1708653536115.gitgitgadget@gmail.com>

"Leslie Cheng via GitGitGadget" <gitgitgadget@gmail.com> writes:

> Subject: Re: [PATCH v2] Add unix domain socket support to HTTP transport

Perhaps

	Subject: [PATCH] http: enable proxying via unix-domain socket

to follow the usual "<area>: <description>" format?

> From: Leslie Cheng <leslie.cheng5@gmail.com>
>
> This changeset introduces an `http.unixSocket` option so that users can

"This changeset introduces" -> "Introduce".  There may be other
gotchas that might use help from Documentation/SubmittingPatches,
but I didn't read too carefully.

Besides, it is a single patch, not a set of changes ;-).

`http.unixSocket` is a configuration variable.  It may be confusing
to use the word "option".  Speaking of options, shouldn't there be a
command line option that overrides the configured value?

We should honor the usual http.<url>.VARIABLE convention where
http.<url>.VARIABLE that is destination-specific overrides a more
generic http.VARIABLE configuration variable.

> proxy their git over HTTP remotes to a unix domain socket. In terms of
> why, since UDS are local and git already has a local protocol: some
> corporate environments use a UDS to proxy requests to internal resources
> (ie. source control), so this change would support those use-cases. This

"ie." -> "i.e.,"?

> proxy can occasionally be necessary to attach MFA tokens or client
> certificates for CLI tools.
>
> The implementation leverages `--unix-socket` option [0] via the
> `CURLOPT_UNIX_SOCKET_PATH` flag available with libcurl [1].

There is a feature in libcURL library, that is enabled by setting
the CURLOPT_UNIX_SOCKET_PATH option via the curl_easy_setopt() call,
and their command line utility.  You do the same to implement this
feature.  But when you are not adding "--unix-socket" option to any
of our commands, mention of that option name makes it more confusing
than necessary.

The usual way to compose a log message of this project is to

 - Give an observation on how the current system work in the present
   tense (so no need to say "Currently X is Y", just "X is Y"), and
   discuss what you perceive as a problem in it.

 - Propose a solution (optional---often, problem description
   trivially leads to an obvious solution in reader's minds).

 - Give commands to the codebase to "become like so".

in this order.

How about following that convention, perhaps like:

    In some corporate environments, the proxy server listens to a
    local unix domain socket for requests, instead of listening to a
    network port.  Even though we have http.proxy (and more
    destination specific http.<url>.proxy) configuration variables
    to specify the network address/port of a proxy, that would not
    help if your proxy does not listen to the network.

    Introduce an `http.unixSocket` (and `http.<url>.unixSocket`)
    configuration variables that specify the path to a unix domain
    socket for such a proxy.  Recent versions of libcURL library
    added CURLOPT_UNIX_SOCKET_PATH to support "curl --unix-socket
    <path>"---use the same mechanism to implement it.

> `GIT_CURL_HAVE_CURLOPT_UNIX_SOCKET_PATH` and `NO_UNIX_SOCKETS` were kept
> separate so that we can spit out better error messages for users if git
> was compiled with `NO_UNIX_SOCKETS`.

Unlike NO_UNIX_SOCKETS, GIT_CURL_HAVE_CURLOPT_UNIX_SOCKET_PATH is
entirely internal to your implementation and not surfaced to neither
the end-users or the binary packagers.  Because of that, I suspect
that any description that has to use that name probably falls on the
other side of "too much implementation details" to be useful to help
future developers..

Besides, I suspect that GIT_CURL_HAVE_CURLOPT_UNIX_SOCKET_PATH might
not be the optimum approach.  See below.

> diff --git a/Documentation/config/http.txt b/Documentation/config/http.txt
> index 2d4e0c9b869..bf48cbd599a 100644
> --- a/Documentation/config/http.txt
> +++ b/Documentation/config/http.txt
> @@ -277,6 +277,11 @@ http.followRedirects::
>  	the base for the follow-up requests, this is generally
>  	sufficient. The default is `initial`.
>  
> +http.unixSocket::
> +	Connect through this Unix domain socket via HTTP, instead of using the
> +	network. If set, this config takes precendence over `http.proxy` and
> +	is incompatible with the proxy options (see `curl(1)`).

Talking about precedence between this and http.proxy is good thing,
but one very important piece of information is missing.  What value
does it take?

	The absolute path of a unix-domain socket to pass the HTTP
	traffic over, instead of using the network.

or something, perhaps?

> diff --git a/git-curl-compat.h b/git-curl-compat.h
> index fd96b3cdffd..f0f3bec0e17 100644
> --- a/git-curl-compat.h
> +++ b/git-curl-compat.h
> @@ -74,6 +74,13 @@
>  #define GIT_CURL_HAVE_CURLE_SSL_PINNEDPUBKEYNOTMATCH 1
>  #endif
>  
> +/**
> + * CURLOPT_UNIX_SOCKET_PATH was added in 7.40.0, released in January 2015.
> + */
> +#if LIBCURL_VERSION_NUM >= 0x074000
> +#define GIT_CURL_HAVE_CURLOPT_UNIX_SOCKET_PATH 1
> +#endif

The "HAVE" part in GIT_CURL_HAVE_CURLOPT_UNIX_SOCKET_PATH is a
statement of a fact.  If the version of cURL library we have is
certain value, we have it.  OK.

> diff --git a/http.c b/http.c
> index e73b136e589..8cfdcaeac82 100644
> --- a/http.c
> +++ b/http.c
> @@ -79,6 +79,9 @@ static const char *http_proxy_ssl_ca_info;
>  static struct credential proxy_cert_auth = CREDENTIAL_INIT;
>  static int proxy_ssl_cert_password_required;

It might make the code easier to follow if you did:

	#if !defined(NO_CURLOPT_UNIX_SOCKET_PATH) && !defined(NO_UNIX_SOCKETS)
	#if defined(GIT_CURL_HAVE_CURLOPT_UNIX_SOCKET_PATH)
        #define USE_CURLOPT_UNIX_SOCKET_PATH
	#endif
	#endif
        
The points are

 (1) the users can decline to use CURLOPT_UNIX_SOCKET_PATH while
     still using unix domain socket for other purposes, and

 (2) you do not have to care if you HAVE it or not most of time;
     what matters more often is if the user told you to USE it.

Hmm?

> +#if defined(GIT_CURL_HAVE_CURLOPT_UNIX_SOCKET_PATH) && !defined(NO_UNIX_SOCKETS)
> +static const char *curl_unix_socket_path;
> +#endif

The guard here would become "#ifdef USE_CURLOPT_UNIX_SOCKET_PATH" if
we wanted this to be conditional, but I think it is easier to make
the variable unconditionally available; see below.

> @@ -455,6 +458,20 @@ static int http_options(const char *var, const char *value,
>  		return 0;
>  	}
>  
> +	if (!strcmp("http.unixsocket", var)) {
> +#ifdef GIT_CURL_HAVE_CURLOPT_UNIX_SOCKET_PATH
> +#ifndef NO_UNIX_SOCKETS
> +		return git_config_string(&curl_unix_socket_path, var, value);
> +#else
> +		warning(_("Unix socket support unavailable in this build of Git"));
> +		return 0;
> +#endif
> +#else
> +		warning(_("Unix socket support is not supported with cURL < 7.40.0"));
> +		return 0;
> +#endif
> +	}

In general, it is inadvisable to issue a warning in the codepath
that parses configuration variables, as the values we read may not
be necessarily used.  We could instead accept the given path into a
variable unconditionally, and complain only before it gets used,
near the call to curl_easy_setopt().

>  	if (!strcmp("http.cookiefile", var))
>  		return git_config_pathname(&curl_cookie_file, var, value);
>  	if (!strcmp("http.savecookies", var)) {
> @@ -1203,6 +1220,12 @@ static CURL *get_curl_handle(void)
>  	}
>  	init_curl_proxy_auth(result);
>  
> +#if defined(GIT_CURL_HAVE_CURLOPT_UNIX_SOCKET_PATH) && !defined(NO_UNIX_SOCKETS)
> +	if (curl_unix_socket_path) {
> +		curl_easy_setopt(result, CURLOPT_UNIX_SOCKET_PATH, curl_unix_socket_path);
> +	}
> +#endif

Here, the guard may become more like

		if (curl_unix_socket_path) {
	#ifdef USE_CURLOPT_UNIX_SOCKET_PATH
			curl_easy_setopt(...);
	#elif defined(NO_CURLOPT_UNIX_SOCKET_PATH) || defined(NO_UNIX_SOCKETS)
			warning(_("this build disables the unix-domain-socket feature"));
	#elif
			warning(_("your cURL library is too old"));
	#endif
		}

^ permalink raw reply

* [PATCH v4 6/6] fill_tree_descriptor(): mark error message for translation
From: Johannes Schindelin via GitGitGadget @ 2024-02-23  8:34 UTC (permalink / raw)
  To: git
  Cc: Patrick Steinhardt, Eric Sunshine, Johannes Schindelin,
	Johannes Schindelin
In-Reply-To: <pull.1651.v4.git.1708677266.gitgitgadget@gmail.com>

From: Johannes Schindelin <johannes.schindelin@gmx.de>

There is an error message in that function to report a missing tree; In
contrast to three other, similar error messages, it is not marked for
translation yet.

Mark it for translation, and while at it, make the error message
consistent with the others by enclosing the SHA in parentheses.

This requires a change to t6030 which expects the previous format of the
commit message. Theoretically, this could present problems with existing
scripts that use `git bisect` and parse its output (because Git does not
provide other means for callers to discern between error conditions).
However, this is unlikely to matter in practice because the most common
course of action to deal with fatal corruptions is to report the error
message to the user and exit, rather than trying to do something with
the reported SHA of the missing tree.

Signed-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>
---
 t/t6030-bisect-porcelain.sh | 2 +-
 tree-walk.c                 | 2 +-
 2 files changed, 2 insertions(+), 2 deletions(-)

diff --git a/t/t6030-bisect-porcelain.sh b/t/t6030-bisect-porcelain.sh
index 2a5b7d8379c..58f3d9c675e 100755
--- a/t/t6030-bisect-porcelain.sh
+++ b/t/t6030-bisect-porcelain.sh
@@ -872,7 +872,7 @@ test_expect_success 'broken branch creation' '
 
 echo "" > expected.ok
 cat > expected.missing-tree.default <<EOF
-fatal: unable to read tree $deleted
+fatal: unable to read tree ($deleted)
 EOF
 
 test_expect_success 'bisect fails if tree is broken on start commit' '
diff --git a/tree-walk.c b/tree-walk.c
index b517792ba23..690fa6569bd 100644
--- a/tree-walk.c
+++ b/tree-walk.c
@@ -100,7 +100,7 @@ void *fill_tree_descriptor(struct repository *r,
 	if (oid) {
 		buf = read_object_with_reference(r, oid, OBJ_TREE, &size, NULL);
 		if (!buf)
-			die("unable to read tree %s", oid_to_hex(oid));
+			die(_("unable to read tree (%s)"), oid_to_hex(oid));
 	}
 	init_tree_desc(desc, buf, size);
 	return buf;
-- 
gitgitgadget

^ permalink raw reply related

* [PATCH v4 5/6] cache-tree: avoid an unnecessary check
From: Johannes Schindelin via GitGitGadget @ 2024-02-23  8:34 UTC (permalink / raw)
  To: git
  Cc: Patrick Steinhardt, Eric Sunshine, Johannes Schindelin,
	Johannes Schindelin
In-Reply-To: <pull.1651.v4.git.1708677266.gitgitgadget@gmail.com>

From: Johannes Schindelin <johannes.schindelin@gmx.de>

The first thing the `parse_tree()` function does is to return early if
the tree has already been parsed. Therefore we do not need to guard the
`parse_tree()` call behind a check of that flag.

As of time of writing, there are no other instances of this in Git's
code bases: whenever the `parsed` flag guards a `parse_tree()` call, it
guards more than just that call.

Suggested-by: Patrick Steinhardt <ps@pks.im>
Signed-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>
---
 cache-tree.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/cache-tree.c b/cache-tree.c
index c6508b64a5c..78d6ba92853 100644
--- a/cache-tree.c
+++ b/cache-tree.c
@@ -779,7 +779,7 @@ static void prime_cache_tree_rec(struct repository *r,
 			struct cache_tree_sub *sub;
 			struct tree *subtree = lookup_tree(r, &entry.oid);
 
-			if (!subtree->object.parsed && parse_tree(subtree) < 0)
+			if (parse_tree(subtree) < 0)
 				exit(128);
 			sub = cache_tree_sub(it, entry.path);
 			sub->cache_tree = cache_tree();
-- 
gitgitgadget


^ permalink raw reply related

* [PATCH v4 4/6] Always check `parse_tree*()`'s return value
From: Johannes Schindelin via GitGitGadget @ 2024-02-23  8:34 UTC (permalink / raw)
  To: git
  Cc: Patrick Steinhardt, Eric Sunshine, Johannes Schindelin,
	Johannes Schindelin
In-Reply-To: <pull.1651.v4.git.1708677266.gitgitgadget@gmail.com>

From: Johannes Schindelin <johannes.schindelin@gmx.de>

Otherwise we may easily run into serious crashes: For example, if we run
`init_tree_desc()` directly after a failed `parse_tree()`, we are
accessing uninitialized data or trying to dereference `NULL`.

Note that the `parse_tree()` function already takes care of showing an
error message. The `parse_tree_indirectly()` and
`repo_get_commit_tree()` functions do not, therefore those latter call
sites need to show a useful error message while the former do not.

Signed-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>
---
 builtin/checkout.c   | 19 ++++++++++++++++---
 builtin/clone.c      |  3 ++-
 builtin/commit.c     |  3 ++-
 builtin/merge-tree.c |  6 ++++++
 builtin/read-tree.c  |  3 ++-
 builtin/reset.c      |  4 ++++
 cache-tree.c         |  4 ++--
 merge-ort.c          |  3 +++
 merge-recursive.c    |  3 ++-
 merge.c              |  5 ++++-
 reset.c              |  5 +++++
 sequencer.c          |  4 ++++
 12 files changed, 52 insertions(+), 10 deletions(-)

diff --git a/builtin/checkout.c b/builtin/checkout.c
index f02434bc155..9ab0901d629 100644
--- a/builtin/checkout.c
+++ b/builtin/checkout.c
@@ -707,7 +707,8 @@ static int reset_tree(struct tree *tree, const struct checkout_opts *o,
 	init_checkout_metadata(&opts.meta, info->refname,
 			       info->commit ? &info->commit->object.oid : null_oid(),
 			       NULL);
-	parse_tree(tree);
+	if (parse_tree(tree) < 0)
+		return 128;
 	init_tree_desc(&tree_desc, tree->buffer, tree->size);
 	switch (unpack_trees(1, &tree_desc, &opts)) {
 	case -2:
@@ -786,9 +787,15 @@ static int merge_working_tree(const struct checkout_opts *opts,
 		if (new_branch_info->commit)
 			BUG("'switch --orphan' should never accept a commit as starting point");
 		new_tree = parse_tree_indirect(the_hash_algo->empty_tree);
-	} else
+		if (!new_tree)
+			BUG("unable to read empty tree");
+	} else {
 		new_tree = repo_get_commit_tree(the_repository,
 						new_branch_info->commit);
+		if (!new_tree)
+			return error(_("unable to read tree (%s)"),
+				     oid_to_hex(&new_branch_info->commit->object.oid));
+	}
 	if (opts->discard_changes) {
 		ret = reset_tree(new_tree, opts, 1, writeout_error, new_branch_info);
 		if (ret)
@@ -823,7 +830,8 @@ static int merge_working_tree(const struct checkout_opts *opts,
 				oid_to_hex(old_commit_oid));
 
 		init_tree_desc(&trees[0], tree->buffer, tree->size);
-		parse_tree(new_tree);
+		if (parse_tree(new_tree) < 0)
+			exit(128);
 		tree = new_tree;
 		init_tree_desc(&trees[1], tree->buffer, tree->size);
 
@@ -1239,10 +1247,15 @@ static void setup_new_branch_info_and_source_tree(
 	if (!new_branch_info->commit) {
 		/* not a commit */
 		*source_tree = parse_tree_indirect(rev);
+		if (!*source_tree)
+			die(_("unable to read tree (%s)"), oid_to_hex(rev));
 	} else {
 		parse_commit_or_die(new_branch_info->commit);
 		*source_tree = repo_get_commit_tree(the_repository,
 						    new_branch_info->commit);
+		if (!*source_tree)
+			die(_("unable to read tree (%s)"),
+			    oid_to_hex(&new_branch_info->commit->object.oid));
 	}
 }
 
diff --git a/builtin/clone.c b/builtin/clone.c
index c6357af9498..4410b55be98 100644
--- a/builtin/clone.c
+++ b/builtin/clone.c
@@ -736,7 +736,8 @@ static int checkout(int submodule_progress, int filter_submodules)
 	tree = parse_tree_indirect(&oid);
 	if (!tree)
 		die(_("unable to parse commit %s"), oid_to_hex(&oid));
-	parse_tree(tree);
+	if (parse_tree(tree) < 0)
+		exit(128);
 	init_tree_desc(&t, tree->buffer, tree->size);
 	if (unpack_trees(1, &t, &opts) < 0)
 		die(_("unable to checkout working tree"));
diff --git a/builtin/commit.c b/builtin/commit.c
index 781af2e206c..0723f06de7a 100644
--- a/builtin/commit.c
+++ b/builtin/commit.c
@@ -339,7 +339,8 @@ static void create_base_index(const struct commit *current_head)
 	tree = parse_tree_indirect(&current_head->object.oid);
 	if (!tree)
 		die(_("failed to unpack HEAD tree object"));
-	parse_tree(tree);
+	if (parse_tree(tree) < 0)
+		exit(128);
 	init_tree_desc(&t, tree->buffer, tree->size);
 	if (unpack_trees(1, &t, &opts))
 		exit(128); /* We've already reported the error, finish dying */
diff --git a/builtin/merge-tree.c b/builtin/merge-tree.c
index 2d4ce5b3886..3492a575a6c 100644
--- a/builtin/merge-tree.c
+++ b/builtin/merge-tree.c
@@ -447,12 +447,18 @@ static int real_merge(struct merge_tree_options *o,
 		if (repo_get_oid_treeish(the_repository, merge_base, &base_oid))
 			die(_("could not parse as tree '%s'"), merge_base);
 		base_tree = parse_tree_indirect(&base_oid);
+		if (!base_tree)
+			die(_("unable to read tree (%s)"), oid_to_hex(&base_oid));
 		if (repo_get_oid_treeish(the_repository, branch1, &head_oid))
 			die(_("could not parse as tree '%s'"), branch1);
 		parent1_tree = parse_tree_indirect(&head_oid);
+		if (!parent1_tree)
+			die(_("unable to read tree (%s)"), oid_to_hex(&head_oid));
 		if (repo_get_oid_treeish(the_repository, branch2, &merge_oid))
 			die(_("could not parse as tree '%s'"), branch2);
 		parent2_tree = parse_tree_indirect(&merge_oid);
+		if (!parent2_tree)
+			die(_("unable to read tree (%s)"), oid_to_hex(&merge_oid));
 
 		opt.ancestor = merge_base;
 		merge_incore_nonrecursive(&opt, base_tree, parent1_tree, parent2_tree, &result);
diff --git a/builtin/read-tree.c b/builtin/read-tree.c
index 8196ca9dd85..5923ed36893 100644
--- a/builtin/read-tree.c
+++ b/builtin/read-tree.c
@@ -263,7 +263,8 @@ int cmd_read_tree(int argc, const char **argv, const char *cmd_prefix)
 	cache_tree_free(&the_index.cache_tree);
 	for (i = 0; i < nr_trees; i++) {
 		struct tree *tree = trees[i];
-		parse_tree(tree);
+		if (parse_tree(tree) < 0)
+			return 128;
 		init_tree_desc(t+i, tree->buffer, tree->size);
 	}
 	if (unpack_trees(nr_trees, t, &opts))
diff --git a/builtin/reset.c b/builtin/reset.c
index 4b018d20e3b..fd36fc5bd95 100644
--- a/builtin/reset.c
+++ b/builtin/reset.c
@@ -119,6 +119,10 @@ static int reset_index(const char *ref, const struct object_id *oid, int reset_t
 
 	if (reset_type == MIXED || reset_type == HARD) {
 		tree = parse_tree_indirect(oid);
+		if (!tree) {
+			error(_("unable to read tree (%s)"), oid_to_hex(oid));
+			goto out;
+		}
 		prime_cache_tree(the_repository, the_repository->index, tree);
 	}
 
diff --git a/cache-tree.c b/cache-tree.c
index 641427ed410..c6508b64a5c 100644
--- a/cache-tree.c
+++ b/cache-tree.c
@@ -779,8 +779,8 @@ static void prime_cache_tree_rec(struct repository *r,
 			struct cache_tree_sub *sub;
 			struct tree *subtree = lookup_tree(r, &entry.oid);
 
-			if (!subtree->object.parsed)
-				parse_tree(subtree);
+			if (!subtree->object.parsed && parse_tree(subtree) < 0)
+				exit(128);
 			sub = cache_tree_sub(it, entry.path);
 			sub->cache_tree = cache_tree();
 
diff --git a/merge-ort.c b/merge-ort.c
index 79d9e18f63d..910ba38ff05 100644
--- a/merge-ort.c
+++ b/merge-ort.c
@@ -4983,6 +4983,9 @@ static void merge_ort_nonrecursive_internal(struct merge_options *opt,
 
 	if (result->clean >= 0) {
 		result->tree = parse_tree_indirect(&working_tree_oid);
+		if (!result->tree)
+			die(_("unable to read tree (%s)"),
+			    oid_to_hex(&working_tree_oid));
 		/* existence of conflicted entries implies unclean */
 		result->clean &= strmap_empty(&opt->priv->conflicted);
 	}
diff --git a/merge-recursive.c b/merge-recursive.c
index e3beb0801b1..10d41bfd487 100644
--- a/merge-recursive.c
+++ b/merge-recursive.c
@@ -410,7 +410,8 @@ static inline int merge_detect_rename(struct merge_options *opt)
 
 static void init_tree_desc_from_tree(struct tree_desc *desc, struct tree *tree)
 {
-	parse_tree(tree);
+	if (parse_tree(tree) < 0)
+		exit(128);
 	init_tree_desc(desc, tree->buffer, tree->size);
 }
 
diff --git a/merge.c b/merge.c
index b60925459c2..14a7325859d 100644
--- a/merge.c
+++ b/merge.c
@@ -80,7 +80,10 @@ int checkout_fast_forward(struct repository *r,
 		return -1;
 	}
 	for (i = 0; i < nr_trees; i++) {
-		parse_tree(trees[i]);
+		if (parse_tree(trees[i]) < 0) {
+			rollback_lock_file(&lock_file);
+			return -1;
+		}
 		init_tree_desc(t+i, trees[i]->buffer, trees[i]->size);
 	}
 
diff --git a/reset.c b/reset.c
index 48da0adf851..080bcb6d656 100644
--- a/reset.c
+++ b/reset.c
@@ -158,6 +158,11 @@ int reset_head(struct repository *r, const struct reset_head_opts *opts)
 	}
 
 	tree = parse_tree_indirect(oid);
+	if (!tree) {
+		ret = error(_("unable to read tree (%s)"), oid_to_hex(oid));
+		goto leave_reset_head;
+	}
+
 	prime_cache_tree(r, r->index, tree);
 
 	if (write_locked_index(r->index, &lock, COMMIT_LOCK) < 0) {
diff --git a/sequencer.c b/sequencer.c
index d584cac8ed9..33d12b2ffd1 100644
--- a/sequencer.c
+++ b/sequencer.c
@@ -715,6 +715,8 @@ static int do_recursive_merge(struct repository *r,
 	o.show_rename_progress = 1;
 
 	head_tree = parse_tree_indirect(head);
+	if (!head_tree)
+		return error(_("unable to read tree (%s)"), oid_to_hex(head));
 	next_tree = next ? repo_get_commit_tree(r, next) : empty_tree(r);
 	base_tree = base ? repo_get_commit_tree(r, base) : empty_tree(r);
 
@@ -3887,6 +3889,8 @@ static int do_reset(struct repository *r,
 	}
 
 	tree = parse_tree_indirect(&oid);
+	if (!tree)
+		return error(_("unable to read tree (%s)"), oid_to_hex(&oid));
 	prime_cache_tree(r, r->index, tree);
 
 	if (write_locked_index(r->index, &lock, COMMIT_LOCK) < 0)
-- 
gitgitgadget


^ permalink raw reply related

* [PATCH v4 3/6] t4301: verify that merge-tree fails on missing blob objects
From: Johannes Schindelin via GitGitGadget @ 2024-02-23  8:34 UTC (permalink / raw)
  To: git
  Cc: Patrick Steinhardt, Eric Sunshine, Johannes Schindelin,
	Johannes Schindelin
In-Reply-To: <pull.1651.v4.git.1708677266.gitgitgadget@gmail.com>

From: Johannes Schindelin <johannes.schindelin@gmx.de>

We just fixed a problem where `merge-tree` would not fail on missing
tree objects. Let's ensure that that problem does not occur with blob
objects (and won't, in the future, either).

Signed-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>
---
 t/t4301-merge-tree-write-tree.sh | 16 ++++++++++++++++
 1 file changed, 16 insertions(+)

diff --git a/t/t4301-merge-tree-write-tree.sh b/t/t4301-merge-tree-write-tree.sh
index 908c9b540c8..d4463a45706 100755
--- a/t/t4301-merge-tree-write-tree.sh
+++ b/t/t4301-merge-tree-write-tree.sh
@@ -962,4 +962,20 @@ test_expect_success 'error out on missing tree objects' '
 	test_must_be_empty actual
 '
 
+test_expect_success 'error out on missing blob objects' '
+	echo 1 | git hash-object -w --stdin >blob1 &&
+	echo 2 | git hash-object -w --stdin >blob2 &&
+	echo 3 | git hash-object -w --stdin >blob3 &&
+	printf "100644 blob $(cat blob1)\tblob\n" | git mktree >tree1 &&
+	printf "100644 blob $(cat blob2)\tblob\n" | git mktree >tree2 &&
+	printf "100644 blob $(cat blob3)\tblob\n" | git mktree >tree3 &&
+	git init --bare missing-blob.git &&
+	cat blob1 blob3 tree1 tree2 tree3 |
+	git pack-objects missing-blob.git/objects/pack/side1-whatever-is-missing &&
+	test_must_fail git --git-dir=missing-blob.git >actual 2>err \
+		merge-tree --merge-base=$(cat tree1) $(cat tree2) $(cat tree3) &&
+	test_grep "unable to read blob object $(cat blob2)" err &&
+	test_must_be_empty actual
+'
+
 test_done
-- 
gitgitgadget


^ permalink raw reply related

* [PATCH v4 2/6] merge-ort: do check `parse_tree()`'s return value
From: Johannes Schindelin via GitGitGadget @ 2024-02-23  8:34 UTC (permalink / raw)
  To: git
  Cc: Patrick Steinhardt, Eric Sunshine, Johannes Schindelin,
	Johannes Schindelin
In-Reply-To: <pull.1651.v4.git.1708677266.gitgitgadget@gmail.com>

From: Johannes Schindelin <johannes.schindelin@gmx.de>

The previous commit fixed a bug where a missing tree was reported, but
not treated as an error.

This patch addresses the same issue for the remaining two callers of
`parse_tree()`.

This change is not accompanied by a regression test because the code in
question is only reached at the `checkout` stage, i.e. after the merge
has happened (and therefore the tree objects could only be missing if
the disk had gone bad in that short time window, or something similarly
tricky to recreate in the test suite).

Signed-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>
---
 merge-ort.c | 6 ++++--
 1 file changed, 4 insertions(+), 2 deletions(-)

diff --git a/merge-ort.c b/merge-ort.c
index c37fc035f13..79d9e18f63d 100644
--- a/merge-ort.c
+++ b/merge-ort.c
@@ -4379,9 +4379,11 @@ static int checkout(struct merge_options *opt,
 	unpack_opts.verbose_update = (opt->verbosity > 2);
 	unpack_opts.fn = twoway_merge;
 	unpack_opts.preserve_ignored = 0; /* FIXME: !opts->overwrite_ignore */
-	parse_tree(prev);
+	if (parse_tree(prev) < 0)
+		return -1;
 	init_tree_desc(&trees[0], prev->buffer, prev->size);
-	parse_tree(next);
+	if (parse_tree(next) < 0)
+		return -1;
 	init_tree_desc(&trees[1], next->buffer, next->size);
 
 	ret = unpack_trees(2, trees, &unpack_opts);
-- 
gitgitgadget


^ permalink raw reply related

* [PATCH v4 1/6] merge-tree: fail with a non-zero exit code on missing tree objects
From: Johannes Schindelin via GitGitGadget @ 2024-02-23  8:34 UTC (permalink / raw)
  To: git
  Cc: Patrick Steinhardt, Eric Sunshine, Johannes Schindelin,
	Johannes Schindelin
In-Reply-To: <pull.1651.v4.git.1708677266.gitgitgadget@gmail.com>

From: Johannes Schindelin <johannes.schindelin@gmx.de>

When `git merge-tree` encounters a missing tree object, it should error
out and not continue quietly as if nothing had happened.

However, as of time of writing, `git merge-tree` _does_ continue, and
then offers the empty tree as result.

Let's fix this.

Signed-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>
---
 merge-ort.c                      |  7 ++++---
 t/t4301-merge-tree-write-tree.sh | 11 +++++++++++
 2 files changed, 15 insertions(+), 3 deletions(-)

diff --git a/merge-ort.c b/merge-ort.c
index 6491070d965..c37fc035f13 100644
--- a/merge-ort.c
+++ b/merge-ort.c
@@ -1659,9 +1659,10 @@ static int collect_merge_info(struct merge_options *opt,
 	info.data = opt;
 	info.show_all_errors = 1;
 
-	parse_tree(merge_base);
-	parse_tree(side1);
-	parse_tree(side2);
+	if (parse_tree(merge_base) < 0 ||
+	    parse_tree(side1) < 0 ||
+	    parse_tree(side2) < 0)
+		return -1;
 	init_tree_desc(t + 0, merge_base->buffer, merge_base->size);
 	init_tree_desc(t + 1, side1->buffer, side1->size);
 	init_tree_desc(t + 2, side2->buffer, side2->size);
diff --git a/t/t4301-merge-tree-write-tree.sh b/t/t4301-merge-tree-write-tree.sh
index 7d0fa74da74..908c9b540c8 100755
--- a/t/t4301-merge-tree-write-tree.sh
+++ b/t/t4301-merge-tree-write-tree.sh
@@ -951,4 +951,15 @@ test_expect_success '--merge-base with tree OIDs' '
 	test_cmp with-commits with-trees
 '
 
+test_expect_success 'error out on missing tree objects' '
+	git init --bare missing-tree.git &&
+	git rev-list side3 >list &&
+	git rev-parse side3^: >>list &&
+	git pack-objects missing-tree.git/objects/pack/side3-tree-is-missing <list &&
+	side3=$(git rev-parse side3) &&
+	test_must_fail git --git-dir=missing-tree.git merge-tree $side3^ $side3 >actual 2>err &&
+	test_grep "Could not read $(git rev-parse $side3:)" err &&
+	test_must_be_empty actual
+'
+
 test_done
-- 
gitgitgadget


^ permalink raw reply related

* [PATCH v4 0/6] merge-tree: handle missing objects correctly
From: Johannes Schindelin via GitGitGadget @ 2024-02-23  8:34 UTC (permalink / raw)
  To: git; +Cc: Patrick Steinhardt, Eric Sunshine, Johannes Schindelin
In-Reply-To: <pull.1651.v3.git.1708612605.gitgitgadget@gmail.com>

I recently looked into issues where git merge-tree calls returned bogus data
(in one instance returning an empty tree for non-empty merge parents). By
the time I had a look at the corresponding repository, the issue was no
longer reproducible, but a closer look at the code combined with some manual
experimenting turned up the fact that missing tree objects aren't handled as
errors by git merge-tree.

While at it, I added a commit on top that tries to catch all remaining
unchecked parse_tree() calls.

This patch series is based on 5f43cf5b2e4 (merge-tree: accept 3 trees as
arguments, 2024-01-28) (the original tip commit of js/merge-tree-3-trees)
because I introduced three unchecked parse_tree() calls in that topic.

Changes since v3:

 * Aligned the translated error messages with pre-existing ones (sorry, I
   forgot to make that change in v2!).
 * Added a new commit at the end to mark the one error message for
   translation which I had imitated, after making it consistent with the
   remaining "unable to read tree" error messages.

Changes since v2:

 * Fixed the new "missing tree object" test case in t4301 that succeeded for
   the wrong reason.
 * Adjusted the new "missing blob object" test case to avoid succeeding for
   the wrong reason.
 * Simplified the "missing blob object" test case.

Changes since v1:

 * Simplified the test case, avoiding a subshell and a pipe in the process.
 * Added a patch to remove a superfluous subtree->object.parsed guard around
   a parse_tree(subtree) call.

Johannes Schindelin (6):
  merge-tree: fail with a non-zero exit code on missing tree objects
  merge-ort: do check `parse_tree()`'s return value
  t4301: verify that merge-tree fails on missing blob objects
  Always check `parse_tree*()`'s return value
  cache-tree: avoid an unnecessary check
  fill_tree_descriptor(): mark error message for translation

 builtin/checkout.c               | 19 ++++++++++++++++---
 builtin/clone.c                  |  3 ++-
 builtin/commit.c                 |  3 ++-
 builtin/merge-tree.c             |  6 ++++++
 builtin/read-tree.c              |  3 ++-
 builtin/reset.c                  |  4 ++++
 cache-tree.c                     |  4 ++--
 merge-ort.c                      | 16 +++++++++++-----
 merge-recursive.c                |  3 ++-
 merge.c                          |  5 ++++-
 reset.c                          |  5 +++++
 sequencer.c                      |  4 ++++
 t/t4301-merge-tree-write-tree.sh | 27 +++++++++++++++++++++++++++
 t/t6030-bisect-porcelain.sh      |  2 +-
 tree-walk.c                      |  2 +-
 15 files changed, 89 insertions(+), 17 deletions(-)


base-commit: 5f43cf5b2e4b68386d3774bce880b0f74d801635
Published-As: https://github.com/gitgitgadget/git/releases/tag/pr-1651%2Fdscho%2Fmerge-tree-and-missing-objects-v4
Fetch-It-Via: git fetch https://github.com/gitgitgadget/git pr-1651/dscho/merge-tree-and-missing-objects-v4
Pull-Request: https://github.com/gitgitgadget/git/pull/1651

Range-diff vs v3:

 1:  11b9cd8c5da = 1:  11b9cd8c5da merge-tree: fail with a non-zero exit code on missing tree objects
 2:  f01f4eb011b = 2:  f01f4eb011b merge-ort: do check `parse_tree()`'s return value
 3:  e82fdf7fbcb = 3:  e82fdf7fbcb t4301: verify that merge-tree fails on missing blob objects
 4:  9e4dc94ef03 ! 4:  5942c27f439 Always check `parse_tree*()`'s return value
     @@ builtin/checkout.c: static int merge_working_tree(const struct checkout_opts *op
       		new_tree = repo_get_commit_tree(the_repository,
       						new_branch_info->commit);
      +		if (!new_tree)
     -+			return error(_("unable to read tree %s"),
     ++			return error(_("unable to read tree (%s)"),
      +				     oid_to_hex(&new_branch_info->commit->object.oid));
      +	}
       	if (opts->discard_changes) {
     @@ builtin/checkout.c: static void setup_new_branch_info_and_source_tree(
       		/* not a commit */
       		*source_tree = parse_tree_indirect(rev);
      +		if (!*source_tree)
     -+			die(_("unable to read tree %s"), oid_to_hex(rev));
     ++			die(_("unable to read tree (%s)"), oid_to_hex(rev));
       	} else {
       		parse_commit_or_die(new_branch_info->commit);
       		*source_tree = repo_get_commit_tree(the_repository,
       						    new_branch_info->commit);
      +		if (!*source_tree)
     -+			die(_("unable to read tree %s"),
     ++			die(_("unable to read tree (%s)"),
      +			    oid_to_hex(&new_branch_info->commit->object.oid));
       	}
       }
     @@ builtin/merge-tree.c: static int real_merge(struct merge_tree_options *o,
       			die(_("could not parse as tree '%s'"), merge_base);
       		base_tree = parse_tree_indirect(&base_oid);
      +		if (!base_tree)
     -+			die(_("unable to read tree %s"), oid_to_hex(&base_oid));
     ++			die(_("unable to read tree (%s)"), oid_to_hex(&base_oid));
       		if (repo_get_oid_treeish(the_repository, branch1, &head_oid))
       			die(_("could not parse as tree '%s'"), branch1);
       		parent1_tree = parse_tree_indirect(&head_oid);
      +		if (!parent1_tree)
     -+			die(_("unable to read tree %s"), oid_to_hex(&head_oid));
     ++			die(_("unable to read tree (%s)"), oid_to_hex(&head_oid));
       		if (repo_get_oid_treeish(the_repository, branch2, &merge_oid))
       			die(_("could not parse as tree '%s'"), branch2);
       		parent2_tree = parse_tree_indirect(&merge_oid);
      +		if (!parent2_tree)
     -+			die(_("unable to read tree %s"), oid_to_hex(&merge_oid));
     ++			die(_("unable to read tree (%s)"), oid_to_hex(&merge_oid));
       
       		opt.ancestor = merge_base;
       		merge_incore_nonrecursive(&opt, base_tree, parent1_tree, parent2_tree, &result);
     @@ builtin/reset.c: static int reset_index(const char *ref, const struct object_id
       	if (reset_type == MIXED || reset_type == HARD) {
       		tree = parse_tree_indirect(oid);
      +		if (!tree) {
     -+			error(_("unable to read tree %s"), oid_to_hex(oid));
     ++			error(_("unable to read tree (%s)"), oid_to_hex(oid));
      +			goto out;
      +		}
       		prime_cache_tree(the_repository, the_repository->index, tree);
     @@ merge-ort.c: static void merge_ort_nonrecursive_internal(struct merge_options *o
       	if (result->clean >= 0) {
       		result->tree = parse_tree_indirect(&working_tree_oid);
      +		if (!result->tree)
     -+			die(_("unable to read tree %s"),
     ++			die(_("unable to read tree (%s)"),
      +			    oid_to_hex(&working_tree_oid));
       		/* existence of conflicted entries implies unclean */
       		result->clean &= strmap_empty(&opt->priv->conflicted);
     @@ reset.c: int reset_head(struct repository *r, const struct reset_head_opts *opts
       
       	tree = parse_tree_indirect(oid);
      +	if (!tree) {
     -+		ret = error(_("unable to read tree %s"), oid_to_hex(oid));
     ++		ret = error(_("unable to read tree (%s)"), oid_to_hex(oid));
      +		goto leave_reset_head;
      +	}
      +
     @@ sequencer.c: static int do_recursive_merge(struct repository *r,
       
       	head_tree = parse_tree_indirect(head);
      +	if (!head_tree)
     -+		return error(_("unable to read tree %s"), oid_to_hex(head));
     ++		return error(_("unable to read tree (%s)"), oid_to_hex(head));
       	next_tree = next ? repo_get_commit_tree(r, next) : empty_tree(r);
       	base_tree = base ? repo_get_commit_tree(r, base) : empty_tree(r);
       
     @@ sequencer.c: static int do_reset(struct repository *r,
       
       	tree = parse_tree_indirect(&oid);
      +	if (!tree)
     -+		return error(_("unable to read tree %s"), oid_to_hex(&oid));
     ++		return error(_("unable to read tree (%s)"), oid_to_hex(&oid));
       	prime_cache_tree(r, r->index, tree);
       
       	if (write_locked_index(r->index, &lock, COMMIT_LOCK) < 0)
 5:  91dc4ccd04e = 5:  7e5e84a4e7c cache-tree: avoid an unnecessary check
 -:  ----------- > 6:  ee2fcee5a10 fill_tree_descriptor(): mark error message for translation

-- 
gitgitgadget

^ permalink raw reply


This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox