Message ID | pull.1250.git.1654509678718.gitgitgadget@gmail.com (mailing list archive) |
---|---|
State | New, archived |
Headers | show |
Series | ls-files.c: add --only-object-name option | expand |
On Mon, Jun 06 2022, ZheNing Hu via GitGitGadget wrote: > From: ZheNing Hu <adlternative@gmail.com> > > `git ls-files --stage` default output format is: > > [<tag> ]<mode> <object> <stage> <file> > > sometime we want to find a path's corresponding objectname, > we will parse the output and extract objectname from it > again and again. > > So introduce a new option `--only-object-name` which can only > output objectname when giving `--stage` or `--resolve-undo`. > > Signed-off-by: ZheNing Hu <adlternative@gmail.com> > --- > ls-files.c: add --only-object-name option > > Something we want to extract objectname from git ls-files --stage, but > git ls-file don't support something like --format=%(objectname) (which > git ls-tree have implemented) > > So now add a new option --only-object-name which can only output > objectname. > > (Maybe we should add something like git ls-files --format ?) Yes I think that would be very useful, especially if we could see if some of the code could be shared (maybe not). But in any case shouldn't this be called --name-only to go with "git ls-tree"'s version of this? Or is there some subtle difference I'm missing...? > Published-As: https://github.com/gitgitgadget/git/releases/tag/pr-1250%2Fadlternative%2Fzh%2Fls-file-only-objectname-v1 > Fetch-It-Via: git fetch https://github.com/gitgitgadget/git pr-1250/adlternative/zh/ls-file-only-objectname-v1 > Pull-Request: https://github.com/gitgitgadget/git/pull/1250 > > Documentation/git-ls-files.txt | 6 +++++- > builtin/ls-files.c | 18 +++++++++++++++++- > t/t2030-unresolve-info.sh | 33 +++++++++++++++++++++++++++++++++ > t/t3004-ls-files-basic.sh | 32 ++++++++++++++++++++++++++++++++ > 4 files changed, 87 insertions(+), 2 deletions(-) > > diff --git a/Documentation/git-ls-files.txt b/Documentation/git-ls-files.txt > index 0dabf3f0ddc..0e3f4f094f3 100644 > --- a/Documentation/git-ls-files.txt > +++ b/Documentation/git-ls-files.txt > @@ -13,7 +13,7 @@ SYNOPSIS > [-c|--cached] [-d|--deleted] [-o|--others] [-i|--|ignored] > [-s|--stage] [-u|--unmerged] [-k|--|killed] [-m|--modified] > [--directory [--no-empty-directory]] [--eol] > - [--deduplicate] > + [--deduplicate] [--only-object-name] > [-x <pattern>|--exclude=<pattern>] > [-X <file>|--exclude-from=<file>] > [--exclude-per-directory=<file>] > @@ -88,6 +88,10 @@ OPTIONS > When any of the `-t`, `--unmerged`, or `--stage` option is > in use, this option has no effect. > > +--only-object-name: > + When giving `--stage` or `--resolve-undo` , only output `<object>` > + instead of `[<tag> ]<mode> <object> <stage> <file>` format. > + > -x <pattern>:: > --exclude=<pattern>:: > Skip untracked files matching pattern. > diff --git a/builtin/ls-files.c b/builtin/ls-files.c > index e791b65e7e9..fd9c10e9f94 100644 > --- a/builtin/ls-files.c > +++ b/builtin/ls-files.c > @@ -26,6 +26,7 @@ static int show_deleted; > static int show_cached; > static int show_others; > static int show_stage; > +static int only_object_name; > static int show_unmerged; > static int show_resolve_undo; > static int show_modified; > @@ -241,10 +242,15 @@ static void show_ce(struct repository *repo, struct dir_struct *dir, > if (!show_stage) { > fputs(tag, stdout); > } else { > + const char *object_name = repo_find_unique_abbrev(repo, &ce->oid, abbrev); > + if (only_object_name) { > + printf("%s%c", object_name, line_terminator); > + return; > + } > printf("%s%06o %s %d\t", > tag, > ce->ce_mode, > - repo_find_unique_abbrev(repo, &ce->oid, abbrev), > + object_name, > ce_stage(ce)); > } > write_eolinfo(repo->index, ce, fullname); > @@ -274,6 +280,10 @@ static void show_ru_info(struct index_state *istate) > for (i = 0; i < 3; i++) { > if (!ui->mode[i]) > continue; > + if (only_object_name) { > + printf("%s%c", find_unique_abbrev(&ui->oid[i], abbrev), line_terminator); > + continue; > + } > printf("%s%06o %s %d\t", tag_resolve_undo, ui->mode[i], > find_unique_abbrev(&ui->oid[i], abbrev), > i + 1); > @@ -635,6 +645,8 @@ int cmd_ls_files(int argc, const char **argv, const char *cmd_prefix) > DIR_SHOW_IGNORED), > OPT_BOOL('s', "stage", &show_stage, > N_("show staged contents' object name in the output")), > + OPT_BOOL(0, "only-object-name", &only_object_name, > + N_("only show staged contents' object name in the output")), > OPT_BOOL('k', "killed", &show_killed, > N_("show files on the filesystem that need to be removed")), > OPT_BIT(0, "directory", &dir.flags, > @@ -734,6 +746,10 @@ int cmd_ls_files(int argc, const char **argv, const char *cmd_prefix) > die("ls-files --recurse-submodules does not support " > "--error-unmatch"); > > + if (only_object_name && !show_stage && !show_resolve_undo) > + die("ls-files --only-object-name only used with --stage " > + "or --resolve-undo"); missing _(). > + > parse_pathspec(&pathspec, 0, > PATHSPEC_PREFER_CWD, > prefix, argv); > diff --git a/t/t2030-unresolve-info.sh b/t/t2030-unresolve-info.sh > index f691e6d9032..d940226c5f9 100755 > --- a/t/t2030-unresolve-info.sh > +++ b/t/t2030-unresolve-info.sh > @@ -32,6 +32,31 @@ check_resolve_undo () { > test_cmp "$msg.expect" "$msg.actual" > } > > +check_resolve_undo_only_object_name() { > + msg=$1 > + shift > + while case $# in > + 0) break ;; > + 1|2|3) die "Bug in check-resolve-undo test" ;; Use the "BUG" helper in thaht case. > + esac > + do > + path=$1 > + shift > + for stage in 1 2 3 > + do > + sha1=$1 > + shift > + case "$sha1" in > + '') continue ;; > + esac > + sha1=$(git rev-parse --verify "$sha1") missing && here when invoking "git". > +test_expect_success 'git ls-files --stage with --only-object-name' ' > + git init test && > + test_when_finished "rm -rf test" && FWIW you can do all the below with -C to relevant commands and skip the sub-shell. > + ( > + cd test && > + echo a >a.txt && > + echo b >b.txt && > + git add a.txt b.txt && > + oid1=$(git hash-object a.txt) && > + oid2=$(git hash-object b.txt) && > + git ls-files --stage --only-object-name >actual && > + cat >expect <<-EOF && > + $oid1 > + $oid2 > + EOF > + test_cmp expect actual > + ) > +' > + > +test_expect_success 'git ls-files --only-object-name without --stage or --resolve-undo' ' > + git init test && > + test_when_finished "rm -rf test" && > + ( > + cd test && > + echo a >a.txt && > + echo b >b.txt && > + git add a.txt b.txt && > + test_must_fail git ls-files --only-object-name 2>stderr && > + test_i18ngrep "fatal: ls-files --only-object-name only used with --stage or --resolve-undo" stderr use "grep", not "test_i18ngrep".
Ævar Arnfjörð Bjarmason <avarab@gmail.com> 于2022年6月7日周二 01:45写道: > > > On Mon, Jun 06 2022, ZheNing Hu via GitGitGadget wrote: > > > From: ZheNing Hu <adlternative@gmail.com> > > > > `git ls-files --stage` default output format is: > > > > [<tag> ]<mode> <object> <stage> <file> > > > > sometime we want to find a path's corresponding objectname, > > we will parse the output and extract objectname from it > > again and again. > > > > So introduce a new option `--only-object-name` which can only > > output objectname when giving `--stage` or `--resolve-undo`. > > > > Signed-off-by: ZheNing Hu <adlternative@gmail.com> > > --- > > ls-files.c: add --only-object-name option > > > > Something we want to extract objectname from git ls-files --stage, but > > git ls-file don't support something like --format=%(objectname) (which > > git ls-tree have implemented) > > > > So now add a new option --only-object-name which can only output > > objectname. > > > > (Maybe we should add something like git ls-files --format ?) > > Yes I think that would be very useful, especially if we could see if > some of the code could be shared (maybe not). > Maybe I can try to implement it :-) > But in any case shouldn't this be called --name-only to go with "git > ls-tree"'s version of this? Or is there some subtle difference I'm > missing...? > Eh, git ls-tree --name-only will only show file paths, so maybe --only-object-name will be better than --object-name-only in git ls-files. > > +check_resolve_undo_only_object_name() { > > + msg=$1 > > + shift > > + while case $# in > > + 0) break ;; > > + 1|2|3) die "Bug in check-resolve-undo test" ;; > > Use the "BUG" helper in thaht case. > > + esac > > + do > > + path=$1 > > + shift > > + for stage in 1 2 3 > > + do > > + sha1=$1 > > + shift > > + case "$sha1" in > > + '') continue ;; > > + esac > > + sha1=$(git rev-parse --verify "$sha1") > > missing && here when invoking "git". > Sorry, but this function check_resolve_undo_only_object_name() is just a mock version of check_resolve_undo(), so maybe I should fix this function first?
ZheNing Hu <adlternative@gmail.com> writes: >> But in any case shouldn't this be called --name-only to go with "git >> ls-tree"'s version of this? Or is there some subtle difference I'm >> missing...? > > Eh, git ls-tree --name-only will only show file paths, so maybe > --only-object-name will be better than --object-name-only in git > ls-files. Yeah, it is not "--name-only" which is about paths, but "--object-name-only" would be more correct but it is a tad long. I think ls-tree learned "--object-only" for that fairly recently. When in doubt, always check the documentation of a similar command for inspiration. Thanks.
diff --git a/Documentation/git-ls-files.txt b/Documentation/git-ls-files.txt index 0dabf3f0ddc..0e3f4f094f3 100644 --- a/Documentation/git-ls-files.txt +++ b/Documentation/git-ls-files.txt @@ -13,7 +13,7 @@ SYNOPSIS [-c|--cached] [-d|--deleted] [-o|--others] [-i|--|ignored] [-s|--stage] [-u|--unmerged] [-k|--|killed] [-m|--modified] [--directory [--no-empty-directory]] [--eol] - [--deduplicate] + [--deduplicate] [--only-object-name] [-x <pattern>|--exclude=<pattern>] [-X <file>|--exclude-from=<file>] [--exclude-per-directory=<file>] @@ -88,6 +88,10 @@ OPTIONS When any of the `-t`, `--unmerged`, or `--stage` option is in use, this option has no effect. +--only-object-name: + When giving `--stage` or `--resolve-undo` , only output `<object>` + instead of `[<tag> ]<mode> <object> <stage> <file>` format. + -x <pattern>:: --exclude=<pattern>:: Skip untracked files matching pattern. diff --git a/builtin/ls-files.c b/builtin/ls-files.c index e791b65e7e9..fd9c10e9f94 100644 --- a/builtin/ls-files.c +++ b/builtin/ls-files.c @@ -26,6 +26,7 @@ static int show_deleted; static int show_cached; static int show_others; static int show_stage; +static int only_object_name; static int show_unmerged; static int show_resolve_undo; static int show_modified; @@ -241,10 +242,15 @@ static void show_ce(struct repository *repo, struct dir_struct *dir, if (!show_stage) { fputs(tag, stdout); } else { + const char *object_name = repo_find_unique_abbrev(repo, &ce->oid, abbrev); + if (only_object_name) { + printf("%s%c", object_name, line_terminator); + return; + } printf("%s%06o %s %d\t", tag, ce->ce_mode, - repo_find_unique_abbrev(repo, &ce->oid, abbrev), + object_name, ce_stage(ce)); } write_eolinfo(repo->index, ce, fullname); @@ -274,6 +280,10 @@ static void show_ru_info(struct index_state *istate) for (i = 0; i < 3; i++) { if (!ui->mode[i]) continue; + if (only_object_name) { + printf("%s%c", find_unique_abbrev(&ui->oid[i], abbrev), line_terminator); + continue; + } printf("%s%06o %s %d\t", tag_resolve_undo, ui->mode[i], find_unique_abbrev(&ui->oid[i], abbrev), i + 1); @@ -635,6 +645,8 @@ int cmd_ls_files(int argc, const char **argv, const char *cmd_prefix) DIR_SHOW_IGNORED), OPT_BOOL('s', "stage", &show_stage, N_("show staged contents' object name in the output")), + OPT_BOOL(0, "only-object-name", &only_object_name, + N_("only show staged contents' object name in the output")), OPT_BOOL('k', "killed", &show_killed, N_("show files on the filesystem that need to be removed")), OPT_BIT(0, "directory", &dir.flags, @@ -734,6 +746,10 @@ int cmd_ls_files(int argc, const char **argv, const char *cmd_prefix) die("ls-files --recurse-submodules does not support " "--error-unmatch"); + if (only_object_name && !show_stage && !show_resolve_undo) + die("ls-files --only-object-name only used with --stage " + "or --resolve-undo"); + parse_pathspec(&pathspec, 0, PATHSPEC_PREFER_CWD, prefix, argv); diff --git a/t/t2030-unresolve-info.sh b/t/t2030-unresolve-info.sh index f691e6d9032..d940226c5f9 100755 --- a/t/t2030-unresolve-info.sh +++ b/t/t2030-unresolve-info.sh @@ -32,6 +32,31 @@ check_resolve_undo () { test_cmp "$msg.expect" "$msg.actual" } +check_resolve_undo_only_object_name() { + msg=$1 + shift + while case $# in + 0) break ;; + 1|2|3) die "Bug in check-resolve-undo test" ;; + esac + do + path=$1 + shift + for stage in 1 2 3 + do + sha1=$1 + shift + case "$sha1" in + '') continue ;; + esac + sha1=$(git rev-parse --verify "$sha1") + printf "%s\n" $sha1 + done + done >"$msg.expect" && + git ls-files --resolve-undo --only-object-name >"$msg.actual" && + test_cmp "$msg.expect" "$msg.actual" +} + prime_resolve_undo () { git reset --hard && git checkout second^0 && @@ -194,4 +219,12 @@ test_expect_success 'rerere forget (add-add conflict)' ' test_i18ngrep "no remembered" actual ' +test_expect_success '--resolve-undo with --only-object-name' ' + prime_resolve_undo && + check_resolve_undo_only_object_name kept fi/le initial:fi/le second:fi/le third:fi/le && + git checkout second^0 && + echo switching clears && + check_resolve_undo cleared +' + test_done diff --git a/t/t3004-ls-files-basic.sh b/t/t3004-ls-files-basic.sh index a16e25c79bd..e42f6e7e548 100755 --- a/t/t3004-ls-files-basic.sh +++ b/t/t3004-ls-files-basic.sh @@ -52,4 +52,36 @@ test_expect_success SYMLINKS 'ls-files with absolute paths to symlinks' ' test_cmp expect actual ' +test_expect_success 'git ls-files --stage with --only-object-name' ' + git init test && + test_when_finished "rm -rf test" && + ( + cd test && + echo a >a.txt && + echo b >b.txt && + git add a.txt b.txt && + oid1=$(git hash-object a.txt) && + oid2=$(git hash-object b.txt) && + git ls-files --stage --only-object-name >actual && + cat >expect <<-EOF && + $oid1 + $oid2 + EOF + test_cmp expect actual + ) +' + +test_expect_success 'git ls-files --only-object-name without --stage or --resolve-undo' ' + git init test && + test_when_finished "rm -rf test" && + ( + cd test && + echo a >a.txt && + echo b >b.txt && + git add a.txt b.txt && + test_must_fail git ls-files --only-object-name 2>stderr && + test_i18ngrep "fatal: ls-files --only-object-name only used with --stage or --resolve-undo" stderr + ) +' + test_done