aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJunio C Hamano <gitster@pobox.com>2026-02-05 15:42:01 -0800
committerJunio C Hamano <gitster@pobox.com>2026-02-05 15:42:01 -0800
commit7758f84682eb248b8738ea5d9b72e60864fa2ee0 (patch)
tree525c27c12c1901987a6886754a3a9a5fc4d89a41
parent1f17604ce4e35e8a94e73c5c11e5882812663c2f (diff)
parent9dcc09bed13aba0dc93d253f18ee2c7da5970c0c (diff)
downloadgit-7758f84682eb248b8738ea5d9b72e60864fa2ee0.tar.xz
Merge branch 'tc/last-modified-options-cleanup'
The "-z" and "--max-depth" documentation (and implementation of "-z") in the "git last-modified" command have been updated. * tc/last-modified-options-cleanup: last-modified: change default max-depth to 0 last-modified: document option '--max-depth' last-modified: document option '-z' last-modified: clarify in the docs the command takes a pathspec
-rw-r--r--Documentation/git-last-modified.adoc45
-rw-r--r--builtin/last-modified.c25
-rwxr-xr-xt/t8020-last-modified.sh35
3 files changed, 87 insertions, 18 deletions
diff --git a/Documentation/git-last-modified.adoc b/Documentation/git-last-modified.adoc
index 602843e095..d7d16fc4f7 100644
--- a/Documentation/git-last-modified.adoc
+++ b/Documentation/git-last-modified.adoc
@@ -9,7 +9,8 @@ git-last-modified - EXPERIMENTAL: Show when files were last modified
SYNOPSIS
--------
[synopsis]
-git last-modified [--recursive] [--show-trees] [<revision-range>] [[--] <path>...]
+git last-modified [--recursive] [--show-trees] [--max-depth=<depth>] [-z]
+ [<revision-range>] [[--] <pathspec>...]
DESCRIPTION
-----------
@@ -24,13 +25,23 @@ OPTIONS
`-r`::
`--recursive`::
- Instead of showing tree entries, step into subtrees and show all entries
- inside them recursively.
+ Recursively traverse into all subtrees. By default, the command only
+ shows tree entries matching the `<pathspec>`. With this option, it
+ descends into subtrees and displays all entries within them.
+ Equivalent to `--max-depth=-1`.
`-t`::
`--show-trees`::
- Show tree entries even when recursing into them. It has no effect
- without `--recursive`.
+ Show tree entries even when recursing into them.
+
+`--max-depth=<depth>`::
+ For each pathspec given on the command line, traverse at most `<depth>`
+ levels into subtrees. A negative value means no limit.
+ The default is 0, which shows all paths matching the pathspec
+ without descending into subtrees.
+
+`-z`::
+ Terminate each line with a _NUL_ character rather than a newline.
`<revision-range>`::
Only traverse commits in the specified revision range. When no
@@ -39,10 +50,26 @@ OPTIONS
spell `<revision-range>`, see the 'Specifying Ranges' section of
linkgit:gitrevisions[7].
-`[--] <path>...`::
- For each _<path>_ given, the commit which last modified it is returned.
- Without an optional path parameter, all files and subdirectories
- in path traversal the are included in the output.
+`[--] <pathspec>...`::
+ Show the commit that last modified each path matching _<pathspec>_.
+ If no _<pathspec>_ is given, all files and subdirectories are included.
+ See linkgit:gitglossary[7] for details on pathspec syntax.
+
+OUTPUT
+------
+
+The output is in the format:
+
+------------
+ <oid> TAB <path> LF
+------------
+
+If a path contains any special characters, the path is C-style quoted. To
+avoid quoting, pass option `-z` to terminate each line with a NUL.
+
+------------
+ <oid> TAB <path> NUL
+------------
SEE ALSO
--------
diff --git a/builtin/last-modified.c b/builtin/last-modified.c
index c80f0535f6..f7f4c5109c 100644
--- a/builtin/last-modified.c
+++ b/builtin/last-modified.c
@@ -53,8 +53,9 @@ define_commit_slab(active_paths_for_commit, struct bitmap *);
struct last_modified {
struct hashmap paths;
struct rev_info rev;
- bool recursive;
bool show_trees;
+ bool nul_termination;
+ int max_depth;
const char **all_paths;
size_t all_paths_nr;
@@ -165,10 +166,10 @@ static void last_modified_emit(struct last_modified *lm,
putchar('^');
printf("%s\t", oid_to_hex(&commit->object.oid));
- if (lm->rev.diffopt.line_termination)
- write_name_quoted(path, stdout, '\n');
- else
+ if (lm->nul_termination)
printf("%s%c", path, '\0');
+ else
+ write_name_quoted(path, stdout, '\n');
}
static void mark_path(const char *path, const struct object_id *oid,
@@ -479,8 +480,10 @@ static int last_modified_init(struct last_modified *lm, struct repository *r,
lm->rev.no_commit_id = 1;
lm->rev.diff = 1;
lm->rev.diffopt.flags.no_recursive_diff_tree_combined = 1;
- lm->rev.diffopt.flags.recursive = lm->recursive;
+ lm->rev.diffopt.flags.recursive = 1;
lm->rev.diffopt.flags.tree_in_recursive = lm->show_trees;
+ lm->rev.diffopt.max_depth = lm->max_depth;
+ lm->rev.diffopt.max_depth_valid = lm->max_depth >= 0;
argc = setup_revisions(argc, argv, &lm->rev, NULL);
if (argc > 1) {
@@ -510,16 +513,20 @@ int cmd_last_modified(int argc, const char **argv, const char *prefix,
struct last_modified lm = { 0 };
const char * const last_modified_usage[] = {
- N_("git last-modified [--recursive] [--show-trees] "
- "[<revision-range>] [[--] <path>...]"),
+ N_("git last-modified [--recursive] [--show-trees] [--max-depth=<depth>] [-z]\n"
+ " [<revision-range>] [[--] <pathspec>...]"),
NULL
};
struct option last_modified_options[] = {
- OPT_BOOL('r', "recursive", &lm.recursive,
- N_("recurse into subtrees")),
+ OPT_SET_INT('r', "recursive", &lm.max_depth,
+ N_("recurse into subtrees"), -1),
OPT_BOOL('t', "show-trees", &lm.show_trees,
N_("show tree entries when recursing into subtrees")),
+ OPT_INTEGER_F(0, "max-depth", &lm.max_depth,
+ N_("maximum tree depth to recurse"), PARSE_OPT_NONEG),
+ OPT_BOOL('z', NULL, &lm.nul_termination,
+ N_("lines are separated with NUL character")),
OPT_END()
};
diff --git a/t/t8020-last-modified.sh b/t/t8020-last-modified.sh
index 50f4312f71..3944d2e153 100755
--- a/t/t8020-last-modified.sh
+++ b/t/t8020-last-modified.sh
@@ -93,6 +93,41 @@ test_expect_success 'last-modified subdir recursive' '
EOF
'
+test_expect_success 'last-modified subdir non-recursive' '
+ check_last_modified a <<-\EOF
+ 3 a
+ EOF
+'
+
+test_expect_success 'last-modified path in subdir non-recursive' '
+ check_last_modified a/file <<-\EOF
+ 2 a/file
+ EOF
+'
+
+test_expect_success 'last-modified subdir with wildcard non-recursive' '
+ check_last_modified a/* <<-\EOF
+ 3 a/b
+ 2 a/file
+ EOF
+'
+
+test_expect_success 'last-modified with negative max-depth' '
+ check_last_modified --max-depth=-1 <<-\EOF
+ 3 a/b/file
+ 2 a/file
+ 1 file
+ EOF
+'
+
+test_expect_success 'last-modified with max-depth of 1' '
+ check_last_modified --max-depth=1 <<-\EOF
+ 3 a/b
+ 2 a/file
+ 1 file
+ EOF
+'
+
test_expect_success 'last-modified from non-HEAD commit' '
check_last_modified HEAD^ <<-\EOF
2 a