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:
parent
c0f9c70589
commit
b0176ce6b5
@ -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
|
||||||
|
@ -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);
|
||||||
|
@ -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
|
||||||
|
Loading…
Reference in New Issue
Block a user