Subject: Re: [PATCH 10/12] merge-tree: provide easy access to `ls-files -u` style info

From: Ævar Arnfjörð Bjarmason <[email-masked]>
Date: Mon, 24 Jan 2022 11:06:48 +0100

On Sat, Jan 22 2022, Elijah Newren via GitGitGadget wrote:

> From: Elijah Newren <[email-masked]>
>
> Much like `git merge` updates the index with information of the form
>     (mode, oid, stage, name)
> provide this output for conflicted files for merge-tree as well.
> Provide an --exclude-oids-and-modes option for users to exclude the
> mode, oid, and stage and only get the list of conflicted filenames.
> [...]
> +--exclude-oids-and-modes::
> +	Instead of writing a list of (mode, oid, stage, path) tuples
> +	to output for conflicted files, just provide a list of
> +	filenames with conflicts.
> +
> [...]
> -This is a sequence of lines containing a filename on each line, quoted
> -as explained for the configuration variable `core.quotePath` (see
> -linkgit:git-config[1]).
> +This is a sequence of lines with the format
> +
> +	<mode> <object> <stage> <filename>
> +
> +The filename will be quoted as explained for the configuration
> +variable `core.quotePath` (see linkgit:git-config[1]).  However, if
> +the `--exclude-oids-and-modes` option is passed, the mode, object, and
> +stage will be omitted.
>  
>  Informational messages
>  ~~~~~~~~~~~~~~~~~~~~~~
>  
>  This always starts with a blank line to separate it from the previous
> -section, and then has free-form messages about the merge, such as:
> +sections, and then has free-form messages about the merge, such as:
>  
>    * "Auto-merging <file>"
>    * "CONFLICT (rename/delete): <oldfile> renamed...but deleted in..."
> @@ -113,6 +123,14 @@ plumbing commands since the possibility of merge conflicts give it a
>  much higher chance of the command not succeeding (and NEWTREE containing
>  a bunch of stuff other than just a toplevel tree).
>  
> +git-merge-tree was written to provide users with the same information
> +that they'd have access to if using `git merge`:
> +  * what would be written to the working tree (the <OID of toplevel tree>)
> +  * the higher order stages that would be written to the index (the
> +    <Conflicted file info>)
> +  * any messages that would have been printed to stdout (the <Informational
> +    messages>)
> +
>  GIT
>  ---
>  Part of the linkgit:git[1] suite
> diff --git a/builtin/merge-tree.c b/builtin/merge-tree.c
> index d8eeeb3f306..7aa7f9fd54a 100644
> --- a/builtin/merge-tree.c
> +++ b/builtin/merge-tree.c
> @@ -395,6 +395,7 @@ struct merge_tree_options {
>  	int real;
>  	int trivial;
>  	int show_messages;
> +	int exclude_oids_and_modes;
>  };
>  
>  static int real_merge(struct merge_tree_options *o,
> @@ -461,7 +462,11 @@ static int real_merge(struct merge_tree_options *o,
>  		merge_get_conflicted_files(&result, &conflicted_files);
>  		for (i = 0; i < conflicted_files.nr; i++) {
>  			const char *name = conflicted_files.items[i].string;
> -			if (last && !strcmp(last, name))
> +			struct stage_info *c = conflicted_files.items[i].util;
> +			if (!o->exclude_oids_and_modes)
> +				printf("%06o %s %d\t",
> +				       c->mode, oid_to_hex(&c->oid), c->stage);
> +			else if (last && !strcmp(last, name))
>  				continue;
>  			write_name_quoted_relative(
>  				name, prefix, stdout, line_termination);
> @@ -495,6 +500,10 @@ int cmd_merge_tree(int argc, const char **argv, const char *prefix)
>  			 N_("do a trivial merge only")),
>  		OPT_BOOL(0, "messages", &o.show_messages,
>  			 N_("also show informational/conflict messages")),
> +		OPT_BOOL_F(0, "exclude-oids-and-modes",
> +			   &o.exclude_oids_and_modes,
> +			   N_("list conflicted files without oids and modes"),
> +			   PARSE_OPT_NONEG),
>  		OPT_END()
>  	};

Perhaps this really is the last formatting information anyone will want,
but with a default of "<mode> <object> <stage> <filename>" being made
"<stage> <filename>" with --exclude-oids-and-modes perhaps we'll want
--exclude-all-except-filename etc. later.

It seems a lot simpler for new code to just support a --conflict-format
option, lifting some code from the in-flight
https://lore.kernel.org/git/db[email-masked]/

I.e. that inner loop becomes a slightly more verbose strbuf_expand(),
but it's all easy boilerplate code.

Then we just feed "%(objectmode) %(objectname) %(objectstage)
%(filename)" into it by default, and allow the user to customize it.