builtin/describe: introduce --broken flag

git-describe tells you the version number you're at, or errors out, e.g.
when you run it outside of a repository, which may happen when downloading
a tar ball instead of using git to obtain the source code.

To keep this property of only erroring out, when not in a repository,
severe (submodule) errors must be downgraded to reporting them gently
instead of having git-describe error out completely.

To achieve that a flag '--broken' is introduced, which is in the same
vein as '--dirty' but uses an actual child process to check for dirtiness.
When that child dies unexpectedly, we'll append '-broken' instead of
'-dirty'.

Signed-off-by: Stefan Beller <sbeller@google.com>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
This commit is contained in:
Stefan Beller 2017-03-21 15:57:18 -07:00 committed by Junio C Hamano
parent c0f9c70589
commit b0176ce6b5
3 changed files with 66 additions and 12 deletions

View File

@ -30,9 +30,14 @@ OPTIONS
Commit-ish object names to describe. Defaults to HEAD if omitted. Commit-ish object names to describe. Defaults to HEAD if omitted.
--dirty[=<mark>]:: --dirty[=<mark>]::
Describe the working tree. --broken[=<mark>]::
It means describe HEAD and appends <mark> (`-dirty` by Describe the state of the working tree. When the working
default) if the working tree is dirty. tree matches HEAD, the output is the same as "git describe
HEAD". If the working tree has local modification "-dirty"
is appended to it. If a repository is corrupt and Git
cannot determine if there is local modification, Git will
error out, unless `--broken' is given, which appends
the suffix "-broken" instead.
--all:: --all::
Instead of using only the annotated tags, use any ref Instead of using only the annotated tags, use any ref

View File

@ -9,6 +9,7 @@
#include "diff.h" #include "diff.h"
#include "hashmap.h" #include "hashmap.h"
#include "argv-array.h" #include "argv-array.h"
#include "run-command.h"
#define SEEN (1u << 0) #define SEEN (1u << 0)
#define MAX_TAGS (FLAG_BITS - 1) #define MAX_TAGS (FLAG_BITS - 1)
@ -31,7 +32,7 @@ static int have_util;
static struct string_list patterns = STRING_LIST_INIT_NODUP; static struct string_list patterns = STRING_LIST_INIT_NODUP;
static struct string_list exclude_patterns = STRING_LIST_INIT_NODUP; static struct string_list exclude_patterns = STRING_LIST_INIT_NODUP;
static int always; static int always;
static const char *dirty; static const char *suffix, *dirty, *broken;
/* diff-index command arguments to check if working tree is dirty. */ /* diff-index command arguments to check if working tree is dirty. */
static const char *diff_index_args[] = { static const char *diff_index_args[] = {
@ -292,8 +293,8 @@ static void describe(const char *arg, int last_one)
display_name(n); display_name(n);
if (longformat) if (longformat)
show_suffix(0, n->tag ? &n->tag->tagged->oid : &oid); show_suffix(0, n->tag ? &n->tag->tagged->oid : &oid);
if (dirty) if (suffix)
printf("%s", dirty); printf("%s", suffix);
printf("\n"); printf("\n");
return; return;
} }
@ -369,8 +370,8 @@ static void describe(const char *arg, int last_one)
struct object_id *oid = &cmit->object.oid; struct object_id *oid = &cmit->object.oid;
if (always) { if (always) {
printf("%s", find_unique_abbrev(oid->hash, abbrev)); printf("%s", find_unique_abbrev(oid->hash, abbrev));
if (dirty) if (suffix)
printf("%s", dirty); printf("%s", suffix);
printf("\n"); printf("\n");
return; return;
} }
@ -413,8 +414,8 @@ static void describe(const char *arg, int last_one)
display_name(all_matches[0].name); display_name(all_matches[0].name);
if (abbrev) if (abbrev)
show_suffix(all_matches[0].depth, &cmit->object.oid); show_suffix(all_matches[0].depth, &cmit->object.oid);
if (dirty) if (suffix)
printf("%s", dirty); printf("%s", suffix);
printf("\n"); printf("\n");
if (!last_one) if (!last_one)
@ -445,6 +446,9 @@ int cmd_describe(int argc, const char **argv, const char *prefix)
{OPTION_STRING, 0, "dirty", &dirty, N_("mark"), {OPTION_STRING, 0, "dirty", &dirty, N_("mark"),
N_("append <mark> on dirty working tree (default: \"-dirty\")"), N_("append <mark> on dirty working tree (default: \"-dirty\")"),
PARSE_OPT_OPTARG, NULL, (intptr_t) "-dirty"}, PARSE_OPT_OPTARG, NULL, (intptr_t) "-dirty"},
{OPTION_STRING, 0, "broken", &broken, N_("mark"),
N_("append <mark> on broken working tree (default: \"-broken\")"),
PARSE_OPT_OPTARG, NULL, (intptr_t) "-broken"},
OPT_END(), OPT_END(),
}; };
@ -493,7 +497,28 @@ int cmd_describe(int argc, const char **argv, const char *prefix)
die(_("No names found, cannot describe anything.")); die(_("No names found, cannot describe anything."));
if (argc == 0) { if (argc == 0) {
if (dirty) { if (broken) {
struct child_process cp = CHILD_PROCESS_INIT;
argv_array_pushv(&cp.args, diff_index_args);
cp.git_cmd = 1;
cp.no_stdin = 1;
cp.no_stdout = 1;
if (!dirty)
dirty = "-dirty";
switch (run_command(&cp)) {
case 0:
suffix = NULL;
break;
case 1:
suffix = dirty;
break;
default:
/* diff-index aborted abnormally */
suffix = broken;
}
} else if (dirty) {
static struct lock_file index_lock; static struct lock_file index_lock;
int fd; int fd;
@ -506,11 +531,15 @@ int cmd_describe(int argc, const char **argv, const char *prefix)
if (!cmd_diff_index(ARRAY_SIZE(diff_index_args) - 1, if (!cmd_diff_index(ARRAY_SIZE(diff_index_args) - 1,
diff_index_args, prefix)) diff_index_args, prefix))
dirty = NULL; suffix = NULL;
else
suffix = dirty;
} }
describe("HEAD", 1); describe("HEAD", 1);
} else if (dirty) { } else if (dirty) {
die(_("--dirty is incompatible with commit-ishes")); die(_("--dirty is incompatible with commit-ishes"));
} else if (broken) {
die(_("--broken is incompatible with commit-ishes"));
} else { } else {
while (argc-- > 0) while (argc-- > 0)
describe(*argv++, argc == 0); describe(*argv++, argc == 0);

View File

@ -233,4 +233,24 @@ test_expect_success 'describe --contains and --no-match' '
test_cmp expect actual test_cmp expect actual
' '
test_expect_success 'setup and absorb a submodule' '
test_create_repo sub1 &&
test_commit -C sub1 initial &&
git submodule add ./sub1 &&
git submodule absorbgitdirs &&
git commit -a -m "add submodule" &&
git describe --dirty >expect &&
git describe --broken >out &&
test_cmp expect out
'
test_expect_success 'describe chokes on severly broken submodules' '
mv .git/modules/sub1/ .git/modules/sub_moved &&
test_must_fail git describe --dirty
'
test_expect_success 'describe ignoring a borken submodule' '
git describe --broken >out &&
grep broken out
'
test_done test_done