Git development
 help / color / mirror / Atom feed
* Re: [PATCH] doc: add missing --message long option to merge docs
From: Junio C Hamano @ 2026-05-29  5:02 UTC (permalink / raw)
  To: Brandon Dong via GitGitGadget; +Cc: git, Brandon Dong
In-Reply-To: <pull.2315.git.git.1780019726297.gitgitgadget@gmail.com>

"Brandon Dong via GitGitGadget" <gitgitgadget@gmail.com> writes:

> From: Brandon <brandondong96@gmail.com>

As you identify yourself as "Brandon Dong" on the Signed-off-by line
below, please match this in-body From: line with it.

> Include mention of --message flag in merge docs to match what is
> accepted (builtin/merge.c) and to make it consistent with the git
> commit docs.
>
> Signed-off-by: Brandon Dong <brandondong96@gmail.com>
> ---
>     doc: add missing --message long option to merge docs
>
> Published-As: https://github.com/gitgitgadget/git/releases/tag/pr-git-2315%2Fbrandondong%2Fmerge_message_docs-v1
> Fetch-It-Via: git fetch https://github.com/gitgitgadget/git pr-git-2315/brandondong/merge_message_docs-v1
> Pull-Request: https://github.com/git/git/pull/2315
>
>  Documentation/git-merge.adoc | 1 +
>  1 file changed, 1 insertion(+)
>
> diff --git a/Documentation/git-merge.adoc b/Documentation/git-merge.adoc
> index a055384ad6..6581f4c69c 100644
> --- a/Documentation/git-merge.adoc
> +++ b/Documentation/git-merge.adoc
> @@ -68,6 +68,7 @@ OPTIONS
>  include::merge-options.adoc[]
>  
>  `-m <msg>`::
> +`--message=<msg>`::
>  	Set the commit message to be used for the merge commit (in
>  	case one is created).
>  +

Hmph.  This is still not consistent with "git merge -h" output has,
which seems to accept --[no-]message as well.

It is not exactly your fault, but there are a few options other than
this one that support optional [no-] and they are not documented as
such, even though they appear in "git merge -h".  "git merge -m foo
--no-message other" behaves as if "GIT_EDITOR=: git merge other" was
run, it seems.

^ permalink raw reply

* git hook question
From: Wesley Schwengle @ 2026-05-29  5:01 UTC (permalink / raw)
  To: Git maillinglist


Hello,

I added the following to my gitconfig:

hook.npm-test.event=pre-push
hook.npm-test.command=npm run test

This works well when I run `git hook run pre-push' but when using `git 
push' this breaks a little because it adds the remote and the location, 
as seen via `GIT_TRACE=1 git push origin':

00:46:53.714453 run-command.c:673       trace: run_command: 'npm run 
test' origin git@gitlab.com:waterkip/mything.git
00:46:53.714458 run-command.c:765       trace: start_command: /bin/sh -c 
'npm run test "$@"' 'npm run test' origin 
git@gitlab.com:waterkip/mything.git

I understand the why, normally pre-push gets `<local-ref> SP 
<local-object-name> SP <remote-ref> SP <remote-object-name> LF'. This 
has a similar feel, albeit a different syntax. The difference feels like 
a minor bug, but not one I'm worried about at this moment: you would 
expect it to get the same arguments/parameters as the regular pre-push 
hook. But I digress.

My actual question is: Is there a way to tell the hook "Don't give me 
arguments, just run the plain command that is defined". I looked in `man 
1 git-hook', but I was unable to find something that looks like it.


Cheers,
Wesley

-- 
Wesley Schwengle


^ permalink raw reply

* [PATCH] doc: add missing --message long option to merge docs
From: Brandon Dong via GitGitGadget @ 2026-05-29  1:55 UTC (permalink / raw)
  To: git; +Cc: Brandon Dong, Brandon

From: Brandon <brandondong96@gmail.com>

Include mention of --message flag in merge docs to match what is
accepted (builtin/merge.c) and to make it consistent with the git
commit docs.

Signed-off-by: Brandon Dong <brandondong96@gmail.com>
---
    doc: add missing --message long option to merge docs

Published-As: https://github.com/gitgitgadget/git/releases/tag/pr-git-2315%2Fbrandondong%2Fmerge_message_docs-v1
Fetch-It-Via: git fetch https://github.com/gitgitgadget/git pr-git-2315/brandondong/merge_message_docs-v1
Pull-Request: https://github.com/git/git/pull/2315

 Documentation/git-merge.adoc | 1 +
 1 file changed, 1 insertion(+)

diff --git a/Documentation/git-merge.adoc b/Documentation/git-merge.adoc
index a055384ad6..6581f4c69c 100644
--- a/Documentation/git-merge.adoc
+++ b/Documentation/git-merge.adoc
@@ -68,6 +68,7 @@ OPTIONS
 include::merge-options.adoc[]
 
 `-m <msg>`::
+`--message=<msg>`::
 	Set the commit message to be used for the merge commit (in
 	case one is created).
 +

base-commit: c69baaf57ba26cf117c2b6793802877f19738b0d
-- 
gitgitgadget

^ permalink raw reply related

* Re: [PATCH v2 3/4] diff: add long-running diff process via diff.<driver>.process
From: Michael Montalbo @ 2026-05-29  0:55 UTC (permalink / raw)
  To: Junio C Hamano; +Cc: Michael Montalbo via GitGitGadget, git
In-Reply-To: <xmqqjysqnbxu.fsf@gitster.g>

On Mon, May 25, 2026 at 7:26 PM Junio C Hamano <gitster@pobox.com> wrote:
>
> "Michael Montalbo via GitGitGadget" <gitgitgadget@gmail.com> writes:
>
> > Zero hunks with status=success means the tool considers the
> > files equivalent.  Git skips diff output for that file.
>
> Is "zero hunk" a common word or some random string you invented?  If
> the latter, which is I am assuming it to be, you should define what
> it means at/before the first use.  Here in the proposed log message,
> and ...
>
> >
> > Signed-off-by: Michael Montalbo <mmontalbo@gmail.com>
> > ---
> >  Documentation/config/diff.adoc   |   8 +
> >  Documentation/gitattributes.adoc |  40 ++++
> >  Makefile                         |   1 +
> >  diff-process.c                   | 206 +++++++++++++++++++
> >  diff-process.h                   |  28 +++
> >  diff.c                           |  23 +++
> >  t/.gitattributes                 |   1 +
> >  t/t4080-diff-process.sh          | 338 +++++++++++++++++++++++++++++++
> >  8 files changed, 645 insertions(+)
> >  create mode 100644 diff-process.c
> >  create mode 100644 diff-process.h
> >  create mode 100755 t/t4080-diff-process.sh
> >
> > diff --git a/Documentation/config/diff.adoc b/Documentation/config/diff.adoc
> > index 1135a62a0a..4ab5f60df6 100644
> > --- a/Documentation/config/diff.adoc
> > +++ b/Documentation/config/diff.adoc
> > @@ -218,6 +218,14 @@ endif::git-diff[]
> >       Set this option to `true` to make the diff driver cache the text
> >       conversion outputs.  See linkgit:gitattributes[5] for details.
> >
> > +`diff.<driver>.process`::
> > +     The command to run as a long-running diff process.
> > +     The tool communicates via the pkt-line protocol and returns
> > +     hunks that are fed into Git's diff and blame pipelines.
> > +     If the tool returns zero hunks, the file is treated as
> > +     unchanged for both diff output and blame attribution.
> > +     See linkgit:gitattributes[5] for details.
>
> ... also here.
>
> I do not know if you mean "the tool returns no hunks" (there is no
> "hunk <old_start> <old_count> <new_start> <new_count>" line passed
> from the tool over the protocol) or "the tool returns zero-hunk"
> (there is a special "zero-hunk" message to signal this particular
> condition sent over the protocol), and this description does not
> quite help disambiguating between the two.
>
> If the former, then avoid "zero hunks" as it sounds like a noun with
> special meaning.  Yes, we can say "tool returns one hunk", "tool
> returns 31 hunks", etc., so "tool returns zero hunks" may logically
> be correct, but "when the tool returns no hunks with status=success"
> is much less confusing, I think.

Yes, "zero hunks" was my own invention and I see why it's confusing. Will
update the messaging to use "no hunks" instead and do a broader sweep of
the documentation to clarify the protocol and expected tool behavior.

^ permalink raw reply

* Re: [PATCH v2 3/4] diff: add long-running diff process via diff.<driver>.process
From: Michael Montalbo @ 2026-05-29  0:51 UTC (permalink / raw)
  To: Junio C Hamano; +Cc: Michael Montalbo via GitGitGadget, git
In-Reply-To: <xmqqpl2jlyr3.fsf@gitster.g>

On Mon, May 25, 2026 at 6:56 PM Junio C Hamano <gitster@pobox.com> wrote:
>
> "Michael Montalbo via GitGitGadget" <gitgitgadget@gmail.com> writes:
>
> > +struct diff_subprocess {
> > +     struct subprocess_entry subprocess;
> > +     unsigned int supported_capabilities;
> > +};
> > +
> > +static int subprocess_map_initialized;
> > +static struct hashmap subprocess_map;
>
> Can we avoid introducing new global variables like these?  Would
> "struct userdiff_driver" or "struct diff_options" be a good place to
> hang this hashmap, perhaps?
>

Will clean this up.

