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;
|
rev->abbrev_commit = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (rev->commit_format == CMIT_FMT_USERFORMAT && !w.decorate)
|
||||||
|
decoration_style = 0;
|
||||||
|
|
||||||
if (decoration_style) {
|
if (decoration_style) {
|
||||||
const struct string_list *config_exclude =
|
const struct string_list *config_exclude =
|
||||||
repo_config_get_value_multi(the_repository,
|
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)
|
int flags, void *cb_data)
|
||||||
{
|
{
|
||||||
struct object *obj;
|
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;
|
struct decoration_filter *filter = (struct decoration_filter *)cb_data;
|
||||||
|
|
||||||
if (filter && !ref_filter_match(refname, filter))
|
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;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
obj = parse_object(the_repository, oid);
|
objtype = oid_object_info(the_repository, oid, NULL);
|
||||||
if (!obj)
|
if (objtype < 0)
|
||||||
return 0;
|
return 0;
|
||||||
|
obj = lookup_object_by_type(the_repository, oid, objtype);
|
||||||
|
|
||||||
if (starts_with(refname, "refs/heads/"))
|
if (starts_with(refname, "refs/heads/"))
|
||||||
type = DECORATION_REF_LOCAL;
|
deco_type = DECORATION_REF_LOCAL;
|
||||||
else if (starts_with(refname, "refs/remotes/"))
|
else if (starts_with(refname, "refs/remotes/"))
|
||||||
type = DECORATION_REF_REMOTE;
|
deco_type = DECORATION_REF_REMOTE;
|
||||||
else if (starts_with(refname, "refs/tags/"))
|
else if (starts_with(refname, "refs/tags/"))
|
||||||
type = DECORATION_REF_TAG;
|
deco_type = DECORATION_REF_TAG;
|
||||||
else if (!strcmp(refname, "refs/stash"))
|
else if (!strcmp(refname, "refs/stash"))
|
||||||
type = DECORATION_REF_STASH;
|
deco_type = DECORATION_REF_STASH;
|
||||||
else if (!strcmp(refname, "HEAD"))
|
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) {
|
while (obj->type == OBJ_TAG) {
|
||||||
|
if (!obj->parsed)
|
||||||
|
parse_object(the_repository, &obj->oid);
|
||||||
obj = ((struct tag *)obj)->tagged;
|
obj = ((struct tag *)obj)->tagged;
|
||||||
if (!obj)
|
if (!obj)
|
||||||
break;
|
break;
|
||||||
if (!obj->parsed)
|
|
||||||
parse_object(the_repository, &obj->oid);
|
|
||||||
add_name_decoration(DECORATION_REF_TAG, refname, obj);
|
add_name_decoration(DECORATION_REF_TAG, refname, obj);
|
||||||
}
|
}
|
||||||
return 0;
|
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;
|
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 *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;
|
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);
|
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);
|
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 *object_list_insert(struct object *item,
|
||||||
struct object_list **list_p);
|
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':
|
case 'S':
|
||||||
w->source = 1;
|
w->source = 1;
|
||||||
break;
|
break;
|
||||||
|
case 'd':
|
||||||
|
case 'D':
|
||||||
|
w->decorate = 1;
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
return 0;
|
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);
|
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 {
|
struct userformat_want {
|
||||||
unsigned notes:1;
|
unsigned notes:1;
|
||||||
unsigned source: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);
|
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);
|
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,
|
static int mark_object_seen(const struct object_id *oid,
|
||||||
enum object_type type,
|
enum object_type type,
|
||||||
int exclude,
|
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_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' '
|
test_expect_success 'log --end-of-options' '
|
||||||
git update-ref refs/heads/--source HEAD &&
|
git update-ref refs/heads/--source HEAD &&
|
||||||
git log --end-of-options --source >actual &&
|
git log --end-of-options --source >actual &&
|
||||||
|
Loading…
x
Reference in New Issue
Block a user