Merge branch 'sb/describe-blob'
"git describe" was taught to dig trees deeper to find a <commit-ish>:<path> that refers to a given blob object. * sb/describe-blob: builtin/describe.c: describe a blob builtin/describe.c: factor out describe_commit builtin/describe.c: print debug statements earlier builtin/describe.c: rename `oid` to avoid variable shadowing revision.h: introduce blob/tree walking in order of the commits list-objects.c: factor out traverse_trees_and_blobs t6120: fix typo in test name
This commit is contained in:
commit
556de1a8e3
@ -3,14 +3,14 @@ git-describe(1)
|
|||||||
|
|
||||||
NAME
|
NAME
|
||||||
----
|
----
|
||||||
git-describe - Describe a commit using the most recent tag reachable from it
|
git-describe - Give an object a human readable name based on an available ref
|
||||||
|
|
||||||
|
|
||||||
SYNOPSIS
|
SYNOPSIS
|
||||||
--------
|
--------
|
||||||
[verse]
|
[verse]
|
||||||
'git describe' [--all] [--tags] [--contains] [--abbrev=<n>] [<commit-ish>...]
|
'git describe' [--all] [--tags] [--contains] [--abbrev=<n>] [<commit-ish>...]
|
||||||
'git describe' [--all] [--tags] [--contains] [--abbrev=<n>] --dirty[=<mark>]
|
'git describe' [--all] [--tags] [--contains] [--abbrev=<n>] --dirty[=<mark>]
|
||||||
|
'git describe' <blob>
|
||||||
|
|
||||||
DESCRIPTION
|
DESCRIPTION
|
||||||
-----------
|
-----------
|
||||||
@ -24,6 +24,12 @@ By default (without --all or --tags) `git describe` only shows
|
|||||||
annotated tags. For more information about creating annotated tags
|
annotated tags. For more information about creating annotated tags
|
||||||
see the -a and -s options to linkgit:git-tag[1].
|
see the -a and -s options to linkgit:git-tag[1].
|
||||||
|
|
||||||
|
If the given object refers to a blob, it will be described
|
||||||
|
as `<commit-ish>:<path>`, such that the blob can be found
|
||||||
|
at `<path>` in the `<commit-ish>`, which itself describes the
|
||||||
|
first commit in which this blob occurs in a reverse revision walk
|
||||||
|
from HEAD.
|
||||||
|
|
||||||
OPTIONS
|
OPTIONS
|
||||||
-------
|
-------
|
||||||
<commit-ish>...::
|
<commit-ish>...::
|
||||||
@ -186,6 +192,14 @@ selected and output. Here fewest commits different is defined as
|
|||||||
the number of commits which would be shown by `git log tag..input`
|
the number of commits which would be shown by `git log tag..input`
|
||||||
will be the smallest number of commits possible.
|
will be the smallest number of commits possible.
|
||||||
|
|
||||||
|
BUGS
|
||||||
|
----
|
||||||
|
|
||||||
|
Tree objects as well as tag objects not pointing at commits, cannot be described.
|
||||||
|
When describing blobs, the lightweight tags pointing at blobs are ignored,
|
||||||
|
but the blob is still described as <committ-ish>:<path> despite the lightweight
|
||||||
|
tag being favorable.
|
||||||
|
|
||||||
GIT
|
GIT
|
||||||
---
|
---
|
||||||
Part of the linkgit:git[1] suite
|
Part of the linkgit:git[1] suite
|
||||||
|
@ -686,6 +686,11 @@ ifdef::git-rev-list[]
|
|||||||
all object IDs which I need to download if I have the commit
|
all object IDs which I need to download if I have the commit
|
||||||
object _bar_ but not _foo_''.
|
object _bar_ but not _foo_''.
|
||||||
|
|
||||||
|
--in-commit-order::
|
||||||
|
Print tree and blob ids in order of the commits. The tree
|
||||||
|
and blob ids are printed after they are first referenced
|
||||||
|
by a commit.
|
||||||
|
|
||||||
--objects-edge::
|
--objects-edge::
|
||||||
Similar to `--objects`, but also print the IDs of excluded
|
Similar to `--objects`, but also print the IDs of excluded
|
||||||
commits prefixed with a ``-'' character. This is used by
|
commits prefixed with a ``-'' character. This is used by
|
||||||
|
@ -3,6 +3,7 @@
|
|||||||
#include "lockfile.h"
|
#include "lockfile.h"
|
||||||
#include "commit.h"
|
#include "commit.h"
|
||||||
#include "tag.h"
|
#include "tag.h"
|
||||||
|
#include "blob.h"
|
||||||
#include "refs.h"
|
#include "refs.h"
|
||||||
#include "builtin.h"
|
#include "builtin.h"
|
||||||
#include "exec_cmd.h"
|
#include "exec_cmd.h"
|
||||||
@ -12,6 +13,8 @@
|
|||||||
#include "hashmap.h"
|
#include "hashmap.h"
|
||||||
#include "argv-array.h"
|
#include "argv-array.h"
|
||||||
#include "run-command.h"
|
#include "run-command.h"
|
||||||
|
#include "revision.h"
|
||||||
|
#include "list-objects.h"
|
||||||
|
|
||||||
#define MAX_TAGS (FLAG_BITS - 1)
|
#define MAX_TAGS (FLAG_BITS - 1)
|
||||||
|
|
||||||
@ -256,7 +259,7 @@ static unsigned long finish_depth_computation(
|
|||||||
return seen_commits;
|
return seen_commits;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void display_name(struct commit_name *n)
|
static void append_name(struct commit_name *n, struct strbuf *dst)
|
||||||
{
|
{
|
||||||
if (n->prio == 2 && !n->tag) {
|
if (n->prio == 2 && !n->tag) {
|
||||||
n->tag = lookup_tag(&n->oid);
|
n->tag = lookup_tag(&n->oid);
|
||||||
@ -272,19 +275,18 @@ static void display_name(struct commit_name *n)
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (n->tag)
|
if (n->tag)
|
||||||
printf("%s", n->tag->tag);
|
strbuf_addstr(dst, n->tag->tag);
|
||||||
else
|
else
|
||||||
printf("%s", n->path);
|
strbuf_addstr(dst, n->path);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void show_suffix(int depth, const struct object_id *oid)
|
static void append_suffix(int depth, const struct object_id *oid, struct strbuf *dst)
|
||||||
{
|
{
|
||||||
printf("-%d-g%s", depth, find_unique_abbrev(oid->hash, abbrev));
|
strbuf_addf(dst, "-%d-g%s", depth, find_unique_abbrev(oid->hash, abbrev));
|
||||||
}
|
}
|
||||||
|
|
||||||
static void describe(const char *arg, int last_one)
|
static void describe_commit(struct object_id *oid, struct strbuf *dst)
|
||||||
{
|
{
|
||||||
struct object_id oid;
|
|
||||||
struct commit *cmit, *gave_up_on = NULL;
|
struct commit *cmit, *gave_up_on = NULL;
|
||||||
struct commit_list *list;
|
struct commit_list *list;
|
||||||
struct commit_name *n;
|
struct commit_name *n;
|
||||||
@ -293,30 +295,25 @@ static void describe(const char *arg, int last_one)
|
|||||||
unsigned long seen_commits = 0;
|
unsigned long seen_commits = 0;
|
||||||
unsigned int unannotated_cnt = 0;
|
unsigned int unannotated_cnt = 0;
|
||||||
|
|
||||||
if (get_oid(arg, &oid))
|
cmit = lookup_commit_reference(oid);
|
||||||
die(_("Not a valid object name %s"), arg);
|
|
||||||
cmit = lookup_commit_reference(&oid);
|
|
||||||
if (!cmit)
|
|
||||||
die(_("%s is not a valid '%s' object"), arg, commit_type);
|
|
||||||
|
|
||||||
n = find_commit_name(&cmit->object.oid);
|
n = find_commit_name(&cmit->object.oid);
|
||||||
if (n && (tags || all || n->prio == 2)) {
|
if (n && (tags || all || n->prio == 2)) {
|
||||||
/*
|
/*
|
||||||
* Exact match to an existing ref.
|
* Exact match to an existing ref.
|
||||||
*/
|
*/
|
||||||
display_name(n);
|
append_name(n, dst);
|
||||||
if (longformat)
|
if (longformat)
|
||||||
show_suffix(0, n->tag ? &n->tag->tagged->oid : &oid);
|
append_suffix(0, n->tag ? &n->tag->tagged->oid : oid, dst);
|
||||||
if (suffix)
|
if (suffix)
|
||||||
printf("%s", suffix);
|
strbuf_addstr(dst, suffix);
|
||||||
printf("\n");
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!max_candidates)
|
if (!max_candidates)
|
||||||
die(_("no tag exactly matches '%s'"), oid_to_hex(&cmit->object.oid));
|
die(_("no tag exactly matches '%s'"), oid_to_hex(&cmit->object.oid));
|
||||||
if (debug)
|
if (debug)
|
||||||
fprintf(stderr, _("searching to describe %s\n"), arg);
|
fprintf(stderr, _("No exact match on refs or tags, searching to describe\n"));
|
||||||
|
|
||||||
if (!have_util) {
|
if (!have_util) {
|
||||||
struct hashmap_iter iter;
|
struct hashmap_iter iter;
|
||||||
@ -381,22 +378,21 @@ static void describe(const char *arg, int last_one)
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (!match_cnt) {
|
if (!match_cnt) {
|
||||||
struct object_id *oid = &cmit->object.oid;
|
struct object_id *cmit_oid = &cmit->object.oid;
|
||||||
if (always) {
|
if (always) {
|
||||||
printf("%s", find_unique_abbrev(oid->hash, abbrev));
|
strbuf_addstr(dst, find_unique_abbrev(cmit_oid->hash, abbrev));
|
||||||
if (suffix)
|
if (suffix)
|
||||||
printf("%s", suffix);
|
strbuf_addstr(dst, suffix);
|
||||||
printf("\n");
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if (unannotated_cnt)
|
if (unannotated_cnt)
|
||||||
die(_("No annotated tags can describe '%s'.\n"
|
die(_("No annotated tags can describe '%s'.\n"
|
||||||
"However, there were unannotated tags: try --tags."),
|
"However, there were unannotated tags: try --tags."),
|
||||||
oid_to_hex(oid));
|
oid_to_hex(cmit_oid));
|
||||||
else
|
else
|
||||||
die(_("No tags can describe '%s'.\n"
|
die(_("No tags can describe '%s'.\n"
|
||||||
"Try --always, or create some tags."),
|
"Try --always, or create some tags."),
|
||||||
oid_to_hex(oid));
|
oid_to_hex(cmit_oid));
|
||||||
}
|
}
|
||||||
|
|
||||||
QSORT(all_matches, match_cnt, compare_pt);
|
QSORT(all_matches, match_cnt, compare_pt);
|
||||||
@ -434,15 +430,86 @@ static void describe(const char *arg, int last_one)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
display_name(all_matches[0].name);
|
append_name(all_matches[0].name, dst);
|
||||||
if (abbrev)
|
if (abbrev)
|
||||||
show_suffix(all_matches[0].depth, &cmit->object.oid);
|
append_suffix(all_matches[0].depth, &cmit->object.oid, dst);
|
||||||
if (suffix)
|
if (suffix)
|
||||||
printf("%s", suffix);
|
strbuf_addstr(dst, suffix);
|
||||||
printf("\n");
|
}
|
||||||
|
|
||||||
|
struct process_commit_data {
|
||||||
|
struct object_id current_commit;
|
||||||
|
struct object_id looking_for;
|
||||||
|
struct strbuf *dst;
|
||||||
|
struct rev_info *revs;
|
||||||
|
};
|
||||||
|
|
||||||
|
static void process_commit(struct commit *commit, void *data)
|
||||||
|
{
|
||||||
|
struct process_commit_data *pcd = data;
|
||||||
|
pcd->current_commit = commit->object.oid;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void process_object(struct object *obj, const char *path, void *data)
|
||||||
|
{
|
||||||
|
struct process_commit_data *pcd = data;
|
||||||
|
|
||||||
|
if (!oidcmp(&pcd->looking_for, &obj->oid) && !pcd->dst->len) {
|
||||||
|
reset_revision_walk();
|
||||||
|
describe_commit(&pcd->current_commit, pcd->dst);
|
||||||
|
strbuf_addf(pcd->dst, ":%s", path);
|
||||||
|
free_commit_list(pcd->revs->commits);
|
||||||
|
pcd->revs->commits = NULL;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void describe_blob(struct object_id oid, struct strbuf *dst)
|
||||||
|
{
|
||||||
|
struct rev_info revs;
|
||||||
|
struct argv_array args = ARGV_ARRAY_INIT;
|
||||||
|
struct process_commit_data pcd = { null_oid, oid, dst, &revs};
|
||||||
|
|
||||||
|
argv_array_pushl(&args, "internal: The first arg is not parsed",
|
||||||
|
"--objects", "--in-commit-order", "--reverse", "HEAD",
|
||||||
|
NULL);
|
||||||
|
|
||||||
|
init_revisions(&revs, NULL);
|
||||||
|
if (setup_revisions(args.argc, args.argv, &revs, NULL) > 1)
|
||||||
|
BUG("setup_revisions could not handle all args?");
|
||||||
|
|
||||||
|
if (prepare_revision_walk(&revs))
|
||||||
|
die("revision walk setup failed");
|
||||||
|
|
||||||
|
traverse_commit_list(&revs, process_commit, process_object, &pcd);
|
||||||
|
reset_revision_walk();
|
||||||
|
}
|
||||||
|
|
||||||
|
static void describe(const char *arg, int last_one)
|
||||||
|
{
|
||||||
|
struct object_id oid;
|
||||||
|
struct commit *cmit;
|
||||||
|
struct strbuf sb = STRBUF_INIT;
|
||||||
|
|
||||||
|
if (debug)
|
||||||
|
fprintf(stderr, _("describe %s\n"), arg);
|
||||||
|
|
||||||
|
if (get_oid(arg, &oid))
|
||||||
|
die(_("Not a valid object name %s"), arg);
|
||||||
|
cmit = lookup_commit_reference_gently(&oid, 1);
|
||||||
|
|
||||||
|
if (cmit)
|
||||||
|
describe_commit(&oid, &sb);
|
||||||
|
else if (lookup_blob(&oid))
|
||||||
|
describe_blob(oid, &sb);
|
||||||
|
else
|
||||||
|
die(_("%s is neither a commit nor blob"), arg);
|
||||||
|
|
||||||
|
puts(sb.buf);
|
||||||
|
|
||||||
if (!last_one)
|
if (!last_one)
|
||||||
clear_commit_marks(cmit, -1);
|
clear_commit_marks(cmit, -1);
|
||||||
|
|
||||||
|
strbuf_release(&sb);
|
||||||
}
|
}
|
||||||
|
|
||||||
int cmd_describe(int argc, const char **argv, const char *prefix)
|
int cmd_describe(int argc, const char **argv, const char *prefix)
|
||||||
|
@ -214,27 +214,17 @@ static void add_pending_tree(struct rev_info *revs, struct tree *tree)
|
|||||||
add_pending_object(revs, &tree->object, "");
|
add_pending_object(revs, &tree->object, "");
|
||||||
}
|
}
|
||||||
|
|
||||||
static void do_traverse(struct rev_info *revs,
|
static void traverse_trees_and_blobs(struct rev_info *revs,
|
||||||
show_commit_fn show_commit,
|
struct strbuf *base,
|
||||||
show_object_fn show_object,
|
show_object_fn show_object,
|
||||||
void *show_data,
|
void *show_data,
|
||||||
filter_object_fn filter_fn,
|
filter_object_fn filter_fn,
|
||||||
void *filter_data)
|
void *filter_data)
|
||||||
{
|
{
|
||||||
int i;
|
int i;
|
||||||
struct commit *commit;
|
|
||||||
struct strbuf base;
|
|
||||||
|
|
||||||
strbuf_init(&base, PATH_MAX);
|
assert(base->len == 0);
|
||||||
while ((commit = get_revision(revs)) != NULL) {
|
|
||||||
/*
|
|
||||||
* an uninteresting boundary commit may not have its tree
|
|
||||||
* parsed yet, but we are not going to show them anyway
|
|
||||||
*/
|
|
||||||
if (commit->tree)
|
|
||||||
add_pending_tree(revs, commit->tree);
|
|
||||||
show_commit(commit, show_data);
|
|
||||||
}
|
|
||||||
for (i = 0; i < revs->pending.nr; i++) {
|
for (i = 0; i < revs->pending.nr; i++) {
|
||||||
struct object_array_entry *pending = revs->pending.objects + i;
|
struct object_array_entry *pending = revs->pending.objects + i;
|
||||||
struct object *obj = pending->item;
|
struct object *obj = pending->item;
|
||||||
@ -251,13 +241,13 @@ static void do_traverse(struct rev_info *revs,
|
|||||||
path = "";
|
path = "";
|
||||||
if (obj->type == OBJ_TREE) {
|
if (obj->type == OBJ_TREE) {
|
||||||
process_tree(revs, (struct tree *)obj, show_object,
|
process_tree(revs, (struct tree *)obj, show_object,
|
||||||
&base, path, show_data,
|
base, path, show_data,
|
||||||
filter_fn, filter_data);
|
filter_fn, filter_data);
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
if (obj->type == OBJ_BLOB) {
|
if (obj->type == OBJ_BLOB) {
|
||||||
process_blob(revs, (struct blob *)obj, show_object,
|
process_blob(revs, (struct blob *)obj, show_object,
|
||||||
&base, path, show_data,
|
base, path, show_data,
|
||||||
filter_fn, filter_data);
|
filter_fn, filter_data);
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
@ -265,7 +255,42 @@ static void do_traverse(struct rev_info *revs,
|
|||||||
oid_to_hex(&obj->oid), name);
|
oid_to_hex(&obj->oid), name);
|
||||||
}
|
}
|
||||||
object_array_clear(&revs->pending);
|
object_array_clear(&revs->pending);
|
||||||
strbuf_release(&base);
|
}
|
||||||
|
|
||||||
|
static void do_traverse(struct rev_info *revs,
|
||||||
|
show_commit_fn show_commit,
|
||||||
|
show_object_fn show_object,
|
||||||
|
void *show_data,
|
||||||
|
filter_object_fn filter_fn,
|
||||||
|
void *filter_data)
|
||||||
|
{
|
||||||
|
struct commit *commit;
|
||||||
|
struct strbuf csp; /* callee's scratch pad */
|
||||||
|
strbuf_init(&csp, PATH_MAX);
|
||||||
|
|
||||||
|
while ((commit = get_revision(revs)) != NULL) {
|
||||||
|
/*
|
||||||
|
* an uninteresting boundary commit may not have its tree
|
||||||
|
* parsed yet, but we are not going to show them anyway
|
||||||
|
*/
|
||||||
|
if (commit->tree)
|
||||||
|
add_pending_tree(revs, commit->tree);
|
||||||
|
show_commit(commit, show_data);
|
||||||
|
|
||||||
|
if (revs->tree_blobs_in_commit_order)
|
||||||
|
/*
|
||||||
|
* NEEDSWORK: Adding the tree and then flushing it here
|
||||||
|
* needs a reallocation for each commit. Can we pass the
|
||||||
|
* tree directory without allocation churn?
|
||||||
|
*/
|
||||||
|
traverse_trees_and_blobs(revs, &csp,
|
||||||
|
show_object, show_data,
|
||||||
|
filter_fn, filter_data);
|
||||||
|
}
|
||||||
|
traverse_trees_and_blobs(revs, &csp,
|
||||||
|
show_object, show_data,
|
||||||
|
filter_fn, filter_data);
|
||||||
|
strbuf_release(&csp);
|
||||||
}
|
}
|
||||||
|
|
||||||
void traverse_commit_list(struct rev_info *revs,
|
void traverse_commit_list(struct rev_info *revs,
|
||||||
|
@ -1855,6 +1855,8 @@ static int handle_revision_opt(struct rev_info *revs, int argc, const char **arg
|
|||||||
revs->dense = 0;
|
revs->dense = 0;
|
||||||
} else if (!strcmp(arg, "--show-all")) {
|
} else if (!strcmp(arg, "--show-all")) {
|
||||||
revs->show_all = 1;
|
revs->show_all = 1;
|
||||||
|
} else if (!strcmp(arg, "--in-commit-order")) {
|
||||||
|
revs->tree_blobs_in_commit_order = 1;
|
||||||
} else if (!strcmp(arg, "--remove-empty")) {
|
} else if (!strcmp(arg, "--remove-empty")) {
|
||||||
revs->remove_empty_trees = 1;
|
revs->remove_empty_trees = 1;
|
||||||
} else if (!strcmp(arg, "--merges")) {
|
} else if (!strcmp(arg, "--merges")) {
|
||||||
|
@ -121,7 +121,8 @@ struct rev_info {
|
|||||||
bisect:1,
|
bisect:1,
|
||||||
ancestry_path:1,
|
ancestry_path:1,
|
||||||
first_parent_only:1,
|
first_parent_only:1,
|
||||||
line_level_traverse:1;
|
line_level_traverse:1,
|
||||||
|
tree_blobs_in_commit_order:1;
|
||||||
|
|
||||||
/* Diff flags */
|
/* Diff flags */
|
||||||
unsigned int diff:1,
|
unsigned int diff:1,
|
||||||
|
77
t/t6100-rev-list-in-order.sh
Executable file
77
t/t6100-rev-list-in-order.sh
Executable file
@ -0,0 +1,77 @@
|
|||||||
|
#!/bin/sh
|
||||||
|
|
||||||
|
test_description='rev-list testing in-commit-order'
|
||||||
|
|
||||||
|
. ./test-lib.sh
|
||||||
|
|
||||||
|
test_expect_success 'setup a commit history with trees, blobs' '
|
||||||
|
for x in one two three four
|
||||||
|
do
|
||||||
|
echo $x >$x &&
|
||||||
|
git add $x &&
|
||||||
|
git commit -m "add file $x" ||
|
||||||
|
return 1
|
||||||
|
done &&
|
||||||
|
for x in four three
|
||||||
|
do
|
||||||
|
git rm $x &&
|
||||||
|
git commit -m "remove $x" ||
|
||||||
|
return 1
|
||||||
|
done
|
||||||
|
'
|
||||||
|
|
||||||
|
test_expect_success 'rev-list --in-commit-order' '
|
||||||
|
git rev-list --in-commit-order --objects HEAD >actual.raw &&
|
||||||
|
cut -c 1-40 >actual <actual.raw &&
|
||||||
|
|
||||||
|
git cat-file --batch-check="%(objectname)" >expect.raw <<-\EOF &&
|
||||||
|
HEAD^{commit}
|
||||||
|
HEAD^{tree}
|
||||||
|
HEAD^{tree}:one
|
||||||
|
HEAD^{tree}:two
|
||||||
|
HEAD~1^{commit}
|
||||||
|
HEAD~1^{tree}
|
||||||
|
HEAD~1^{tree}:three
|
||||||
|
HEAD~2^{commit}
|
||||||
|
HEAD~2^{tree}
|
||||||
|
HEAD~2^{tree}:four
|
||||||
|
HEAD~3^{commit}
|
||||||
|
# HEAD~3^{tree} skipped, same as HEAD~1^{tree}
|
||||||
|
HEAD~4^{commit}
|
||||||
|
# HEAD~4^{tree} skipped, same as HEAD^{tree}
|
||||||
|
HEAD~5^{commit}
|
||||||
|
HEAD~5^{tree}
|
||||||
|
EOF
|
||||||
|
grep -v "#" >expect <expect.raw &&
|
||||||
|
|
||||||
|
test_cmp expect actual
|
||||||
|
'
|
||||||
|
|
||||||
|
test_expect_success 'rev-list lists blobs and trees after commits' '
|
||||||
|
git rev-list --objects HEAD >actual.raw &&
|
||||||
|
cut -c 1-40 >actual <actual.raw &&
|
||||||
|
|
||||||
|
git cat-file --batch-check="%(objectname)" >expect.raw <<-\EOF &&
|
||||||
|
HEAD^{commit}
|
||||||
|
HEAD~1^{commit}
|
||||||
|
HEAD~2^{commit}
|
||||||
|
HEAD~3^{commit}
|
||||||
|
HEAD~4^{commit}
|
||||||
|
HEAD~5^{commit}
|
||||||
|
HEAD^{tree}
|
||||||
|
HEAD^{tree}:one
|
||||||
|
HEAD^{tree}:two
|
||||||
|
HEAD~1^{tree}
|
||||||
|
HEAD~1^{tree}:three
|
||||||
|
HEAD~2^{tree}
|
||||||
|
HEAD~2^{tree}:four
|
||||||
|
# HEAD~3^{tree} skipped, same as HEAD~1^{tree}
|
||||||
|
# HEAD~4^{tree} skipped, same as HEAD^{tree}
|
||||||
|
HEAD~5^{tree}
|
||||||
|
EOF
|
||||||
|
grep -v "#" >expect <expect.raw &&
|
||||||
|
|
||||||
|
test_cmp expect actual
|
||||||
|
'
|
||||||
|
|
||||||
|
test_done
|
@ -304,12 +304,46 @@ test_expect_success 'describe chokes on severely broken submodules' '
|
|||||||
mv .git/modules/sub1/ .git/modules/sub_moved &&
|
mv .git/modules/sub1/ .git/modules/sub_moved &&
|
||||||
test_must_fail git describe --dirty
|
test_must_fail git describe --dirty
|
||||||
'
|
'
|
||||||
test_expect_success 'describe ignoring a borken submodule' '
|
test_expect_success 'describe ignoring a broken submodule' '
|
||||||
git describe --broken >out &&
|
git describe --broken >out &&
|
||||||
test_when_finished "mv .git/modules/sub_moved .git/modules/sub1" &&
|
test_when_finished "mv .git/modules/sub_moved .git/modules/sub1" &&
|
||||||
grep broken out
|
grep broken out
|
||||||
'
|
'
|
||||||
|
|
||||||
|
test_expect_success 'describe a blob at a directly tagged commit' '
|
||||||
|
echo "make it a unique blob" >file &&
|
||||||
|
git add file && git commit -m "content in file" &&
|
||||||
|
git tag -a -m "latest annotated tag" unique-file &&
|
||||||
|
git describe HEAD:file >actual &&
|
||||||
|
echo "unique-file:file" >expect &&
|
||||||
|
test_cmp expect actual
|
||||||
|
'
|
||||||
|
|
||||||
|
test_expect_success 'describe a blob with its first introduction' '
|
||||||
|
git commit --allow-empty -m "empty commit" &&
|
||||||
|
git rm file &&
|
||||||
|
git commit -m "delete blob" &&
|
||||||
|
git revert HEAD &&
|
||||||
|
git commit --allow-empty -m "empty commit" &&
|
||||||
|
git describe HEAD:file >actual &&
|
||||||
|
echo "unique-file:file" >expect &&
|
||||||
|
test_cmp expect actual
|
||||||
|
'
|
||||||
|
|
||||||
|
test_expect_success 'describe directly tagged blob' '
|
||||||
|
git tag test-blob unique-file:file &&
|
||||||
|
git describe test-blob >actual &&
|
||||||
|
echo "unique-file:file" >expect &&
|
||||||
|
# suboptimal: we rather want to see "test-blob"
|
||||||
|
test_cmp expect actual
|
||||||
|
'
|
||||||
|
|
||||||
|
test_expect_success 'describe tag object' '
|
||||||
|
git tag test-blob-1 -a -m msg unique-file:file &&
|
||||||
|
test_must_fail git describe test-blob-1 2>actual &&
|
||||||
|
test_i18ngrep "fatal: test-blob-1 is neither a commit nor blob" actual
|
||||||
|
'
|
||||||
|
|
||||||
test_expect_failure ULIMIT_STACK_SIZE 'name-rev works in a deep repo' '
|
test_expect_failure ULIMIT_STACK_SIZE 'name-rev works in a deep repo' '
|
||||||
i=1 &&
|
i=1 &&
|
||||||
while test $i -lt 8000
|
while test $i -lt 8000
|
||||||
|
Loading…
x
Reference in New Issue
Block a user