* [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
* Re:
From: Weijie Yuan @ 2026-05-28 14:16 UTC (permalink / raw)
To: 胡锦; +Cc: git
In-Reply-To: <tencent_124443E95FD3502A16815464@qq.com>
Hi,
I'm just a diver here, but I would like to give you some suggestions though.
* Your email doesn't have a subject line. So it seems not possible for
a true dev here to be interested in your email.
* I guess you would need a proper text editor or a proper email client,
your email doen's wrap perfectly.
As for your feature request, I believe it's even harder, as for the "online
collaborative documents". This doesn't seem like a problem that git was
designed to solve, but more like features of certain forges. Based on
discussions in recent years, this feature you are looking for is not
within the scope or schedule of discussion.
But I guess they would be more possible to discuss it if you could
attach some patches.
Thanks.
^ permalink raw reply
* Re: [PATCH] compat/mingw: Allow SIGKILL to kill in mingw_kill.
From: Johannes Schindelin @ 2026-05-28 13:11 UTC (permalink / raw)
To: Junio C Hamano
Cc: Siddh Raman Pant, Johannes Sixt, git, Kristoffer Haugsbakk,
Elijah Newren, Patrick Steinhardt
In-Reply-To: <xmqqwlwwt0mj.fsf@gitster.g>
Hi Junio & Siddh,
On Fri, 22 May 2026, Junio C Hamano wrote:
> Siddh Raman Pant <siddh.raman.pant@oracle.com> writes:
>
> > mingw_kill() only allows SIGTERM for killing a process.
> >
> > Let's also allow the natural SIGKILL for the same so that callers don't
> > have to do ifdef soup for special Windows handling.
>
> [...]
>
> The current code only handles TERM (to terminate) or 0 (to probe)
> and everything else results in EINVAL, so the updated behaviour is
> to pretend as if TERM is sent and do whatever PROCESS_TERMINATE
> does, instead of doing nothing and erroring with EINVAL. Which does
> sound like an improvement over the status quo.
>
> What I am wondering is if there are different kind of "kill" in the
> Windows land, just like there are distinction between TERM and KILL.
> For example, the program ought to be able to block TERM but not
> KILL. There are other termination-inducing signals like SIGQUIT but
> until we start using them in our code, this emulation layer does not
> have to know about them, I think.
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.
Ciao,
Johannes
^ permalink raw reply
* Re: [PATCH v2] config: retry acquiring config.lock, configurable via core.configLockTimeout
From: Junio C Hamano @ 2026-05-28 12:23 UTC (permalink / raw)
To: Johannes Schindelin; +Cc: Joerg Thalheim, git, Patrick Steinhardt
In-Reply-To: <f449d0db-0434-f870-c69f-793f2b096816@gmx.de>
Johannes Schindelin <Johannes.Schindelin@gmx.de> writes:
> Footnote *1*: In general, I am quite wary of unit-less numbers in
> configurations.
Hear, hear.
I do not like unit-less names for variables that store numbers, not
just configuration but in-code variables. In the longer run we want
to clean these up. In-code variables are much easier to clean-up
than end-user facing configuration variable names, of course.
^ permalink raw reply
* Re: [PATCH v2] config: retry acquiring config.lock, configurable via core.configLockTimeout
From: Johannes Schindelin @ 2026-05-28 11:51 UTC (permalink / raw)
To: Joerg Thalheim; +Cc: git, Junio C Hamano, Patrick Steinhardt
In-Reply-To: <20260517132111.1014901-1-joerg@thalheim.io>
Hi Joerg,
On Sun, 17 May 2026, Joerg Thalheim wrote:
> I matched the core.filesRefLockTimeout naming rather than reusing
> microsoft/git's core.configWriteLockTimeoutMS, but can switch if the
> downstream compat matters more.
I see that there is quite a bit of precedent for naming a config setting
`*Timeout` and implying that it specifies milliseconds, e.g.
https://git-scm.com/docs/git-config#Documentation/git-config.txt-corefilesRefLockTimeout
In general, I am pretty wary of unit-less numbers [*1*], that's why I
chose that "MS" suffix. However, the prior art in Git is clear, and I
should not have missed it. Therefore, I have no objections against
`core.configLockTimeout` as-is; I'll take care of providing a smooth
upgrade path in Microsoft Git.
Thank you,
Johannes
Footnote *1*: In general, I am quite wary of unit-less numbers in
configurations. There's not only the precedent of Mars Climate Orbiter
https://en.wikipedia.org/wiki/Mars_Climate_Orbiter#Cause_of_failure, I
also heard a story that seemed to be entertaining only in hindsight where
a German car's software improperly interpreted a British speed limit sign
to mean km/h instead of mph.
^ permalink raw reply
* Re: Suggestion: Real-time or Conflict-Reducing Collaboration Support for Specific Directories
From: Christian Couder @ 2026-05-28 9:23 UTC (permalink / raw)
To: 胡锦; +Cc: git
In-Reply-To: <tencent_530FD5EC0E2FA9A005AB4725@qq.com>
Hi Hujin,
On Thu, May 28, 2026 at 7:16 AM 胡锦 <hujin2@sunline.cn> wrote:
>
> Dear Git Team,
>
> My name is Hujin, and I am an IT engineer from China. I have been using Git for more than 10 years.
>
> First of all, I would like to express my appreciation for Git. In my experience, Git remains one of the best and most reliable version control systems in modern software development. It has played an important role in many projects I have worked on.
Thanks.
> However, I have also encountered a recurring difficulty in daily use. For certain types of files, especially files under script directories or other frequently modified directories, conflicts happen quite often because updates are not synchronized in real time. In some project scenarios, multiple engineers may edit related scripts at the same time, and this can lead to repeated merge conflicts and extra coordination costs.
>
> I wonder whether Git could provide, in future versions, some optional features similar to online collaborative documents, or directory-level collaboration mechanisms for specific files or folders. For example, users could enable special real-time update, lock, notification, or conflict-reduction behavior for selected directories such as scripts. This could help reduce conflicts and make Git even more convenient for teams working on highly shared files.
>
> I understand that Git is designed as a distributed version control system, and such functionality may not be simple to implement. Still, I believe an optional feature in this direction could be very helpful for many engineering teams.
First I don't think it's Git's role to provide a full collaborative
editor, but you are right that it could provide mechanisms that could
help.
Then there are a number of features/mechanisms that other SCMs or
tools provide that could perhaps help:
- Jujutsu's working copy as a commit
(https://docs.jj-vcs.dev/latest/working-copy/)
It could help write a background script that constantly pushes and
rebases the current commit to a shared server as the user types,
mimicking a real-time sync.
Jujutsu's first-class conflicts could perhaps help too.
- Pijul's CRDTs and the Theory of Patches (https://pijul.org/manual/theory.html)
To seamlessly merge real-time changes without locking the file or
constantly throwing conflict errors, modern collaborative editors
abandon SCM snapshot merging entirely. Instead, they use one of two
mathematical models:
- Operational Transformation (OT): Used by Google Docs.
- Conflict-free Replicated Data Types (CRDTs): Used by newer tools
like Figma, Zed, and Apple Notes.
Pijul's underlying Rust library (libpijul) which already uses CRDTs
could be wrapped and adapted to fit a real-time context.
- Michael Haggerty’s `git-imerge`
(https://softwareswirl.blogspot.com/2013/05/git-imerge-practical-introduction.html)
I think this is the right way to simplify complex merges and rebases
as much as possible, which is useful if a lot of such operations have
to be made.
- CRDT AST (https://github.com/aaronmunsters/AST_CRDT)
- Automerge (https://automerge.org/docs/hello/)
- Yjs (https://github.com/yjs/yjs)
It would be indeed complex to implement any of these in Git.
The nice thing if someone would want to implement backend
collaborative editing features is that these days an AI could perhaps
resolve merge conflicts automatically. (But of course users should
have a way to override the AI's decisions if they think it's wrong.)
There are already a number of tools out there doing that for regular
development.
Best,
Christian.
^ permalink raw reply
* [PATCH] t3070: skip ls-files tests with backslash patterns on Windows
From: Kristofer Karlsson via GitGitGadget @ 2026-05-28 9:00 UTC (permalink / raw)
To: git; +Cc: @dscho, Kristofer Karlsson, Kristofer Karlsson
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>
---
t3070: skip ls-files tests with backslash patterns on Windows
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."
Published-As: https://github.com/gitgitgadget/git/releases/tag/pr-2128%2Fspkrka%2Fwildmatch-windows-fix-v1
Fetch-It-Via: git fetch https://github.com/gitgitgadget/git pr-2128/spkrka/wildmatch-windows-fix-v1
Pull-Request: https://github.com/gitgitgadget/git/pull/2128
t/t3070-wildmatch.sh | 19 +++++++++++++------
1 file changed, 13 insertions(+), 6 deletions(-)
diff --git a/t/t3070-wildmatch.sh b/t/t3070-wildmatch.sh
index 655bb1a0f2..3394122218 100755
--- a/t/t3070-wildmatch.sh
+++ b/t/t3070-wildmatch.sh
@@ -99,6 +99,13 @@ match_with_ls_files() {
match_function=$4
ls_files_args=$5
+ prereqs=EXPENSIVE_ON_WINDOWS
+ case "$pattern" in
+ *\\*)
+ prereqs="$prereqs,BSLASHPSPEC"
+ ;;
+ esac
+
match_stdout_stderr_cmp="
tr -d '\0' <actual.raw >actual &&
test_must_be_empty actual.err &&
@@ -108,36 +115,36 @@ match_with_ls_files() {
then
if test -e .git/created_test_file
then
- test_expect_success EXPENSIVE_ON_WINDOWS "$match_function (via ls-files): match dies on '$pattern' '$text'" "
+ test_expect_success $prereqs "$match_function (via ls-files): match dies on '$pattern' '$text'" "
printf '%s' '$text' >expect &&
test_must_fail git$ls_files_args ls-files -z -- '$pattern'
"
else
- test_expect_failure EXPENSIVE_ON_WINDOWS "$match_function (via ls-files): match skip '$pattern' '$text'" 'false'
+ test_expect_failure $prereqs "$match_function (via ls-files): match skip '$pattern' '$text'" 'false'
fi
elif test "$match_expect" = 1
then
if test -e .git/created_test_file
then
- test_expect_success EXPENSIVE_ON_WINDOWS "$match_function (via ls-files): match '$pattern' '$text'" "
+ test_expect_success $prereqs "$match_function (via ls-files): match '$pattern' '$text'" "
printf '%s' '$text' >expect &&
git$ls_files_args ls-files -z -- '$pattern' >actual.raw 2>actual.err &&
$match_stdout_stderr_cmp
"
else
- test_expect_failure EXPENSIVE_ON_WINDOWS "$match_function (via ls-files): match skip '$pattern' '$text'" 'false'
+ test_expect_failure $prereqs "$match_function (via ls-files): match skip '$pattern' '$text'" 'false'
fi
elif test "$match_expect" = 0
then
if test -e .git/created_test_file
then
- test_expect_success EXPENSIVE_ON_WINDOWS "$match_function (via ls-files): no match '$pattern' '$text'" "
+ test_expect_success $prereqs "$match_function (via ls-files): no match '$pattern' '$text'" "
>expect &&
git$ls_files_args ls-files -z -- '$pattern' >actual.raw 2>actual.err &&
$match_stdout_stderr_cmp
"
else
- test_expect_failure EXPENSIVE_ON_WINDOWS "$match_function (via ls-files): no match skip '$pattern' '$text'" 'false'
+ test_expect_failure $prereqs "$match_function (via ls-files): no match skip '$pattern' '$text'" 'false'
fi
else
test_expect_success "PANIC: Test framework error. Unknown matches value $match_expect" 'false'
base-commit: c69baaf57ba26cf117c2b6793802877f19738b0d
--
gitgitgadget
^ permalink raw reply related
* Re: [PATCH] pkt-line: initialize packet_buffer to avoid macOS linker warning
From: Harald Nordgren @ 2026-05-28 8:14 UTC (permalink / raw)
To: Junio C Hamano; +Cc: Harald Nordgren via GitGitGadget, git
In-Reply-To: <CAHwyqnWjHTpWfbMcBHOabny5NQN7xTZmxew2yDWWu3AoosngWA@mail.gmail.com>
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
On Thu, May 28, 2026 at 9:40 AM Harald Nordgren
<haraldnordgren@gmail.com> wrote:
>
> > According to Internet, Xcode 16.3 or newer introduced this insanity,
> > it seems. How about adding -fno-common to your CFLAGS? If it
> > solves the issue, then we can think about teaching config.mak.uname
> > to detect macOS with problematic versions of compilers and add the
> > flag as workaround.
>
> Yes, this works:
>
> ```
> make -s CFLAGS_APPEND="-fno-common"
> ```
>
>
> Harald
^ permalink raw reply
page: next (older) | prev (newer) | latest
- recent:[subjects (threaded)|topics (new)|topics (active)]
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox