last-modified: change default max-depth to 0

By default git-last-modified(1) doesn't recurse into subtrees. So when the pathspec contained a path in a subtree, the command would only print the commit information about the parent tree of the path, like: $ git last-modified -- path/file aaa0aab1bbb2bcc3ccc4ddd5dde6eee7eff8fff9 path Change the default behavior to give commit information about the exact path instead: $ git last-modified -- path/file aaa0aab1bbb2bcc3ccc4ddd5dde6eee7eff8fff9 path/file To achieve this, the default max-depth is changed to 0 and recursive is always enabled. The handling of option '-r' is modified to disable a max-depth, resulting in the behavior of this option to remain unchanged. No existing tests were modified, because there didn't exist any tests covering the example above. But more tests are added to cover this now. Signed-off-by: Toon Claes <toon@iotcl.com> Signed-off-by: Junio C Hamano <gitster@pobox.com>

Toon Claes committed Jan 20, 2026 at 22:47 UTC 9dcc09bed13aba0dc93d253f18ee2c7da5970c0c
3 files changed +45 -20
Documentation/git-last-modified.adoc
+5 -4
@@ -25,13 +25,14 @@ OPTIONS
25
26 `-r`::
27 `--recursive`::
28 - Instead of showing tree entries, step into subtrees and show all entries
29 - inside them recursively.
28 + Recursively traverse into all subtrees. By default, the command only
29 + shows tree entries matching the `<pathspec>`. With this option, it
30 + descends into subtrees and displays all entries within them.
31 + Equivalent to `--max-depth=-1`.
32
33 `-t`::
34 `--show-trees`::
33 - Show tree entries even when recursing into them. It has no effect
34 - without `--recursive`.
35 + Show tree entries even when recursing into them.
36
37 `--max-depth=<depth>`::
38 For each pathspec given on the command line, traverse at most `<depth>`
builtin/last-modified.c
+5 -16
@@ -53,7 +53,6 @@ define_commit_slab(active_paths_for_commit, struct bitmap *);
53 struct last_modified {
54 struct hashmap paths;
55 struct rev_info rev;
56 - bool recursive;
56 bool show_trees;
57 bool nul_termination;
58 int max_depth;
@@ -481,14 +480,10 @@ static int last_modified_init(struct last_modified *lm, struct repository *r,
480 lm->rev.no_commit_id = 1;
481 lm->rev.diff = 1;
482 lm->rev.diffopt.flags.no_recursive_diff_tree_combined = 1;
484 - lm->rev.diffopt.flags.recursive = lm->recursive;
483 + lm->rev.diffopt.flags.recursive = 1;
484 lm->rev.diffopt.flags.tree_in_recursive = lm->show_trees;
486 -
487 - if (lm->max_depth >= 0) {
488 - lm->rev.diffopt.flags.recursive = 1;
489 - lm->rev.diffopt.max_depth = lm->max_depth;
490 - lm->rev.diffopt.max_depth_valid = 1;
491 - }
485 + lm->rev.diffopt.max_depth = lm->max_depth;
486 + lm->rev.diffopt.max_depth_valid = lm->max_depth >= 0;
487
488 argc = setup_revisions(argc, argv, &lm->rev, NULL);
489 if (argc > 1) {
@@ -524,8 +519,8 @@ int cmd_last_modified(int argc, const char **argv, const char *prefix,
519 };
520
521 struct option last_modified_options[] = {
527 - OPT_BOOL('r', "recursive", &lm.recursive,
528 - N_("recurse into subtrees")),
522 + OPT_SET_INT('r', "recursive", &lm.max_depth,
523 + N_("recurse into subtrees"), -1),
524 OPT_BOOL('t', "show-trees", &lm.show_trees,
525 N_("show tree entries when recursing into subtrees")),
526 OPT_INTEGER_F(0, "max-depth", &lm.max_depth,
@@ -535,12 +530,6 @@ int cmd_last_modified(int argc, const char **argv, const char *prefix,
530 OPT_END()
531 };
532
538 - /*
539 - * Set the default of a max-depth to "unset". This will change in a
540 - * subsequent commit.
541 - */
542 - lm.max_depth = -1;
543 -
533 argc = parse_options(argc, argv, prefix, last_modified_options,
534 last_modified_usage,
535 PARSE_OPT_KEEP_ARGV0 | PARSE_OPT_KEEP_UNKNOWN_OPT);
t/t8020-last-modified.sh
+35
@@ -85,6 +85,41 @@ test_expect_success 'last-modified subdir recursive' '
85 EOF
86 '
87
88 +test_expect_success 'last-modified subdir non-recursive' '
89 + check_last_modified a <<-\EOF
90 + 3 a
91 + EOF
92 +'
93 +
94 +test_expect_success 'last-modified path in subdir non-recursive' '
95 + check_last_modified a/file <<-\EOF
96 + 2 a/file
97 + EOF
98 +'
99 +
100 +test_expect_success 'last-modified subdir with wildcard non-recursive' '
101 + check_last_modified a/* <<-\EOF
102 + 3 a/b
103 + 2 a/file
104 + EOF
105 +'
106 +
107 +test_expect_success 'last-modified with negative max-depth' '
108 + check_last_modified --max-depth=-1 <<-\EOF
109 + 3 a/b/file
110 + 2 a/file
111 + 1 file
112 + EOF
113 +'
114 +
115 +test_expect_success 'last-modified with max-depth of 1' '
116 + check_last_modified --max-depth=1 <<-\EOF
117 + 3 a/b
118 + 2 a/file
119 + 1 file
120 + EOF
121 +'
122 +
123 test_expect_success 'last-modified from non-HEAD commit' '
124 check_last_modified HEAD^ <<-\EOF
125 2 a