> > +static int send_file_content(int fd, const char *buf, long size)
> > +{
> > +     int ret;
> > +
> > +     if (size > 0)
> > +             ret = write_packetized_from_buf_no_flush(buf, size, fd);
> > +     else
> > +             ret = 0;
>
> Shouldn't "size == -24" be flagged as an invalid input?
>

Will fix and do a broader audit of input validation and bounds checking.

> > +     if (ret)
> > +             return ret;
> > +     return packet_flush_gently(fd);
> > +}
>
> > +static int parse_hunk_line(const char *line, struct xdl_hunk *hunk)
> > +{
> > +...
> > +}
>
> This gives a silent error diagnosis, which is good for a lower level
> helper.
>
> > +int diff_process_get_hunks(struct userdiff_driver *drv,
> > +                        const char *path,
> > +                        const char *old_buf, long old_size,
> > +                        const char *new_buf, long new_size,
> > +                        struct xdl_hunk **hunks_out,
> > +                        size_t *nr_hunks_out)
> > +{
> > +     struct diff_subprocess *backend;
> > +     struct child_process *process;
> > +     int fd_in, fd_out;
> > +     struct strbuf status = STRBUF_INIT;
> > +     struct xdl_hunk *hunks = NULL;
> > +     struct xdl_hunk hunk;
> > +     size_t nr_hunks = 0, alloc_hunks = 0;
> > +     int len;
> > +     char *line;
> > +
> > +     if (!drv || !drv->process)
> > +             return -1;
>
> A driver that does not define process is not an error; it is
> perfectly normal in the current world order where nobody has such an
> external process and even fi this patch lands, external processes
> are optional.  So here "return -1" does not mean an error, and
> silent return is perfectly fine.
>
> > +     backend = find_or_start_process(drv->process);
> > +     if (!backend)
> > +             return -1;
>
> This is probably an error; the user specified drv->process, we
> either tried to find or start the process and failed.  Isn't it an
> event that deserves to be reported in an error message?
>
> > +     if (!(backend->supported_capabilities & CAP_HUNKS))
> > +             return -1;
>
> Backend started, but the "hunks" feature is not supported.  Perhaps
> in a year or two, this external process protocol may have become so
> popular that it gained more capabilities, possibly making get_hunks
> obsolete.  We may be looking at such an external process that uses
> other capabilities but not this one.  This is not an error, so
> silent return is perfectly fine.
>
> > +     process = subprocess_get_child_process(&backend->subprocess);
> > +     fd_in = process->in;
> > +     fd_out = process->out;
> > +
> > +     /* Send request */
> > +     if (packet_write_fmt_gently(fd_in, "command=hunks\n") ||
> > +         packet_write_fmt_gently(fd_in, "pathname=%s\n", path) ||
> > +         packet_flush_gently(fd_in))
> > +             goto error;
> > +
> > +     /* Send old file content */
> > +     if (send_file_content(fd_in, old_buf, old_size))
> > +             goto error;
> > +
> > +     /* Send new file content */
> > +     if (send_file_content(fd_in, new_buf, new_size))
> > +             goto error;
> > +
> > +     /* Read hunks until flush packet */
> > +     while ((len = packet_read_line_gently(fd_out, NULL, &line)) >= 0 &&
> > +            line) {
> > +             if (parse_hunk_line(line, &hunk) < 0)
> > +                     goto error;
> > +             ALLOC_GROW(hunks, nr_hunks + 1, alloc_hunks);
> > +             hunks[nr_hunks++] = hunk;
> > +     }
> > +     if (len < 0)
> > +             goto error;
> > +
> > +     /* Read status */
> > +     if (subprocess_read_status(fd_out, &status))
> > +             goto error;
> > +
> > +     if (strcmp(status.buf, "success")) {
> > +             if (!strcmp(status.buf, "abort"))
> > +                     backend->supported_capabilities &= ~CAP_HUNKS;
> > +             goto error;
> > +     }
> > +
> > +     *hunks_out = hunks;
> > +     *nr_hunks_out = nr_hunks;
> > +     strbuf_release(&status);
> > +     return 0;
> > +
> > +error:
>
> All exceptions that lead here look like events that should be
> reported to the end-user.
>

Agreed on all points. I will restructure things so errors are flagged when
appropriate (i.e., user specified a process but one was not found / couldn't
start and exceptions) and non-errors are treated as they should be.

> > +     free(hunks);
> > +     strbuf_release(&status);
> > +     return -1;
> > +}
>
> > +/*
> > + * Query a diff process for hunks describing the changes
> > + * between old_buf and new_buf.
> > + *
> > + * The backend is a long-running subprocess configured via
> > + * diff.<driver>.process.  It receives file content via
> > + * pkt-line and returns hunks with 1-based line numbers.
> > + *
> > + * On success, sets *hunks_out and *nr_hunks_out to a newly allocated
> > + * array (caller must free) and returns 0.
> > + *
> > + * On failure, returns -1.  The caller should fall back to the
> > + * builtin diff algorithm.
> > + */
>
> I do not agree with this.  If it is a failure, the user should fix
> the external process (or disable).  It shouldn't be hidden behind a
> fallback.  As I left comments, in this round of implementation,
> there are conditions that returns -1 for soemthing that is not an
> error (i.e., not configured, or process not supporting the
> particular capability) *and* in those cases the caller should fall
> back as if nothing happened.  But some error cases, the caller
> should't hide them.

Will address in a follow-up.

Thank you for the feedback!

^ permalink raw reply

* [PATCH v2] http: fix memory leak in fetch_and_setup_pack_index()
From: LorenzoPegorari @ 2026-05-28 23:49 UTC (permalink / raw)
  To: git; +Cc: Taylor Blau, Junio C Hamano, Patrick Steinhardt, fox, Jeff King
In-Reply-To: <agx5tblaCZNsYEBq@lorenzo-VM>

Inside the function `fetch_and_setup_pack_index()`, when the pack
obtained using `parse_pack_index()` fails to be verified by
`verify_pack_index()`, the function returns without closing and freeing
said pack.

Fix this by calling `close_pack_index()` to munmap the index file for
the leaking pack (which might have been mmapped by `fetch_pack_index()`
or `verify_pack_index()`), and then free it, when the verification
fails.

Also, do some more cleanup by removing the useless call to the function
`unlink()`. This is not necessary anymore since 63aca3f7f1 (dumb-http:
store downloaded pack idx as tempfile, 2024-10-25), when
`fetch_pack_index()` started registering its return value (in this case
`tmp_idx`) as a tempfile to be deleted at process exit.

Signed-off-by: LorenzoPegorari <lorenzo.pegorari2002@gmail.com>
---
 http.c | 10 +++++-----
 1 file changed, 5 insertions(+), 5 deletions(-)

