Merge branch 'jk/log-decorate-optim'
Optimize "git log" for cases where we wasted cycles to load ref decoration data that may not be needed. * jk/log-decorate-optim: load_ref_decorations(): fix decoration with tags add_ref_decoration(): rename s/type/deco_type/ load_ref_decorations(): avoid parsing non-tag objects object.h: add lookup_object_by_type() function object.h: expand docstring for lookup_unknown_object() log: avoid loading decorations for userformats that don't need it pretty.h: update and expand docstring for userformat_find_requirements()
This commit is contained in:
commit
c9d6d8a193
@ -245,6 +245,9 @@ static void cmd_log_init_finish(int argc, const char **argv, const char *prefix,
|
||||
rev->abbrev_commit = 0;
|
||||
}
|
||||
|
||||
if (rev->commit_format == CMIT_FMT_USERFORMAT && !w.decorate)
|
||||
decoration_style = 0;
|
||||
|
||||
if (decoration_style) {
|
||||
const struct string_list *config_exclude =
|
||||
repo_config_get_value_multi(the_repository,
|
||||
|
24
log-tree.c
24
log-tree.c
@ -134,7 +134,8 @@ static int add_ref_decoration(const char *refname, const struct object_id *oid,
|
||||
int flags, void *cb_data)
|
||||
{
|
||||
struct object *obj;
|
||||
enum decoration_type type = DECORATION_NONE;
|
||||
enum object_type objtype;
|
||||
enum decoration_type deco_type = DECORATION_NONE;
|
||||
struct decoration_filter *filter = (struct decoration_filter *)cb_data;
|
||||
|
||||
if (filter && !ref_filter_match(refname, filter))
|
||||
@ -155,28 +156,29 @@ static int add_ref_decoration(const char *refname, const struct object_id *oid,
|
||||
return 0;
|
||||
}
|
||||
|
||||
obj = parse_object(the_repository, oid);
|
||||
if (!obj)
|
||||
objtype = oid_object_info(the_repository, oid, NULL);
|
||||
if (objtype < 0)
|
||||
return 0;
|
||||
obj = lookup_object_by_type(the_repository, oid, objtype);
|
||||
|
||||
if (starts_with(refname, "refs/heads/"))
|
||||
type = DECORATION_REF_LOCAL;
|
||||
deco_type = DECORATION_REF_LOCAL;
|
||||
else if (starts_with(refname, "refs/remotes/"))
|
||||
type = DECORATION_REF_REMOTE;
|
||||
deco_type = DECORATION_REF_REMOTE;
|
||||
else if (starts_with(refname, "refs/tags/"))
|
||||
type = DECORATION_REF_TAG;
|
||||
deco_type = DECORATION_REF_TAG;
|
||||
else if (!strcmp(refname, "refs/stash"))
|
||||
type = DECORATION_REF_STASH;
|
||||
deco_type = DECORATION_REF_STASH;
|
||||
else if (!strcmp(refname, "HEAD"))
|
||||
type = DECORATION_REF_HEAD;
|
||||
deco_type = DECORATION_REF_HEAD;
|
||||
|
||||
add_name_decoration(type, refname, obj);
|
||||
add_name_decoration(deco_type, refname, obj);
|
||||
while (obj->type == OBJ_TAG) {
|
||||
if (!obj->parsed)
|
||||
parse_object(the_repository, &obj->oid);
|
||||
obj = ((struct tag *)obj)->tagged;
|
||||
if (!obj)
|
||||
break;
|
||||
if (!obj->parsed)
|
||||
parse_object(the_repository, &obj->oid);
|
||||
add_name_decoration(DECORATION_REF_TAG, refname, obj);
|
||||
}
|
||||
return 0;
|
||||
|
18
object.c
18
object.c
@ -185,6 +185,24 @@ struct object *lookup_unknown_object(struct repository *r, const struct object_i
|
||||
return obj;
|
||||
}
|
||||
|
||||
struct object *lookup_object_by_type(struct repository *r,
|
||||
const struct object_id *oid,
|
||||
enum object_type type)
|
||||
{
|
||||
switch (type) {
|
||||
case OBJ_COMMIT:
|
||||
return (struct object *)lookup_commit(r, oid);
|
||||
case OBJ_TREE:
|
||||
return (struct object *)lookup_tree(r, oid);
|
||||
case OBJ_TAG:
|
||||
return (struct object *)lookup_tag(r, oid);
|
||||
case OBJ_BLOB:
|
||||
return (struct object *)lookup_blob(r, oid);
|
||||
default:
|
||||
die("BUG: unknown object type %d", type);
|
||||
}
|
||||
}
|
||||
|
||||
struct object *parse_object_buffer(struct repository *r, const struct object_id *oid, enum object_type type, unsigned long size, void *buffer, int *eaten_p)
|
||||
{
|
||||
struct object *obj;
|
||||
|
20
object.h
20
object.h
@ -144,9 +144,27 @@ struct object *parse_object_or_die(const struct object_id *oid, const char *name
|
||||
*/
|
||||
struct object *parse_object_buffer(struct repository *r, const struct object_id *oid, enum object_type type, unsigned long size, void *buffer, int *eaten_p);
|
||||
|
||||
/** Returns the object, with potentially excess memory allocated. **/
|
||||
/*
|
||||
* Allocate and return an object struct, even if you do not know the type of
|
||||
* the object. The returned object may have its "type" field set to a real type
|
||||
* (if somebody previously called lookup_blob(), etc), or it may be set to
|
||||
* OBJ_NONE. In the latter case, subsequent calls to lookup_blob(), etc, will
|
||||
* set the type field as appropriate.
|
||||
*
|
||||
* Use this when you do not know the expected type of an object and want to
|
||||
* avoid parsing it for efficiency reasons. Try to avoid it otherwise; it
|
||||
* may allocate excess memory, since the returned object must be as large as
|
||||
* the maximum struct of any type.
|
||||
*/
|
||||
struct object *lookup_unknown_object(struct repository *r, const struct object_id *oid);
|
||||
|
||||
/*
|
||||
* Dispatch to the appropriate lookup_blob(), lookup_commit(), etc, based on
|
||||
* "type".
|
||||
*/
|
||||
struct object *lookup_object_by_type(struct repository *r, const struct object_id *oid,
|
||||
enum object_type type);
|
||||
|
||||
struct object_list *object_list_insert(struct object *item,
|
||||
struct object_list **list_p);
|
||||
|
||||
|
4
pretty.c
4
pretty.c
@ -1735,6 +1735,10 @@ static size_t userformat_want_item(struct strbuf *sb, const char *placeholder,
|
||||
case 'S':
|
||||
w->source = 1;
|
||||
break;
|
||||
case 'd':
|
||||
case 'D':
|
||||
w->decorate = 1;
|
||||
break;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
8
pretty.h
8
pretty.h
@ -65,12 +65,16 @@ static inline int cmit_fmt_is_mail(enum cmit_fmt fmt)
|
||||
return (fmt == CMIT_FMT_EMAIL || fmt == CMIT_FMT_MBOXRD);
|
||||
}
|
||||
|
||||
/*
|
||||
* Examine the user-specified format given by "fmt" (or if NULL, the global one
|
||||
* previously saved by get_commit_format()), and set flags based on which items
|
||||
* the format will need when it is expanded.
|
||||
*/
|
||||
struct userformat_want {
|
||||
unsigned notes:1;
|
||||
unsigned source:1;
|
||||
unsigned decorate:1;
|
||||
};
|
||||
|
||||
/* Set the flag "w->notes" if there is placeholder %N in "fmt". */
|
||||
void userformat_find_requirements(const char *fmt, struct userformat_want *w);
|
||||
|
||||
/*
|
||||
|
18
reachable.c
18
reachable.c
@ -159,24 +159,6 @@ int add_unseen_recent_objects_to_traversal(struct rev_info *revs,
|
||||
FOR_EACH_OBJECT_LOCAL_ONLY);
|
||||
}
|
||||
|
||||
static void *lookup_object_by_type(struct repository *r,
|
||||
const struct object_id *oid,
|
||||
enum object_type type)
|
||||
{
|
||||
switch (type) {
|
||||
case OBJ_COMMIT:
|
||||
return lookup_commit(r, oid);
|
||||
case OBJ_TREE:
|
||||
return lookup_tree(r, oid);
|
||||
case OBJ_TAG:
|
||||
return lookup_tag(r, oid);
|
||||
case OBJ_BLOB:
|
||||
return lookup_blob(r, oid);
|
||||
default:
|
||||
die("BUG: unknown object type %d", type);
|
||||
}
|
||||
}
|
||||
|
||||
static int mark_object_seen(const struct object_id *oid,
|
||||
enum object_type type,
|
||||
int exclude,
|
||||
|
@ -1915,6 +1915,20 @@ test_expect_success '--exclude-promisor-objects does not BUG-crash' '
|
||||
test_must_fail git log --exclude-promisor-objects source-a
|
||||
'
|
||||
|
||||
test_expect_success 'log --decorate includes all levels of tag annotated tags' '
|
||||
git checkout -b branch &&
|
||||
git commit --allow-empty -m "new commit" &&
|
||||
git tag lightweight HEAD &&
|
||||
git tag -m annotated annotated HEAD &&
|
||||
git tag -m double-0 double-0 HEAD &&
|
||||
git tag -m double-1 double-1 double-0 &&
|
||||
cat >expect <<-\EOF &&
|
||||
HEAD -> branch, tag: lightweight, tag: double-1, tag: double-0, tag: annotated
|
||||
EOF
|
||||
git log -1 --format="%D" >actual &&
|
||||
test_cmp expect actual
|
||||
'
|
||||
|
||||
test_expect_success 'log --end-of-options' '
|
||||
git update-ref refs/heads/--source HEAD &&
|
||||
git log --end-of-options --source >actual &&
|
||||
|
Loading…
Reference in New Issue
Block a user