Git fork

Merge branch 'lo/repo-info'

A new subcommand "git repo" gives users a way to grab various
repository characteristics.

* lo/repo-info:
repo: add the --format flag
repo: add the field layout.shallow
repo: add the field layout.bare
repo: add the field references.format
repo: declare the repo command

+337
+1
.gitignore
··· 139 139 /git-repack 140 140 /git-replace 141 141 /git-replay 142 + /git-repo 142 143 /git-request-pull 143 144 /git-rerere 144 145 /git-reset
+84
Documentation/git-repo.adoc
··· 1 + git-repo(1) 2 + =========== 3 + 4 + NAME 5 + ---- 6 + git-repo - Retrieve information about the repository 7 + 8 + SYNOPSIS 9 + -------- 10 + [synopsis] 11 + git repo info [--format=(keyvalue|nul)] [<key>...] 12 + 13 + DESCRIPTION 14 + ----------- 15 + Retrieve information about the repository. 16 + 17 + THIS COMMAND IS EXPERIMENTAL. THE BEHAVIOR MAY CHANGE. 18 + 19 + COMMANDS 20 + -------- 21 + `info [--format=(keyvalue|nul)] [<key>...]`:: 22 + Retrieve metadata-related information about the current repository. Only 23 + the requested data will be returned based on their keys (see "INFO KEYS" 24 + section below). 25 + + 26 + The values are returned in the same order in which their respective keys were 27 + requested. 28 + + 29 + The output format can be chosen through the flag `--format`. Two formats are 30 + supported: 31 + + 32 + `keyvalue`::: 33 + output key-value pairs one per line using the `=` character as 34 + the delimiter between the key and the value. Values containing "unusual" 35 + characters are quoted as explained for the configuration variable 36 + `core.quotePath` (see linkgit:git-config[1]). This is the default. 37 + 38 + `nul`::: 39 + similar to `keyvalue`, but using a newline character as the delimiter 40 + between the key and the value and using a NUL character after each value. 41 + This format is better suited for being parsed by another applications than 42 + `keyvalue`. Unlike in the `keyvalue` format, the values are never quoted. 43 + 44 + INFO KEYS 45 + --------- 46 + In order to obtain a set of values from `git repo info`, you should provide 47 + the keys that identify them. Here's a list of the available keys and the 48 + values that they return: 49 + 50 + `layout.bare`:: 51 + `true` if this is a bare repository, otherwise `false`. 52 + 53 + `layout.shallow`:: 54 + `true` if this is a shallow repository, otherwise `false`. 55 + 56 + `references.format`:: 57 + The reference storage format. The valid values are: 58 + + 59 + include::ref-storage-format.adoc[] 60 + 61 + EXAMPLES 62 + -------- 63 + 64 + * Retrieves the reference format of the current repository: 65 + + 66 + ------------ 67 + git repo info references.format 68 + ------------ 69 + + 70 + 71 + * Retrieves whether the current repository is bare and whether it is shallow 72 + using the `nul` format: 73 + + 74 + ------------ 75 + git repo info --format=nul layout.bare layout.shallow 76 + ------------ 77 + 78 + SEE ALSO 79 + -------- 80 + linkgit:git-rev-parse[1] 81 + 82 + GIT 83 + --- 84 + Part of the linkgit:git[1] suite
+1
Documentation/meson.build
··· 116 116 'git-repack.adoc' : 1, 117 117 'git-replace.adoc' : 1, 118 118 'git-replay.adoc' : 1, 119 + 'git-repo.adoc' : 1, 119 120 'git-request-pull.adoc' : 1, 120 121 'git-rerere.adoc' : 1, 121 122 'git-reset.adoc' : 1,
+1
Makefile
··· 1306 1306 BUILTIN_OBJS += builtin/repack.o 1307 1307 BUILTIN_OBJS += builtin/replace.o 1308 1308 BUILTIN_OBJS += builtin/replay.o 1309 + BUILTIN_OBJS += builtin/repo.o 1309 1310 BUILTIN_OBJS += builtin/rerere.o 1310 1311 BUILTIN_OBJS += builtin/reset.o 1311 1312 BUILTIN_OBJS += builtin/rev-list.o
+1
builtin.h
··· 216 216 int cmd_remote_fd(int argc, const char **argv, const char *prefix, struct repository *repo); 217 217 int cmd_repack(int argc, const char **argv, const char *prefix, struct repository *repo); 218 218 int cmd_replay(int argc, const char **argv, const char *prefix, struct repository *repo); 219 + int cmd_repo(int argc, const char **argv, const char *prefix, struct repository *repo); 219 220 int cmd_rerere(int argc, const char **argv, const char *prefix, struct repository *repo); 220 221 int cmd_reset(int argc, const char **argv, const char *prefix, struct repository *repo); 221 222 int cmd_restore(int argc, const char **argv, const char *prefix, struct repository *repo);
+150
builtin/repo.c
··· 1 + #define USE_THE_REPOSITORY_VARIABLE 2 + 3 + #include "builtin.h" 4 + #include "environment.h" 5 + #include "parse-options.h" 6 + #include "quote.h" 7 + #include "refs.h" 8 + #include "strbuf.h" 9 + #include "shallow.h" 10 + 11 + static const char *const repo_usage[] = { 12 + "git repo info [--format=(keyvalue|nul)] [<key>...]", 13 + NULL 14 + }; 15 + 16 + typedef int get_value_fn(struct repository *repo, struct strbuf *buf); 17 + 18 + enum output_format { 19 + FORMAT_KEYVALUE, 20 + FORMAT_NUL_TERMINATED, 21 + }; 22 + 23 + struct field { 24 + const char *key; 25 + get_value_fn *get_value; 26 + }; 27 + 28 + static int get_layout_bare(struct repository *repo UNUSED, struct strbuf *buf) 29 + { 30 + strbuf_addstr(buf, is_bare_repository() ? "true" : "false"); 31 + return 0; 32 + } 33 + 34 + static int get_layout_shallow(struct repository *repo, struct strbuf *buf) 35 + { 36 + strbuf_addstr(buf, 37 + is_repository_shallow(repo) ? "true" : "false"); 38 + return 0; 39 + } 40 + 41 + static int get_references_format(struct repository *repo, struct strbuf *buf) 42 + { 43 + strbuf_addstr(buf, 44 + ref_storage_format_to_name(repo->ref_storage_format)); 45 + return 0; 46 + } 47 + 48 + /* repo_info_fields keys must be in lexicographical order */ 49 + static const struct field repo_info_fields[] = { 50 + { "layout.bare", get_layout_bare }, 51 + { "layout.shallow", get_layout_shallow }, 52 + { "references.format", get_references_format }, 53 + }; 54 + 55 + static int repo_info_fields_cmp(const void *va, const void *vb) 56 + { 57 + const struct field *a = va; 58 + const struct field *b = vb; 59 + 60 + return strcmp(a->key, b->key); 61 + } 62 + 63 + static get_value_fn *get_value_fn_for_key(const char *key) 64 + { 65 + const struct field search_key = { key, NULL }; 66 + const struct field *found = bsearch(&search_key, repo_info_fields, 67 + ARRAY_SIZE(repo_info_fields), 68 + sizeof(*found), 69 + repo_info_fields_cmp); 70 + return found ? found->get_value : NULL; 71 + } 72 + 73 + static int print_fields(int argc, const char **argv, 74 + struct repository *repo, 75 + enum output_format format) 76 + { 77 + int ret = 0; 78 + struct strbuf valbuf = STRBUF_INIT; 79 + struct strbuf quotbuf = STRBUF_INIT; 80 + 81 + for (int i = 0; i < argc; i++) { 82 + get_value_fn *get_value; 83 + const char *key = argv[i]; 84 + 85 + get_value = get_value_fn_for_key(key); 86 + 87 + if (!get_value) { 88 + ret = error(_("key '%s' not found"), key); 89 + continue; 90 + } 91 + 92 + strbuf_reset(&valbuf); 93 + strbuf_reset(&quotbuf); 94 + 95 + get_value(repo, &valbuf); 96 + 97 + switch (format) { 98 + case FORMAT_KEYVALUE: 99 + quote_c_style(valbuf.buf, &quotbuf, NULL, 0); 100 + printf("%s=%s\n", key, quotbuf.buf); 101 + break; 102 + case FORMAT_NUL_TERMINATED: 103 + printf("%s\n%s%c", key, valbuf.buf, '\0'); 104 + break; 105 + default: 106 + BUG("not a valid output format: %d", format); 107 + } 108 + } 109 + 110 + strbuf_release(&valbuf); 111 + strbuf_release(&quotbuf); 112 + return ret; 113 + } 114 + 115 + static int repo_info(int argc, const char **argv, const char *prefix, 116 + struct repository *repo) 117 + { 118 + const char *format_str = "keyvalue"; 119 + enum output_format format; 120 + struct option options[] = { 121 + OPT_STRING(0, "format", &format_str, N_("format"), 122 + N_("output format")), 123 + OPT_END() 124 + }; 125 + 126 + argc = parse_options(argc, argv, prefix, options, repo_usage, 0); 127 + 128 + if (!strcmp(format_str, "keyvalue")) 129 + format = FORMAT_KEYVALUE; 130 + else if (!strcmp(format_str, "nul")) 131 + format = FORMAT_NUL_TERMINATED; 132 + else 133 + die(_("invalid format '%s'"), format_str); 134 + 135 + return print_fields(argc, argv, repo, format); 136 + } 137 + 138 + int cmd_repo(int argc, const char **argv, const char *prefix, 139 + struct repository *repo) 140 + { 141 + parse_opt_subcommand_fn *fn = NULL; 142 + struct option options[] = { 143 + OPT_SUBCOMMAND("info", &fn, repo_info), 144 + OPT_END() 145 + }; 146 + 147 + argc = parse_options(argc, argv, prefix, options, repo_usage, 0); 148 + 149 + return fn(argc, argv, prefix, repo); 150 + }
+1
command-list.txt
··· 164 164 git-repack ancillarymanipulators complete 165 165 git-replace ancillarymanipulators complete 166 166 git-replay plumbingmanipulators 167 + git-repo plumbinginterrogators 167 168 git-request-pull foreignscminterface complete 168 169 git-rerere ancillaryinterrogators 169 170 git-reset mainporcelain history
+1
git.c
··· 611 611 { "repack", cmd_repack, RUN_SETUP }, 612 612 { "replace", cmd_replace, RUN_SETUP }, 613 613 { "replay", cmd_replay, RUN_SETUP }, 614 + { "repo", cmd_repo, RUN_SETUP }, 614 615 { "rerere", cmd_rerere, RUN_SETUP }, 615 616 { "reset", cmd_reset, RUN_SETUP }, 616 617 { "restore", cmd_restore, RUN_SETUP | NEED_WORK_TREE },
+1
meson.build
··· 645 645 'builtin/repack.c', 646 646 'builtin/replace.c', 647 647 'builtin/replay.c', 648 + 'builtin/repo.c', 648 649 'builtin/rerere.c', 649 650 'builtin/reset.c', 650 651 'builtin/rev-list.c',
+1
t/meson.build
··· 233 233 't1700-split-index.sh', 234 234 't1701-racy-split-index.sh', 235 235 't1800-hook.sh', 236 + 't1900-repo.sh', 236 237 't2000-conflict-when-checking-files-out.sh', 237 238 't2002-checkout-cache-u.sh', 238 239 't2003-checkout-cache-mkdir.sh',
+95
t/t1900-repo.sh
··· 1 + #!/bin/sh 2 + 3 + test_description='test git repo-info' 4 + 5 + . ./test-lib.sh 6 + 7 + # Test whether a key-value pair is correctly returned 8 + # 9 + # Usage: test_repo_info <label> <init command> <repo_name> <key> <expected value> 10 + # 11 + # Arguments: 12 + # label: the label of the test 13 + # init_command: a command which creates a repository 14 + # repo_name: the name of the repository that will be created in init_command 15 + # key: the key of the field that is being tested 16 + # expected_value: the value that the field should contain 17 + test_repo_info () { 18 + label=$1 19 + init_command=$2 20 + repo_name=$3 21 + key=$4 22 + expected_value=$5 23 + 24 + test_expect_success "setup: $label" ' 25 + eval "$init_command $repo_name" 26 + ' 27 + 28 + test_expect_success "keyvalue: $label" ' 29 + echo "$key=$expected_value" > expect && 30 + git -C "$repo_name" repo info "$key" >actual && 31 + test_cmp expect actual 32 + ' 33 + 34 + test_expect_success "nul: $label" ' 35 + printf "%s\n%s\0" "$key" "$expected_value" >expect && 36 + git -C "$repo_name" repo info --format=nul "$key" >actual && 37 + test_cmp_bin expect actual 38 + ' 39 + } 40 + 41 + test_repo_info 'ref format files is retrieved correctly' \ 42 + 'git init --ref-format=files' 'format-files' 'references.format' 'files' 43 + 44 + test_repo_info 'ref format reftable is retrieved correctly' \ 45 + 'git init --ref-format=reftable' 'format-reftable' 'references.format' 'reftable' 46 + 47 + test_repo_info 'bare repository = false is retrieved correctly' \ 48 + 'git init' 'nonbare' 'layout.bare' 'false' 49 + 50 + test_repo_info 'bare repository = true is retrieved correctly' \ 51 + 'git init --bare' 'bare' 'layout.bare' 'true' 52 + 53 + test_repo_info 'shallow repository = false is retrieved correctly' \ 54 + 'git init' 'nonshallow' 'layout.shallow' 'false' 55 + 56 + test_expect_success 'setup remote' ' 57 + git init remote && 58 + echo x >remote/x && 59 + git -C remote add x && 60 + git -C remote commit -m x 61 + ' 62 + 63 + test_repo_info 'shallow repository = true is retrieved correctly' \ 64 + 'git clone --depth 1 "file://$PWD/remote"' 'shallow' 'layout.shallow' 'true' 65 + 66 + test_expect_success 'values returned in order requested' ' 67 + cat >expect <<-\EOF && 68 + layout.bare=false 69 + references.format=files 70 + layout.bare=false 71 + EOF 72 + git init --ref-format=files ordered && 73 + git -C ordered repo info layout.bare references.format layout.bare >actual && 74 + test_cmp expect actual 75 + ' 76 + 77 + test_expect_success 'git-repo-info fails if an invalid key is requested' ' 78 + echo "error: key ${SQ}foo${SQ} not found" >expect && 79 + test_must_fail git repo info foo 2>actual && 80 + test_cmp expect actual 81 + ' 82 + 83 + test_expect_success 'git-repo-info outputs data even if there is an invalid field' ' 84 + echo "references.format=$(test_detect_ref_format)" >expect && 85 + test_must_fail git repo info foo references.format bar >actual && 86 + test_cmp expect actual 87 + ' 88 + 89 + test_expect_success 'git-repo-info aborts when requesting an invalid format' ' 90 + echo "fatal: invalid format ${SQ}foo${SQ}" >expect && 91 + test_must_fail git repo info --format=foo 2>actual && 92 + test_cmp expect actual 93 + ' 94 + 95 + test_done