diff --git a/http.c b/http.c
index 67c9c6fc60..99da4d7529 100644
--- a/http.c
+++ b/http.c
@@ -2538,18 +2538,18 @@ static int fetch_and_setup_pack_index(struct packfile_list *packs,
 
 	new_pack = parse_pack_index(the_repository, sha1, tmp_idx);
 	if (!new_pack) {
-		unlink(tmp_idx);
 		free(tmp_idx);
-
 		return -1; /* parse_pack_index() already issued error message */
 	}
 
 	ret = verify_pack_index(new_pack);
-	if (!ret)
-		close_pack_index(new_pack);
+
+	close_pack_index(new_pack);
 	free(tmp_idx);
-	if (ret)
+	if (ret) {
+		free(new_pack);
 		return -1;
+	}
 
 	packfile_list_prepend(packs, new_pack);
 	return 0;
-- 
2.54.0.129.g2dffd77b94.dirty


^ permalink raw reply related

* [PATCH] describe: fix --exclude, --match with --contains and --all
From: Jacob Keller @ 2026-05-28 23:29 UTC (permalink / raw)
  To: git; +Cc: Junio C Hamano, Jacob Keller, Tuomas Ahola

From: Jacob Keller <jacob.keller@gmail.com>

git describe --contains acts as a wrapper around git name-rev. When
operating with --contains and --all, the --match and --exclude patterns
are not properly forwarded to name-rev as --exclude and --refs options.

This results in the command silently discarding match and exclude
requests from the user when operating in --all mode.

We could check and die() if the user provides --contains, --all, and
--match/--exclude. However, its also straight forward to just pass the
filters down to git name-rev.

Notice that the documentation for --match and --exclude mention the
--all mode. It explains that they operate on refs with the prefix
refs/tags, and additionally refs/heads and refs/remotes when using
--all.

Fix the describe logic to pass the patterns down with the appropriate
prefixes when --all is provided. This fixes the support to match the
documented behavior.

Add tests to check that this works as expected.

Reported-by: Tuomas Ahola <taahol@utu.fi>
Signed-off-by: Jacob Keller <jacob.keller@gmail.com>
---

I was looking into reviving the patch that just added a simple die() and
realized that its actually pretty straight forward to just fix the support
instead. I'm open to either route, if we think this support isn't
necessary... I'm not sure if there are any gotchas or other issues with how
I implemented this.

 builtin/describe.c  | 18 +++++++++++++++---
 t/t6120-describe.sh | 29 +++++++++++++++++++++++++++++
 2 files changed, 44 insertions(+), 3 deletions(-)

diff --git a/builtin/describe.c b/builtin/describe.c
index 1c47d7c0b7c3..faaf44cec573 100644
--- a/builtin/describe.c
+++ b/builtin/describe.c
@@ -712,13 +712,25 @@ int cmd_describe(int argc,
 			     NULL);
 		if (always)
 			strvec_push(&args, "--always");
-		if (!all) {
+		if (!all)
 			strvec_push(&args, "--tags");
+
+		for_each_string_list_item(item, &patterns)
+			strvec_pushf(&args, "--refs=refs/tags/%s", item->string);
+		for_each_string_list_item(item, &exclude_patterns)
+			strvec_pushf(&args, "--exclude=refs/tags/%s", item->string);
+
+		if (all) {
 			for_each_string_list_item(item, &patterns)
-				strvec_pushf(&args, "--refs=refs/tags/%s", item->string);
+				strvec_pushf(&args, "--refs=refs/heads/%s", item->string);
 			for_each_string_list_item(item, &exclude_patterns)
-				strvec_pushf(&args, "--exclude=refs/tags/%s", item->string);
+				strvec_pushf(&args, "--exclude=refs/heads/%s", item->string);
+			for_each_string_list_item(item, &patterns)
+				strvec_pushf(&args, "--refs=refs/remotes/%s", item->string);
+			for_each_string_list_item(item, &exclude_patterns)
+				strvec_pushf(&args, "--exclude=refs/remotes/%s", item->string);
 		}
+
 		if (argc)
 			strvec_pushv(&args, argv);
 		else
diff --git a/t/t6120-describe.sh b/t/t6120-describe.sh
index 8ee3d2c37d02..f46e628d6a1a 100755
--- a/t/t6120-describe.sh
+++ b/t/t6120-describe.sh
@@ -359,6 +359,35 @@ test_expect_success 'describe --contains and --no-match' '
 	test_cmp expect actual
 '
 
+test_expect_success 'describe --contains --all --match' '
+	echo "tags/A^0" >expect &&
+	tagged_commit=$(git rev-parse "refs/tags/A^0") &&
+	test_must_fail git describe --contains --all --match="B" $tagged_commit >actual &&
+	git describe --contains --all --match="A" $tagged_commit >actual &&
+	test_cmp expect actual
+'
+
+test_expect_success 'describe --contains --all --match branch' '
+	echo "branch_A" >expect &&
+	tagged_commit=$(git rev-parse "refs/tags/A^0") &&
+	git describe --contains --all --match="branch*" $tagged_commit >actual &&
+	test_cmp expect actual
+'
+
+test_expect_success 'describe --contains --all --match and --exclude' '
+	echo "branch_C~1" >expect &&
+	tagged_commit=$(git rev-parse "refs/tags/A^0") &&
+	git describe --contains --all --match="branch*" --exclude="branch_A" $tagged_commit >actual &&
+	test_cmp expect actual
+'
+
+test_expect_success 'describe --contains --all --exclude' '
+	echo "branch_A" >expect &&
+	tagged_commit=$(git rev-parse "refs/tags/A^0") &&
+	git describe --contains --all --exclude="A" --exclude="c" --exclude="test*" $tagged_commit >actual &&
+	test_cmp expect actual
+'
+
 test_expect_success 'setup and absorb a submodule' '
 	test_create_repo sub1 &&
 	test_commit -C sub1 initial &&
-- 
2.54.0.633.g0ded84c31b89


^ permalink raw reply related

* [BUG] broken behaviour when running cd in a hook in a secondary worktree
From: Baptiste Jean-Louis @ 2026-05-28 21:03 UTC (permalink / raw)
  To: git

Hello,
Thank you for your great work
here is a bug I encountered

What did you do before the bug happened? (Steps to reproduce your issue)
#!/bin/bash

mkdir topfolder
cd topfolder
mkdir main-worktree
cd main-worktree
git init
mkdir dir
touch file-a dir/file-b
git add .
git commit -m "Initial commit":

cat >.git/hooks/cd-bug << EOF
#!/bin/bash

echo -e "\n\nrunning cd-bug hook"
# Redirect output to stderr.
exec 1>&2

echo "<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<"
git describe
echo pwd : $(pwd)
echo pwd_var : $PWD
echo git_prefix: $GIT_PREFIX
echo git_dir: $GIT_DIR
echo git_work_tree: $GIT_WORK_TREE
git status
echo "========================================================"
cd dir
echo pwd : $(pwd)
echo pwd_var : $PWD
echo git_prefix: $GIT_PREFIX
echo git_dir: $GIT_DIR
echo git_work_tree: $GIT_WORK_TREE
git status
echo ">>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>"
echo -e "cd-bug hook done\n\n"

EOF
chmod u+x .git/hooks/cd-bug

# behave as expected
git hook run cd-bug

git branch branch_b
git worktree add ../second-worktree branch_b
cd ../second-worktree

# broken behaviour here
git hook run cd-bug

# end of script



What did you expect to happen? (Expected behavior)
On branch branch_b
nothing to commit, working tree clean


What happened instead? (Actual behavior)
On branch branch_b
Changes not staged for commit:
  (use "git add/rm <file>..." to update what will be committed)
  (use "git restore <file>..." to discard changes in working directory)
        deleted:    dir/file-b
        deleted:    file-a

Untracked files:
  (use "git add <file>..." to include in what will be committed)
        file-b


What's different between what you expected and what actually happened?
-> Running `git status` after `cd` in a pre-commit hook lists all
repo's tracked file as deleted.
   However when running the hook from the main-worktree, I have no issue.

   In my final use case, I'm doing something that goes like below
   cd subfolder
   `git stash --keep-index`
   `./update-generated-files` which updates some files in subfolder
and subfolder/*/
   `git stash pop`



[System Info]
git version:
git version 2.51.1.windows.1
cpu: x86_64
built from commit: 1454f0a9c4a3a22fb3fd7cc33f76f88cd65ced41
sizeof-long: 4
sizeof-size_t: 8
shell-path: D:/git-sdk-64-build-installers/usr/bin/sh
feature: fsmonitor--daemon
zlib: 1.3.1
SHA-1: SHA1_DC
SHA-256: SHA256_BLK
default-ref-format: files
default-hash: sha1
uname: Windows 10.0 22631
compiler info: gnuc: 15.2
libc info: no libc information available
$SHELL (typically, interactive shell): /bin/bash



[System Info 2]
git version:
git version 2.47.3
cpu: x86_64
no commit associated with this build
sizeof-long: 8
sizeof-size_t: 8
shell-path: /bin/sh
zlib: 1.3.1
uname: Linux 6.12.74+deb13+1-amd64 #1 SMP PREEMPT_DYNAMIC Debian
6.12.74-2 (2026-03-08) x86_64
compiler info: gnuc: 14.2
libc info: glibc: 2.41
$SHELL (typically, interactive shell): /bin/bash

[System Info 3]
Ubuntu 20.04LTS
git version : 2.25.1



[Enabled Hooks]
yes , see reproduction script

Best Regards,
Baptiste JEAN-LOUIS

^ permalink raw reply

* [PATCH v3 3/3] line-log: allow non-patch diff formats with -L
From: Michael Montalbo via GitGitGadget @ 2026-05-28 20:47 UTC (permalink / raw)
  To: git; +Cc: D. Ben Knoble, Michael Montalbo, Michael Montalbo
In-Reply-To: <pull.2094.v3.git.1780001267.gitgitgadget@gmail.com>

From: Michael Montalbo <mmontalbo@gmail.com>

Now that -L flows through log_tree_diff_flush() and diff_flush(),
metadata-only diff formats work because they only read filepair
fields (status, mode, path, oid) already set on the pre-computed
pairs.

Expand the allowlist in setup_revisions() to also accept --raw,
--name-only, --name-status, and --summary.  Diff stat formats
(--stat, --numstat, --shortstat, --dirstat) remain blocked because
they call compute_diffstat() on full blob content and would show
whole-file statistics rather than range-scoped ones.

Signed-off-by: Michael Montalbo <mmontalbo@gmail.com>
---
 Documentation/line-range-options.adoc | 10 +++---
 revision.c                            |  4 ++-
 t/t4211-line-log.sh                   | 47 +++++++++++++++++++++++++--
 3 files changed, 54 insertions(+), 7 deletions(-)

diff --git a/Documentation/line-range-options.adoc b/Documentation/line-range-options.adoc
index ecb2c79fb9..72f639b5e7 100644
--- a/Documentation/line-range-options.adoc
+++ b/Documentation/line-range-options.adoc
@@ -8,12 +8,14 @@
 	give zero or one positive revision arguments, and
 	_<start>_ and _<end>_ (or _<funcname>_) must exist in the starting revision.
 	You can specify this option more than once. Implies `--patch`.
-	Patch output can be suppressed using `--no-patch`, but other diff formats
-	(namely `--raw`, `--numstat`, `--shortstat`, `--dirstat`, `--summary`,
-	`--name-only`, `--name-status`, `--check`) are not currently implemented.
+	Patch output can be suppressed using `--no-patch`.
+	Non-patch diff formats `--raw`, `--name-only`, `--name-status`,
+	and `--summary` are supported.  Diff stat formats
+	(`--stat`, `--numstat`, `--shortstat`, `--dirstat`) are not
+	currently implemented.
 +
 Patch formatting options such as `--word-diff`, `--color-moved`,
 `--no-prefix`, and whitespace options (`-w`, `-b`) are supported,
-as are pickaxe options (`-S`, `-G`).
+as are pickaxe options (`-S`, `-G`) and `--diff-filter`.
 +
 include::line-range-format.adoc[]
diff --git a/revision.c b/revision.c
index c903f7a1b4..f26fc1f4d5 100644
--- a/revision.c
+++ b/revision.c
@@ -3181,7 +3181,9 @@ int setup_revisions(int argc, const char **argv, struct rev_info *revs, struct s
 	if (revs->line_level_traverse &&
 	    (revs->full_diff ||
 	     (revs->diffopt.output_format &
-	      ~(DIFF_FORMAT_PATCH | DIFF_FORMAT_NO_OUTPUT))))
+	      ~(DIFF_FORMAT_PATCH | DIFF_FORMAT_NO_OUTPUT |
+		DIFF_FORMAT_RAW | DIFF_FORMAT_NAME |
+		DIFF_FORMAT_NAME_STATUS | DIFF_FORMAT_SUMMARY))))
 		die(_("-L does not yet support the requested diff format"));
 
 	if (revs->expand_tabs_in_log < 0)
diff --git a/t/t4211-line-log.sh b/t/t4211-line-log.sh
index e3937138a9..ca4eb7bbc7 100755
--- a/t/t4211-line-log.sh
+++ b/t/t4211-line-log.sh
@@ -155,8 +155,45 @@ test_expect_success '-p shows the default patch output' '
 	test_cmp expect actual
 '
 
-test_expect_success '--raw is forbidden' '
-	test_must_fail git log -L1,24:b.c --raw
+test_expect_success '--raw shows mode, oid, status and path' '
+	git log -L1,24:b.c --raw --format= >actual &&
+	test_grep "^:100644 100644 [0-9a-f]\{7\} [0-9a-f]\{7\} M	b.c$" actual &&
+	test_grep ! "^diff --git" actual &&
+	test_grep ! "^@@" actual
+'
+
+test_expect_success '--name-only shows path' '
+	git log -L1,24:b.c --name-only --format= >actual &&
+	test_grep "^b.c$" actual &&
+	test_grep ! "^diff --git" actual &&
+	test_grep ! "^@@" actual
+'
+
+test_expect_success '--name-status shows status and path' '
+	git log -L1,24:b.c --name-status --format= >actual &&
+	test_grep "^M	b.c$" actual &&
+	test_grep ! "^diff --git" actual &&
+	test_grep ! "^@@" actual
+'
+
+test_expect_success '--stat is not yet supported with -L' '
+	test_must_fail git log -L1,24:b.c --stat 2>err &&
+	test_grep "does not yet support" err
+'
+
+test_expect_success '--numstat is not yet supported with -L' '
+	test_must_fail git log -L1,24:b.c --numstat 2>err &&
+	test_grep "does not yet support" err
+'
+
+test_expect_success '--shortstat is not yet supported with -L' '
+	test_must_fail git log -L1,24:b.c --shortstat 2>err &&
+	test_grep "does not yet support" err
+'
+
+test_expect_success '--dirstat is not yet supported with -L' '
+	test_must_fail git log -L1,24:b.c --dirstat 2>err &&
+	test_grep "does not yet support" err
 '
 
 test_expect_success 'setup for checking fancy rename following' '
@@ -738,4 +775,10 @@ test_expect_success '-L --oneline has no extra blank line before diff' '
 	test_grep "^diff --git" line2
 '
 
+test_expect_success '--summary shows new file on root commit' '
+	git checkout parent-oids &&
+	git log -L:func2:file.c --summary --format= >actual &&
+	test_grep "create mode 100644 file.c" actual
+'
+
 test_done
-- 
gitgitgadget

^ permalink raw reply related

* [PATCH v3 2/3] line-log: integrate -L output with the standard log-tree pipeline
From: Michael Montalbo via GitGitGadget @ 2026-05-28 20:47 UTC (permalink / raw)
  To: git; +Cc: D. Ben Knoble, Michael Montalbo, Michael Montalbo
In-Reply-To: <pull.2094.v3.git.1780001267.gitgitgadget@gmail.com>

From: Michael Montalbo <mmontalbo@gmail.com>

`git log -L` has bypassed log_tree_diff() and log_tree_diff_flush()
since the feature was introduced, short-circuiting from
log_tree_commit() directly into line_log_print().  This skips the
no_free save/restore (noted in a NEEDSWORK comment added by
f8781bfda3), the always_show_header fallback, show_diff_of_diff(),
and diff_free() cleanup.

Restructure so that -L flows through log_tree_diff() ->
log_tree_diff_flush(), the same path used by the normal
single-parent and merge diff codepaths:

 - Rename line_log_print() to line_log_queue_pairs() and strip it
   down to just queuing pre-computed filepairs.  The show_log(),
   separator, diffcore_std(), and diff_flush() calls are removed
   since log_tree_diff_flush() handles all of those.

 - In log_tree_diff(), call line_log_queue_pairs() then
   log_tree_diff_flush(), mirroring the diff_tree_oid() + flush
   pattern used by the single-parent and merge codepaths.

 - Remove the early return in log_tree_commit() that is no longer
   needed now that -L output flows through log_tree_diff() and
   log_tree_diff_flush(); this restores no_free save/restore,
   always_show_header, and diff_free() cleanup.

Because show_log() is now deferred until after diffcore_std() inside
log_tree_diff_flush(), pickaxe (-S, -G, --find-object) and
--diff-filter now properly suppress commits when all pairs are
filtered out.

The blank-line separator between commit header and diff changes
slightly: the old code printed one unconditionally, while
log_tree_diff_flush() only emits one for verbose headers.  This
matches the rest of log output.

Also reject --full-diff, which is not yet supported with -L: the
filepairs are pre-computed during the history walk and scoped to
tracked line ranges, so there is currently no full-tree diff to
fall back to for display.

Update tests accordingly.

Signed-off-by: Michael Montalbo <mmontalbo@gmail.com>
---
 line-log.c                                    | 30 ++++-------
 line-log.h                                    |  2 +-
 log-tree.c                                    | 10 ++--
 revision.c                                    |  6 ++-
 t/t4211-line-log.sh                           | 53 ++++++++++++++-----
 t/t4211/sha1/expect.parallel-change-f-to-main |  1 -
 .../sha256/expect.parallel-change-f-to-main   |  1 -
 7 files changed, 60 insertions(+), 43 deletions(-)

diff --git a/line-log.c b/line-log.c
index 858a899cd2..7ee55b05cc 100644
--- a/line-log.c
+++ b/line-log.c
@@ -13,7 +13,6 @@
 #include "revision.h"
 #include "xdiff-interface.h"
 #include "strbuf.h"
-#include "log-tree.h"
 #include "line-log.h"
 #include "setup.h"
 #include "strvec.h"
@@ -1004,29 +1003,18 @@ static int process_all_files(struct line_log_data **range_out,
 	return changed;
 }
 
-int line_log_print(struct rev_info *rev, struct commit *commit)
+void line_log_queue_pairs(struct rev_info *rev, struct commit *commit)
 {
-	show_log(rev);
-	if (!(rev->diffopt.output_format & DIFF_FORMAT_NO_OUTPUT)) {
-		struct line_log_data *range = lookup_line_range(rev, commit);
-		struct line_log_data *r;
-		const char *prefix = diff_line_prefix(&rev->diffopt);
-
-		fprintf(rev->diffopt.file, "%s\n", prefix);
-
-		for (r = range; r; r = r->next) {
-			if (r->pair) {
-				struct diff_filepair *p =
-					diff_filepair_dup(r->pair);
-				p->line_ranges = &r->ranges;
-				diff_q(&diff_queued_diff, p);
-			}
-		}
+	struct line_log_data *range = lookup_line_range(rev, commit);
+	struct line_log_data *r;
 
-		diffcore_std(&rev->diffopt);
-		diff_flush(&rev->diffopt);
+	for (r = range; r; r = r->next) {
+		if (r->pair) {
+			struct diff_filepair *p = diff_filepair_dup(r->pair);
+			p->line_ranges = &r->ranges;
+			diff_q(&diff_queued_diff, p);
+		}
 	}
-	return 1;
 }
 
 static int bloom_filter_check(struct rev_info *rev,
diff --git a/line-log.h b/line-log.h
index 04a6ea64d3..99e1755ce3 100644
--- a/line-log.h
+++ b/line-log.h
@@ -46,7 +46,7 @@ int line_log_filter(struct rev_info *rev);
 int line_log_process_ranges_arbitrary_commit(struct rev_info *rev,
 						    struct commit *commit);
 
-int line_log_print(struct rev_info *rev, struct commit *commit);
+void line_log_queue_pairs(struct rev_info *rev, struct commit *commit);
 
 void line_log_free(struct rev_info *rev);
 
diff --git a/log-tree.c b/log-tree.c
index 7e048701d0..88b3019293 100644
--- a/log-tree.c
+++ b/log-tree.c
@@ -1105,6 +1105,12 @@ static int log_tree_diff(struct rev_info *opt, struct commit *commit, struct log
 	if (!all_need_diff && !opt->merges_need_diff)
 		return 0;
 
+	if (opt->line_level_traverse) {
+		line_log_queue_pairs(opt, commit);
+		log_tree_diff_flush(opt);
+		return !opt->loginfo;
+	}
+
 	parse_commit_or_die(commit);
 	oid = get_commit_tree_oid(commit);
 
@@ -1179,10 +1185,6 @@ int log_tree_commit(struct rev_info *opt, struct commit *commit)
 	opt->loginfo = &log;
 	opt->diffopt.no_free = 1;
 
-	/* NEEDSWORK: no restoring of no_free?  Why? */
-	if (opt->line_level_traverse)
-		return line_log_print(opt, commit);
-
 	if (opt->track_linear && !opt->linear && !opt->reverse_output_stage)
 		fprintf(opt->diffopt.file, "\n%s\n", opt->break_bar);
 	shown = log_tree_diff(opt, commit, &log);
diff --git a/revision.c b/revision.c
index 4a8e24bc38..c903f7a1b4 100644
--- a/revision.c
+++ b/revision.c
@@ -3179,8 +3179,10 @@ int setup_revisions(int argc, const char **argv, struct rev_info *revs, struct s
 		die(_("the option '%s' requires '%s'"), "--grep-reflog", "--walk-reflogs");
 
 	if (revs->line_level_traverse &&
-	    (revs->diffopt.output_format & ~(DIFF_FORMAT_PATCH | DIFF_FORMAT_NO_OUTPUT)))
-		die(_("-L does not yet support diff formats besides -p and -s"));
+	    (revs->full_diff ||
+	     (revs->diffopt.output_format &
+	      ~(DIFF_FORMAT_PATCH | DIFF_FORMAT_NO_OUTPUT))))
+		die(_("-L does not yet support the requested diff format"));
 
 	if (revs->expand_tabs_in_log < 0)
 		revs->expand_tabs_in_log = revs->expand_tabs_in_log_default;
diff --git a/t/t4211-line-log.sh b/t/t4211-line-log.sh
index aaf197d2ed..e3937138a9 100755
--- a/t/t4211-line-log.sh
+++ b/t/t4211-line-log.sh
@@ -368,7 +368,6 @@ test_expect_success '-L diff output includes index and new file mode' '
 
 test_expect_success '-L with --word-diff' '
 	cat >expect <<-\EOF &&
-
 	diff --git a/file.c b/file.c
 	--- a/file.c
 	+++ b/file.c
@@ -377,7 +376,6 @@ test_expect_success '-L with --word-diff' '
 	{
 	    return [-F2;-]{+F2 + 2;+}
 	}
-
 	diff --git a/file.c b/file.c
 	new file mode 100644
 	--- /dev/null
@@ -433,7 +431,6 @@ test_expect_success 'show line-log with graph' '
 	null_blob=$(test_oid zero | cut -c1-7) &&
 	qz_to_tab_space >expect <<-EOF &&
 	* $head_oid Modify func2() in file.c
-	|Z
 	| diff --git a/file.c b/file.c
 	| index $head_blob_old..$head_blob_new 100644
 	| --- a/file.c
@@ -445,7 +442,6 @@ test_expect_success 'show line-log with graph' '
 	| +    return F2 + 2;
 	|  }
 	* $root_oid Add func1() and func2() in file.c
-	ZZ
 	  diff --git a/file.c b/file.c
 	  new file mode 100644
 	  index $null_blob..$root_blob
@@ -494,23 +490,17 @@ test_expect_success '-L --find-object does not crash with merge and rename' '
 		--find-object=$(git rev-parse HEAD:file) >actual
 '
 
-# Commit-level filtering with pickaxe does not yet work for -L.
-# show_log() prints the commit header before diffcore_std() runs
-# pickaxe, so commits cannot be suppressed even when no diff pairs
-# survive filtering.  Fixing this would require deferring show_log()
-# until after diffcore_std(), which is a larger restructuring of the
-# log-tree output pipeline.
-test_expect_failure '-L -G should filter commits by pattern' '
+test_expect_success '-L -G should filter commits by pattern' '
 	git log --format="%s" --no-patch -L 1,1:file -G "nomatch" >actual &&
 	test_must_be_empty actual
 '
 
-test_expect_failure '-L -S should filter commits by pattern' '
+test_expect_success '-L -S should filter commits by pattern' '
 	git log --format="%s" --no-patch -L 1,1:file -S "nomatch" >actual &&
 	test_must_be_empty actual
 '
 
-test_expect_failure '-L --find-object should filter commits by object' '
+test_expect_success '-L --find-object should filter commits by object' '
 	git log --format="%s" --no-patch -L 1,1:file \
 		--find-object=$ZERO_OID >actual &&
 	test_must_be_empty actual
@@ -711,4 +701,41 @@ test_expect_success '-L with -G filters to diff-text matches' '
 	grep "F2 + 2" actual
 '
 
+test_expect_success '-L with --diff-filter=M excludes root commit' '
+	git checkout parent-oids &&
+	git log -L:func2:file.c --diff-filter=M --format=%s --no-patch >actual &&
+	# Root commit is an Add (A), not a Modify (M), so it should
+	# be excluded; only the modification commit remains.
+	echo "Modify func2() in file.c" >expect &&
+	test_cmp expect actual
+'
+
+test_expect_success '-L with --diff-filter=A shows only root commit' '
+	git checkout parent-oids &&
+	git log -L:func2:file.c --diff-filter=A --format=%s --no-patch >actual &&
+	echo "Add func1() and func2() in file.c" >expect &&
+	test_cmp expect actual
+'
+
+test_expect_success '-L with -S suppresses non-matching commits' '
+	git checkout parent-oids &&
+	git log -L:func2:file.c -S "F2 + 2" --format=%s --no-patch >actual &&
+	# Only the commit that changes the count of "F2 + 2" should appear.
+	echo "Modify func2() in file.c" >expect &&
+	test_cmp expect actual
+'
+
+test_expect_success '--full-diff is not yet supported with -L' '
+	test_must_fail git log -L1,24:b.c --full-diff 2>err &&
+	test_grep "does not yet support" err
+'
+
+test_expect_success '-L --oneline has no extra blank line before diff' '
+	git checkout parent-oids &&
+	git log --oneline -L:func2:file.c -1 >actual &&
+	# Oneline header on line 1, diff starts immediately on line 2
+	sed -n 2p actual >line2 &&
+	test_grep "^diff --git" line2
+'
+
 test_done
diff --git a/t/t4211/sha1/expect.parallel-change-f-to-main b/t/t4211/sha1/expect.parallel-change-f-to-main
index 65a8cc673a..6d7a201036 100644
--- a/t/t4211/sha1/expect.parallel-change-f-to-main
+++ b/t/t4211/sha1/expect.parallel-change-f-to-main
@@ -5,7 +5,6 @@ Date:   Fri Apr 12 16:16:24 2013 +0200
 
     Merge across the rename
 
-
 commit 6ce3c4ff690136099bb17e1a8766b75764726ea7
 Author: Thomas Rast <trast@student.ethz.ch>
 Date:   Thu Feb 28 10:49:50 2013 +0100
diff --git a/t/t4211/sha256/expect.parallel-change-f-to-main b/t/t4211/sha256/expect.parallel-change-f-to-main
index 3178989253..c93e03bef4 100644
--- a/t/t4211/sha256/expect.parallel-change-f-to-main
+++ b/t/t4211/sha256/expect.parallel-change-f-to-main
@@ -5,7 +5,6 @@ Date:   Fri Apr 12 16:16:24 2013 +0200
 
     Merge across the rename
 
-
 commit 4f7a58195a92c400e28a2354328587f1ff14fb77f5cf894536f17ccbc72931b9
 Author: Thomas Rast <trast@student.ethz.ch>
 Date:   Thu Feb 28 10:49:50 2013 +0100
-- 
gitgitgadget


^ permalink raw reply related

* [PATCH v3 1/3] revision: move -L setup before output_format-to-diff derivation
From: Michael Montalbo via GitGitGadget @ 2026-05-28 20:47 UTC (permalink / raw)
  To: git; +Cc: D. Ben Knoble, Michael Montalbo, Michael Montalbo
In-Reply-To: <pull.2094.v3.git.1780001267.gitgitgadget@gmail.com>

From: Michael Montalbo <mmontalbo@gmail.com>

The line_level_traverse block sets a default DIFF_FORMAT_PATCH when
no output format has been explicitly requested.  This default must
be visible to the "Did the user ask for any diff output?" check
that derives revs->diff from revs->diffopt.output_format.

Currently the -L block runs after that derivation, so revs->diff
stays 0 when no explicit format is given.  This does not matter yet
because log_tree_commit() short-circuits into line_log_print()
before consulting revs->diff, but the next commit will route -L
through the normal log_tree_diff() path, which checks revs->diff.

Move the block above the derivation so the default DIFF_FORMAT_PATCH
is in place when revs->diff is computed.  No behavior change on its
own.

Signed-off-by: Michael Montalbo <mmontalbo@gmail.com>
---
 revision.c | 16 ++++++++--------
 1 file changed, 8 insertions(+), 8 deletions(-)

diff --git a/revision.c b/revision.c
index 599b3a66c3..4a8e24bc38 100644
--- a/revision.c
+++ b/revision.c
@@ -3112,6 +3112,14 @@ int setup_revisions(int argc, const char **argv, struct rev_info *revs, struct s
 		object_context_release(&oc);
 	}
 
+	if (revs->line_level_traverse) {
+		if (want_ancestry(revs))
+			revs->limited = 1;
+		revs->topo_order = 1;
+		if (!revs->diffopt.output_format)
+			revs->diffopt.output_format = DIFF_FORMAT_PATCH;
+	}
+
 	/* Did the user ask for any diff output? Run the diff! */
 	if (revs->diffopt.output_format & ~DIFF_FORMAT_NO_OUTPUT)
 		revs->diff = 1;
@@ -3125,14 +3133,6 @@ int setup_revisions(int argc, const char **argv, struct rev_info *revs, struct s
 	if (revs->diffopt.objfind)
 		revs->simplify_history = 0;
 
-	if (revs->line_level_traverse) {
-		if (want_ancestry(revs))
-			revs->limited = 1;
-		revs->topo_order = 1;
-		if (!revs->diffopt.output_format)
-			revs->diffopt.output_format = DIFF_FORMAT_PATCH;
-	}
-
 	if (revs->topo_order && !generation_numbers_enabled(the_repository))
 		revs->limited = 1;
 
-- 
gitgitgadget


^ permalink raw reply related

* [PATCH v3 0/3] line-log: integrate -L with the standard log output pipeline
From: Michael Montalbo via GitGitGadget @ 2026-05-28 20:47 UTC (permalink / raw)
  To: git; +Cc: D. Ben Knoble, Michael Montalbo
In-Reply-To: <pull.2094.v2.git.1779738059.gitgitgadget@gmail.com>

Since its introduction, git log -L has short-circuited from
log_tree_commit() into its own output function, bypassing log_tree_diff()
and log_tree_diff_flush(). This skips no_free save/restore,
always_show_header, diff_free() cleanup, and means that pickaxe (-S, -G,
--find-object) and --diff-filter cannot suppress commits whose pairs are all
filtered out, because show_log() runs before diffcore_std().

This series restructures the flow so that -L goes through the same
log_tree_diff() -> log_tree_diff_flush() path as normal single-parent and
merge diffs, then uses that to enable several non-patch diff formats.

Patch 1: revision: move -L setup before output_format-to-diff derivation

Preparatory reorder in setup_revisions(). The -L block sets a default
DIFF_FORMAT_PATCH when no format is requested; move it before the derivation
of revs->diff from output_format so the default is visible to that check. No
behavior change on its own.

Patch 2: line-log: integrate -L output with the standard log-tree pipeline

Rename line_log_print() to line_log_queue_pairs(), stripping it down to only
queue pre-computed filepairs. log_tree_diff_flush() handles show_log(),
diffcore_std(), and diff_flush(). This fixes pickaxe and --diff-filter
suppression, and aligns the commit/diff separator with the rest of log
output. Rejects --full-diff, which is not yet supported when filepairs are
pre-computed.

Patch 3: line-log: allow non-patch diff formats with -L

Expand the allowlist to accept --raw, --name-only, --name-status, and
--summary. These only read filepair metadata already set by the line-log
machinery. Diff stat formats (--stat, --numstat, --shortstat, --dirstat)
remain blocked because they call compute_diffstat() on full blob content and
would show whole-file statistics rather than range-scoped ones.

Changes since v2:

 * Switch "! test_grep" to "test_grep !" in tests.

Michael Montalbo (3):
  revision: move -L setup before output_format-to-diff derivation
  line-log: integrate -L output with the standard log-tree pipeline
  line-log: allow non-patch diff formats with -L

 Documentation/line-range-options.adoc         |  10 +-
 line-log.c                                    |  30 ++----
 line-log.h                                    |   2 +-
 log-tree.c                                    |  10 +-
 revision.c                                    |  24 +++--
 t/t4211-line-log.sh                           | 100 +++++++++++++++---
 t/t4211/sha1/expect.parallel-change-f-to-main |   1 -
 .../sha256/expect.parallel-change-f-to-main   |   1 -
 8 files changed, 121 insertions(+), 57 deletions(-)


base-commit: 9f223ef1c026d91c7ac68cc0211bde255dda6199
Published-As: https://github.com/gitgitgadget/git/releases/tag/pr-2094%2Fmmontalbo%2Fmm%2Fline-log-use-log-tree-diff-flush-v3
Fetch-It-Via: git fetch https://github.com/gitgitgadget/git pr-2094/mmontalbo/mm/line-log-use-log-tree-diff-flush-v3
Pull-Request: https://github.com/gitgitgadget/git/pull/2094

Range-diff vs v2:

 1:  9633eb62c6 = 1:  9633eb62c6 revision: move -L setup before output_format-to-diff derivation
 2:  7acfc5376e = 2:  7acfc5376e line-log: integrate -L output with the standard log-tree pipeline
 3:  10a3d8dde2 ! 3:  ae0b7f3ca8 line-log: allow non-patch diff formats with -L
     @@ t/t4211-line-log.sh: test_expect_success '-p shows the default patch output' '
      +test_expect_success '--raw shows mode, oid, status and path' '
      +	git log -L1,24:b.c --raw --format= >actual &&
      +	test_grep "^:100644 100644 [0-9a-f]\{7\} [0-9a-f]\{7\} M	b.c$" actual &&
     -+	! test_grep "^diff --git" actual &&
     -+	! test_grep "^@@" actual
     ++	test_grep ! "^diff --git" actual &&
     ++	test_grep ! "^@@" actual
      +'
      +
      +test_expect_success '--name-only shows path' '
      +	git log -L1,24:b.c --name-only --format= >actual &&
      +	test_grep "^b.c$" actual &&
     -+	! test_grep "^diff --git" actual &&
     -+	! test_grep "^@@" actual
     ++	test_grep ! "^diff --git" actual &&
     ++	test_grep ! "^@@" actual
      +'
      +
      +test_expect_success '--name-status shows status and path' '
      +	git log -L1,24:b.c --name-status --format= >actual &&
      +	test_grep "^M	b.c$" actual &&
     -+	! test_grep "^diff --git" actual &&
     -+	! test_grep "^@@" actual
     ++	test_grep ! "^diff --git" actual &&
     ++	test_grep ! "^@@" actual
      +'
      +
      +test_expect_success '--stat is not yet supported with -L' '

-- 
gitgitgadget

^ permalink raw reply

* Re: [PATCH 0/2] rebase: handle --update-refs branch symrefs
From: Junio C Hamano @ 2026-05-28 20:42 UTC (permalink / raw)
  To: Son Luong Ngoc via GitGitGadget; +Cc: git, Son Luong Ngoc
In-Reply-To: <pull.2126.git.1779946921.gitgitgadget@gmail.com>

"Son Luong Ngoc via GitGitGadget" <gitgitgadget@gmail.com> writes:

> git rebase --update-refs can fail after the normal rebase path has
> successfully updated the current branch when another local branch is a
> symbolic ref to it.
>
> One practical way to arrive at that setup is a default branch rename from
> master to main. While the migration is in progress, a user may keep
> refs/heads/main as a symbolic ref to refs/heads/master so that both names
> continue to work locally.
>
> If pull.rebase is enabled, a plain git pull can then finish the rebase of
> master and still fail while trying to update the main alias. The reported
> failure looked like this, with line breaks adjusted for the cover letter:
>
> Successfully rebased and updated refs/heads/master.
> error: update_ref failed for ref 'refs/heads/main':
> cannot lock ref 'refs/heads/main':
> is at fc2c7bd5f17abec7861ef759edcd33a1e16662a1
> but expected 531cabdfb49098d6ffa502ed4bf91d1b35edfcfa
> Updated the following refs with --update-refs:
> Failed to update the following refs with --update-refs:
>         refs/heads/main

I vaguely recall we saw a different topic that dealt with a
situation somewhat similar to this topic (I think it was about
'describe' giving a name that is not a branch).  How would this mesh
with what the other topic wanted to do?  Instead of filtering out
non-branch names (which the other topic did), here we want to filter
out names that are not concrete branches but pointers to something
else.  Would it mean that the logic here is more broad (i.e., both
wants to filter out names of non-branches), making the other topic
unnecessary?


^ permalink raw reply

* Re: [PATCH] doc: fix typos via codespell
From: Junio C Hamano @ 2026-05-28 20:37 UTC (permalink / raw)
  To: Kristoffer Haugsbakk; +Cc: Andrew Kreimer, git
In-Reply-To: <a48b62b8-2fc3-43be-a5e3-22189efef0ef@app.fastmail.com>

"Kristoffer Haugsbakk" <kristofferhaugsbakk@fastmail.com> writes:

> On Sun, May 10, 2026, at 00:14, Kristoffer Haugsbakk wrote:
>> On Wed, May 6, 2026, at 12:15, Andrew Kreimer wrote:
>>> There are some typos in the documentation, comments, etc.
>>> Fix them via codespell.
>>>
>>> Signed-off-by: Andrew Kreimer <algonell@gmail.com>
>>> ---
>>>[snip]
>
> I went through the typos in my previous message and with the exception
> of `po/` they all look good. They are all either documentation typos
> or typos in code comments. And they are all legitimate, in other words
> not false positives.
>
> With Junio’s email in mind, I think a second version which just drops
> the `po/` and git-gui typo fixes would be good. Since they are different
> projects.

Thanks!.

^ permalink raw reply

* Re: git mv after the fact
From: Junio C Hamano @ 2026-05-28 20:36 UTC (permalink / raw)
  To: Ben Knoble; +Cc: Chris Torek, Frieder Hannenheim, git
In-Reply-To: <1FEDBC47-5DDB-4C42-A7C7-695630D330BF@gmail.com>

Ben Knoble <ben.knoble@gmail.com> writes:

>> Le 27 mai 2026 à 19:24, Junio C Hamano <gitster@pobox.com> a écrit :
>> 
>> Chris Torek <chris.torek@gmail.com> writes:
>> 
>>>> Chris Torek <chris.torek@gmail.com> writes:
>>>>> A flag for "git mv" would be convenient (and slightly moreefficient ...
>>>> 
>>> 
>>> On Tue, May 26, 2026 at 8:09 PM Junio C Hamano <gitster@pobox.com> wrote:
>>>> May be convenient, but I do not get the "efficient" part.
>>> 
>>> A normal `git mv` renames the index entry and the file in the working
>>> tree without running `git add` on the *contents*, so there's no new hash
>>> computation.  Presumably a `git mv --after foo bar` would do the same: verify
>>> that there is no existing `bar` in the index, that there is an existing `foo` in
>>> the index, and that there is no `foo` but there is a `bar` in the working tree,
>>> and then it would rename (add-and-remove, really, because of sorting)
>>> the index entry, without scanning the working tree contents.
>>> 
>>> In other words, we skip reading the 3 terabyte file, or whatever.
>> 
>> Yup, that matches what I wrote.  We do not rehash and we only write
>> the index just once.
>
> One thing I wondered: if we don’t have an exact move but assume (by not hashing), doesn’t that mean the index would differ from what’s on disk? I originally thought that might be a problem, but the more I thought the more I realized that’s a fairly typical state anyway.
>
> Just seemed like a potential footgun to me, but perhaps not worth worrying about. 

Good point.  Actually with or without --after/--cached, we do not
have to rehash, and more importantly, we should not rehash.

As you can do this already

    $ date >old.txt
    $ git add old.txt
    $ date >>old.txt
    ... now old.txt is _dirty_
    $ git mv old.txt new.txt

I do not think it is unusual to have the contents you have in your
working tree files diverge from the contents you last 'git add'ed to
the index.  You do *not* want to rehash.  The index entry for new.txt
must be left not-up-to-date, which is achieved in the above sequence
by retaining the file timestamp of old.txt at the "git add" time
even after "git mv" (i.e. new.txt has the timestamp and size of the
old.txt after it got the second "date" output, the index entry
records one generation old one, and would not match).  If we do the
"index-entry only" move, i.e.

    $ date >old.txt
    $ git add old.txt
    $ date >>old.txt
    ... now old.txt is _dirty_
    $ mv old.txt new.txt
    ... oops, we forgot to tell git
    $ git mv --cached old.txt new.txt

we need to make sure that we leave the cache entry dirty for
new.txt in the index.


^ permalink raw reply

* Re: [PATCH] compat/mingw: Allow SIGKILL to kill in mingw_kill.
From: Junio C Hamano @ 2026-05-28 20:28 UTC (permalink / raw)
  To: Johannes Schindelin
  Cc: Siddh Raman Pant, Johannes Sixt, git, Kristoffer Haugsbakk,
	Elijah Newren, Patrick Steinhardt
In-Reply-To: <7c0384e2-0d8c-17f2-9881-cf14b24c0a21@gmx.de>

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

> The version that that Git for Windows carries is actually really
> different. For one, it gives processes a chance to run their `atexit()`
> handlers when being terminated via `SIGTERM`.
>
> I'm afraid that the patch under discussion would severely conflict with
> Git for Windows' code. Git for Windows' code, that is, that should have
> been upstreamed a long time ago, but wasn't, out of time constraints.
>
> I'll try to polish the patches and upstream them.

Thanks.

^ permalink raw reply

* Re: [PATCH] t3070: skip ls-files tests with backslash patterns on Windows
From: Junio C Hamano @ 2026-05-28 20:25 UTC (permalink / raw)
  To: Kristofer Karlsson via GitGitGadget
  Cc: git, Johannes Schindelin, Kristofer Karlsson
In-Reply-To: <pull.2128.git.1779958849319.gitgitgadget@gmail.com>

"Kristofer Karlsson via GitGitGadget" <gitgitgadget@gmail.com>
writes:

> From: Kristofer Karlsson <krka@spotify.com>
>
> On Windows (MINGW), backslashes in pathspecs are silently converted to
> forward slashes (directory separators), which changes the glob semantics.
> This causes 36 test failures in t3070-wildmatch when the "via ls-files"
> variants test patterns containing backslash escapes (e.g. '\[ab]',
> '[\-_]', '[A-\\]').
>
> The wildmatch function itself handles these patterns correctly — only the
> ls-files code path fails because pathspec parsing converts the
> backslashes before they reach the glob matcher.
>
> Skip these ls-files tests on platforms where BSLASHPSPEC is not set,
> which is the existing prereq that captures exactly this semantic:
> "backslashes in pathspec are not directory separators."
>
> Signed-off-by: Kristofer Karlsson <krka@spotify.com>
> ---

Thanks for noticing and addressing this.  I think we fairly recently
started seeing this in GitHub actions CI, which puzzles me since
neither t3070 or wildmatch.[ch] have changed for quite some time.
8a6d158a (doc: document backslash in gitignore patterns, 2025-10-29)
added a few lines to the test about matching with backslash to t3070.

Two questions.

 * Has this been broken on Windows since October, or has something
   external change on Windows recently?  I do not know.  Anybody
   knows?

 * Is this change a workaround that sweeps ugly breakage under the
   rug, or is backslash inherently unusable as an excape character
   when handling paths on Windows (which I am afraid would make
   wildmatch fairly useless there)?

Will queue.  Thanks.

^ permalink raw reply

* Re: [PATCH] pkt-line: initialize packet_buffer to avoid macOS linker warning
From: Junio C Hamano @ 2026-05-28 20:12 UTC (permalink / raw)
  To: Harald Nordgren; +Cc: Harald Nordgren via GitGitGadget, git
In-Reply-To: <CAHwyqnXgxnDNiq0UWyAsz6CHvroYPZ36EGbaUn=-OmP6w3gsWw@mail.gmail.com>

Harald Nordgren <haraldnordgren@gmail.com> writes:

> So maybe we can do something like this then?
>
> ```
> +       # Silence Xcode 16.3+ linker warning about __DATA,__common alignment.
> +       LD_MAJOR_VERSION = $(shell ld -v 2>&1 | sed -n
> 's/.*PROJECT:ld-\([0-9]*\).*/\1/p')
> +        ifeq ($(shell test "$(LD_MAJOR_VERSION)" -ge 1167 && echo 1),1)
> +               BASIC_CFLAGS += -fno-common
> +        endif
> ```
>
> Harald

I do not exactly know where these magic numbers and patterns for
"ld" comes from, but yes, something like that in macOS specific
section would be what I had in mind.

Thanks.

^ permalink raw reply

* Re: [PATCH v2 0/3] line-log: integrate -L with the standard log output pipeline
From: Michael Montalbo @ 2026-05-28 19:31 UTC (permalink / raw)
  To: Junio C Hamano; +Cc: D. Ben Knoble, Michael Montalbo via GitGitGadget, git
In-Reply-To: <xmqqo6hzjrde.fsf@gitster.g>

On Thu, May 28, 2026 at 11:55 AM Junio C Hamano <gitster@pobox.com> wrote:
>
> "D. Ben Knoble" <ben.knoble@gmail.com> writes:
>
> >>      ++ ! test_grep "^diff --git" actual &&
> >>      ++ ! test_grep "^@@" actual
> >
> > I wish we had docs for all the little test helpers… in particular, I
> > think this is supposed to be "test_grep !" ?

Good catch, thank you! Will submit a fix and try to address the lack
of docs in a follow-up.

>
> Good eyes.  I wonder if we teach test-lint to catch these.

I had the same thought, and started working on a series that does this
and migrates
existing offenders. I should be able to submit it soon.

^ permalink raw reply

* Re: [BUG] "git diff --word-diff" gives a diff while they are only space changes
From: Michael Montalbo @ 2026-05-28 19:25 UTC (permalink / raw)
  To: Junio C Hamano; +Cc: Chris Torek, Johannes Sixt, vincent, git
In-Reply-To: <CAC2QwmLXk=CXNo8+Ja0fL5pN1YYMTkh7XHAUwN1c9VxuFhyy4Q@mail.gmail.com>

On Wed, May 20, 2026 at 1:21 PM Michael Montalbo <mmontalbo@gmail.com> wrote:
>
> On Mon, May 18, 2026 at 8:11 PM Junio C Hamano <gitster@pobox.com> wrote:
> >
> > Chris Torek <chris.torek@gmail.com> writes:
> >
> > > Call it an "implementation note" (or, if you like, a "practical
> > > consideration"?).
> > > Something along these lines might work...
> > >
> > >   Implementation Note
> > >
> > >   The --word-diff option currently operates by taking the same
> > >   line by line diff that you get without the option, then massaging
> > >   the result into a word-by-word difference. This may cause an
> > >   unnecessarily-larger diff than you would see with a more-clever
> > >   implementation. If and when Git acquires a more-clever
> > >   implementation, the output may change. Note that this is
> > >   similar to the --diff-algorithm option, which may change the
> > >   output.
> > >
> > >   Regardless of which algorithm is used, _any_ diff simply shows
> > >   _a_ way to achieve some particular change. It's impossible for
> > >   any algorithm to tell whether someone deleted two lines and
> > >   then put one back exactly as it appeared earlier, saving the
> > >   resulting text, vs deleting a single line, for instance. Only a
> > >   keystroke-by-keystroke logger would be able to tell what the
> > >   human operator actually typed into some editor. Git does
> > >   not have that information, and having it is not desired.
> > >
> > > Chris
> >
> > I understand your frustration in the second paragraph ;-) but let's
> > not go there.  The first paragraph is excellent.  It gives readers a
> > clear enough explanation to understand what is happening and stop
> > complaining where there is nothing to complain about (which is
> > already hinted by the "Note that" at the end).
> >
>
> Thanks for the ideas, Chris. Here is my attempt at synthesizing Chris'
> suggestions and Junio's feedback:
>
>   The `--word-diff` option operates by taking the same line-by-line
>   diff that is produced without the option and computing
>   word-by-word changes within each hunk.  This may produce a
>   larger diff than a dedicated word-diff tool would.  If Git
>   acquires a different implementation in the future, the output
>   may change.  Note that this is similar to the `--diff-algorithm`
>   option, which may also change the output.
>
> Does this work?

Updated the patch with the revised wording:
https://lore.kernel.org/git/pull.2113.git.1778686956622.gitgitgadget@gmail.com/T/#t

Please feel free to pick up, modify, or drop as appropriate.

^ permalink raw reply

* [PATCH v2] doc: clarify that --word-diff operates on line-level hunks
From: Michael Montalbo via GitGitGadget @ 2026-05-28 19:21 UTC (permalink / raw)
  To: git; +Cc: Michael Montalbo, Michael Montalbo
In-Reply-To: <pull.2113.git.1778686956622.gitgitgadget@gmail.com>

From: Michael Montalbo <mmontalbo@gmail.com>

The --word-diff documentation describes the output modes and
word-regex mechanics but does not explain that word-diff operates
within the hunks produced by the line-level diff rather than
performing an independent word-stream comparison.  This can
surprise users when the line-level alignment causes word-level
changes to appear even though the words in both files are
identical.

Add an implementation note explaining the two-stage relationship
and that the output may change if Git acquires a different
implementation in the future.

Signed-off-by: Michael Montalbo <mmontalbo@gmail.com>
---
    doc: clarify that --word-diff operates on line-level hunks
    
    CC: Vincent Lefevre vincent@vinc17.net, Johannes Sixt j6t@kdbg.org

Published-As: https://github.com/gitgitgadget/git/releases/tag/pr-2113%2Fmmontalbo%2Fmm%2Fdoc-word-diff-v2
Fetch-It-Via: git fetch https://github.com/gitgitgadget/git pr-2113/mmontalbo/mm/doc-word-diff-v2
Pull-Request: https://github.com/gitgitgadget/git/pull/2113

Range-diff vs v1:

 1:  73f7b06c06 ! 1:  bc5ca5a147 doc: clarify that --word-diff operates on line-level hunks
     @@ Commit message
          changes to appear even though the words in both files are
          identical.
      
     -    Add a short note explaining the two-stage relationship.
     +    Add an implementation note explaining the two-stage relationship
     +    and that the output may change if Git acquires a different
     +    implementation in the future.
      
          Signed-off-by: Michael Montalbo <mmontalbo@gmail.com>
      
     @@ Documentation/diff-options.adoc: endif::git-diff[]
       Note that despite the name of the first mode, color is used to
       highlight the changed parts in all modes if enabled.
      ++
     -+Word diff works by finding word-level changes within each hunk of
     -+the line-level diff.  The line-level alignment determines which
     -+changed lines are compared to each other, which can affect the
     -+word-level output.
     ++The `--word-diff` option operates by taking the same line-by-line
     ++diff that is produced without the option and computing
     ++word-by-word changes within each hunk.  This may produce a
     ++larger diff than a dedicated word-diff tool would.  If Git
     ++acquires a different implementation in the future, the output
     ++may change.  Note that this is similar to the `--diff-algorithm`
     ++option, which may also change the output.
       
       `--word-diff-regex=<regex>`::
       	Use _<regex>_ to decide what a word is, instead of considering


 Documentation/diff-options.adoc | 8 ++++++++
 1 file changed, 8 insertions(+)

diff --git a/Documentation/diff-options.adoc b/Documentation/diff-options.adoc
index 8a63b5e164..c8242e2462 100644
--- a/Documentation/diff-options.adoc
+++ b/Documentation/diff-options.adoc
@@ -457,6 +457,14 @@ endif::git-diff[]
 +
 Note that despite the name of the first mode, color is used to
 highlight the changed parts in all modes if enabled.
++
+The `--word-diff` option operates by taking the same line-by-line
+diff that is produced without the option and computing
+word-by-word changes within each hunk.  This may produce a
+larger diff than a dedicated word-diff tool would.  If Git
+acquires a different implementation in the future, the output
+may change.  Note that this is similar to the `--diff-algorithm`
+option, which may also change the output.
 
 `--word-diff-regex=<regex>`::
 	Use _<regex>_ to decide what a word is, instead of considering

base-commit: 94f057755b7941b321fd11fec1b2e3ca5313a4e0
-- 
gitgitgadget

^ permalink raw reply related

* Re: [PATCH v2 0/3] line-log: integrate -L with the standard log output pipeline
From: Junio C Hamano @ 2026-05-28 18:55 UTC (permalink / raw)
  To: D. Ben Knoble; +Cc: Michael Montalbo via GitGitGadget, git, Michael Montalbo
In-Reply-To: <CALnO6CA5GPS2CMv_x_=wOPBgspe31FkW=h832GCBpAUbBoJNLg@mail.gmail.com>

"D. Ben Knoble" <ben.knoble@gmail.com> writes:

>>      ++ ! test_grep "^diff --git" actual &&
>>      ++ ! test_grep "^@@" actual
>
> I wish we had docs for all the little test helpers… in particular, I
> think this is supposed to be "test_grep !" ?

Good eyes.  I wonder if we teach test-lint to catch these.

^ permalink raw reply

* Re: [PATCH] doc: fix typos via codespell
From: Kristoffer Haugsbakk @ 2026-05-28 17:53 UTC (permalink / raw)
  To: Andrew Kreimer, git
In-Reply-To: <b8d57be0-b03c-461c-94e4-02340b5af77b@app.fastmail.com>

On Sun, May 10, 2026, at 00:14, Kristoffer Haugsbakk wrote:
> On Wed, May 6, 2026, at 12:15, Andrew Kreimer wrote:
>> There are some typos in the documentation, comments, etc.
>> Fix them via codespell.
>>
>> Signed-off-by: Andrew Kreimer <algonell@gmail.com>
>> ---
>>[snip]

I went through the typos in my previous message and with the exception
of `po/` they all look good. They are all either documentation typos
or typos in code comments. And they are all legitimate, in other words
not false positives.

With Junio’s email in mind, I think a second version which just drops
the `po/` and git-gui typo fixes would be good. Since they are different
projects.

^ permalink raw reply

* Re: [PATCH 0/3] pack-objects: support bitmaps and delta-islands with `--path-walk`
From: Derrick Stolee @ 2026-05-28 15:28 UTC (permalink / raw)
  To: Taylor Blau, git; +Cc: Junio C Hamano, Jeff King, Elijah Newren
In-Reply-To: <cover.1779923907.git.me@ttaylorr.com>

On 5/27/26 7:18 PM, Taylor Blau wrote:

> Here is a trimmed-down reroll of my series to make `--path-walk` work
> with reachability bitmaps and delta-islands. This series was originally
> an RFC that was a companion to Stolee's recent patches to extend
> `--filter` support to `--path-walk` [1].
> 
> Since the previous round, Stolee's series has graduated and incorporated
> the filter-related patches from my earlier RFC [2]. What remains are the
> three patches here that implement support for reachability bitmaps and
> delta-islands under `--path-walk`.
> 
>   * The first patch allows `--path-walk` to use reachability bitmaps when
>     they can answer the request, falling back to path-walk enumeration
>     when they cannot. It also lets bitmap writing see the same commit
>     candidates that the regular traversal would have shown to the bitmap
>     selector.
> 
>   * The second patch is preparatory, and factors the
>     delta-islands-specific tree-depth recording from `show_object()` into
>     a helper.
> 
>   * The final patch teaches the path-walk callback to perform the same
>     delta-islands side effects as the regular traversal: propagating
>     island marks for commits, and recording tree depths for trees. This
>     gives `resolve_tree_islands()` the same input in either enumeration
>     mode, so the existing island checks can be reused unchanged.

I've applied these patches locally and confirmed that each one passes the
test suite with GIT_TEST_PACK_PATH_WALK=1, which helps to confirm that
the changes are correct (all existing bitmap tests create and use the
bitmaps with --path-walk unless explicitly disabled).

Should we add GIT_TEST_PACK_PATH_WALK=1 to the test-var CI build, now
that this is going to be more commonly used?

Do you have any end-to-end performance data to demonstrate that these
changes are effective at scale? Are we still producing packfiles with the
pack-file compression and now with .bitmap files? How does this impact
the performance of a clone or fetch when using a bitmap index at read
time?

With that in mind, should we update any t/perf/ test to cover some of
these scenarios? I'm running a few with GIT_TEST_PACK_PATH_WALK=1 on
my laptop as a test, but it's taking a while. If you have stats ready
from your local testing, then that would be interesting.

Thanks,
-Stolee


^ permalink raw reply

* Re: git mv after the fact
From: Ben Knoble @ 2026-05-28 14:28 UTC (permalink / raw)
  To: Junio C Hamano; +Cc: Chris Torek, Frieder Hannenheim, git
In-Reply-To: <877bootp3l.fsf@gitster.g>


> Le 27 mai 2026 à 19:24, Junio C Hamano <gitster@pobox.com> a écrit :
> 
> Chris Torek <chris.torek@gmail.com> writes:
> 
>>> Chris Torek <chris.torek@gmail.com> writes:
>>>> A flag for "git mv" would be convenient (and slightly moreefficient ...
>>> 
>> 
>> On Tue, May 26, 2026 at 8:09 PM Junio C Hamano <gitster@pobox.com> wrote:
>>> May be convenient, but I do not get the "efficient" part.
>> 
>> A normal `git mv` renames the index entry and the file in the working
>> tree without running `git add` on the *contents*, so there's no new hash
>> computation.  Presumably a `git mv --after foo bar` would do the same: verify
>> that there is no existing `bar` in the index, that there is an existing `foo` in
>> the index, and that there is no `foo` but there is a `bar` in the working tree,
>> and then it would rename (add-and-remove, really, because of sorting)
>> the index entry, without scanning the working tree contents.
>> 
>> In other words, we skip reading the 3 terabyte file, or whatever.
> 
> Yup, that matches what I wrote.  We do not rehash and we only write
> the index just once.

One thing I wondered: if we don’t have an exact move but assume (by not hashing), doesn’t that mean the index would differ from what’s on disk? I originally thought that might be a problem, but the more I thought the more I realized that’s a fairly typical state anyway.

Just seemed like a potential footgun to me, but perhaps not worth worrying about. 

^ 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