ls-files: align format atoms with ls-tree

"git ls-files --format" can be used to format the output of multiple file entries in the index, while "git ls-tree --format" can be used to format the contents of a tree object. However, the current set of %(objecttype), "(objectsize)", and "%(objectsize:padded)" atoms supported by "git ls-files --format" is a subset of what is available in "git ls-tree --format". Users sometimes need to establish a unified view between the index and tree, which can help with comparison or conversion between the two. Therefore, this patch adds the missing atoms to "git ls-files --format". "%(objecttype)" can be used to retrieve the object type corresponding to a file in the index, "(objectsize)" can be used to retrieve the object size corresponding to a file in the index, and "%(objectsize:padded)" is the same as "(objectsize)", except with padded format. Signed-off-by: ZheNing Hu <adlternative@gmail.com> Signed-off-by: Junio C Hamano <gitster@pobox.com>

ZheNing Hu committed May 23, 2023 at 09:00 UTC 4d28c4f75fc12e7795fb2c1db2caedb6d9648af8
3 files changed +68
Documentation/git-ls-files.txt
+6
@@ -270,8 +270,14 @@ interpolated. The following "fieldname" are understood:
270
271 objectmode::
272 The mode of the file which is recorded in the index.
273 +objecttype::
274 + The object type of the file which is recorded in the index.
275 objectname::
276 The name of the file which is recorded in the index.
277 +objectsize[:padded]::
278 + The object size of the file which is recorded in the index
279 + ("-" if the object is a `commit` or `tree`).
280 + It also supports a padded format of size with "%(objectsize:padded)".
281 stage::
282 The stage of the file which is recorded in the index.
283 eolinfo:index::
builtin/ls-files.c
+27
@@ -25,6 +25,9 @@
25 #include "setup.h"
26 #include "submodule.h"
27 #include "submodule-config.h"
28 +#include "object-store.h"
29 +#include "hex.h"
30 +
31
32 static int abbrev;
33 static int show_deleted;
@@ -241,6 +244,24 @@ static void show_submodule(struct repository *superproject,
244 repo_clear(&subrepo);
245 }
246
247 +static void expand_objectsize(struct strbuf *line, const struct object_id *oid,
248 + const enum object_type type, unsigned int padded)
249 +{
250 + if (type == OBJ_BLOB) {
251 + unsigned long size;
252 + if (oid_object_info(the_repository, oid, &size) < 0)
253 + die(_("could not get object info about '%s'"),
254 + oid_to_hex(oid));
255 + if (padded)
256 + strbuf_addf(line, "%7"PRIuMAX, (uintmax_t)size);
257 + else
258 + strbuf_addf(line, "%"PRIuMAX, (uintmax_t)size);
259 + } else if (padded) {
260 + strbuf_addf(line, "%7s", "-");
261 + } else {
262 + strbuf_addstr(line, "-");
263 + }
264 +}
265 struct show_index_data {
266 const char *pathname;
267 struct index_state *istate;
@@ -272,6 +293,12 @@ static size_t expand_show_index(struct strbuf *sb, const char *start,
293 strbuf_addf(sb, "%06o", data->ce->ce_mode);
294 else if (skip_prefix(start, "(objectname)", &p))
295 strbuf_add_unique_abbrev(sb, &data->ce->oid, abbrev);
296 + else if (skip_prefix(start, "(objecttype)", &p))
297 + strbuf_addstr(sb, type_name(object_type(data->ce->ce_mode)));
298 + else if (skip_prefix(start, "(objectsize:padded)", &p))
299 + expand_objectsize(sb, &data->ce->oid, object_type(data->ce->ce_mode), 1);
300 + else if (skip_prefix(start, "(objectsize)", &p))
301 + expand_objectsize(sb, &data->ce->oid, object_type(data->ce->ce_mode), 0);
302 else if (skip_prefix(start, "(stage)", &p))
303 strbuf_addf(sb, "%d", ce_stage(data->ce));
304 else if (skip_prefix(start, "(eolinfo:index)", &p))
t/t3013-ls-files-format.sh
+35
@@ -38,6 +38,41 @@ test_expect_success 'git ls-files --format objectname v.s. -s' '
38 test_cmp expect actual
39 '
40
41 +test_expect_success 'git ls-files --format objecttype' '
42 + git ls-files --format="%(objectname)" o1.txt o4.txt o6.txt >objectname &&
43 + git cat-file --batch-check="%(objecttype)" >expect <objectname &&
44 + git ls-files --format="%(objecttype)" o1.txt o4.txt o6.txt >actual &&
45 + test_cmp expect actual
46 +'
47 +
48 +test_expect_success 'git ls-files --format objectsize' '
49 + cat>expect <<-\EOF &&
50 +26
51 +29
52 +27
53 +26
54 +-
55 +26
56 + EOF
57 + git ls-files --format="%(objectsize)" >actual &&
58 +
59 + test_cmp expect actual
60 +'
61 +
62 +test_expect_success 'git ls-files --format objectsize:padded' '
63 + cat>expect <<-\EOF &&
64 + 26
65 + 29
66 + 27
67 + 26
68 + -
69 + 26
70 + EOF
71 + git ls-files --format="%(objectsize:padded)" >actual &&
72 +
73 + test_cmp expect actual
74 +'
75 +
76 test_expect_success 'git ls-files --format v.s. --eol' '
77 git ls-files --eol >tmp &&
78 sed -e "s/ / /g" -e "s/ */ /g" tmp >expect 2>err &&