Skip to content

Commit c9d6d8a

Browse files
committed
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()
2 parents 01369fd + d1ed8d6 commit c9d6d8a

File tree

8 files changed

+77
-32
lines changed

8 files changed

+77
-32
lines changed

builtin/log.c

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -245,6 +245,9 @@ static void cmd_log_init_finish(int argc, const char **argv, const char *prefix,
245245
rev->abbrev_commit = 0;
246246
}
247247

248+
if (rev->commit_format == CMIT_FMT_USERFORMAT && !w.decorate)
249+
decoration_style = 0;
250+
248251
if (decoration_style) {
249252
const struct string_list *config_exclude =
250253
repo_config_get_value_multi(the_repository,

log-tree.c

Lines changed: 13 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -134,7 +134,8 @@ static int add_ref_decoration(const char *refname, const struct object_id *oid,
134134
int flags, void *cb_data)
135135
{
136136
struct object *obj;
137-
enum decoration_type type = DECORATION_NONE;
137+
enum object_type objtype;
138+
enum decoration_type deco_type = DECORATION_NONE;
138139
struct decoration_filter *filter = (struct decoration_filter *)cb_data;
139140

140141
if (filter && !ref_filter_match(refname, filter))
@@ -155,28 +156,29 @@ static int add_ref_decoration(const char *refname, const struct object_id *oid,
155156
return 0;
156157
}
157158

158-
obj = parse_object(the_repository, oid);
159-
if (!obj)
159+
objtype = oid_object_info(the_repository, oid, NULL);
160+
if (objtype < 0)
160161
return 0;
162+
obj = lookup_object_by_type(the_repository, oid, objtype);
161163

162164
if (starts_with(refname, "refs/heads/"))
163-
type = DECORATION_REF_LOCAL;
165+
deco_type = DECORATION_REF_LOCAL;
164166
else if (starts_with(refname, "refs/remotes/"))
165-
type = DECORATION_REF_REMOTE;
167+
deco_type = DECORATION_REF_REMOTE;
166168
else if (starts_with(refname, "refs/tags/"))
167-
type = DECORATION_REF_TAG;
169+
deco_type = DECORATION_REF_TAG;
168170
else if (!strcmp(refname, "refs/stash"))
169-
type = DECORATION_REF_STASH;
171+
deco_type = DECORATION_REF_STASH;
170172
else if (!strcmp(refname, "HEAD"))
171-
type = DECORATION_REF_HEAD;
173+
deco_type = DECORATION_REF_HEAD;
172174

173-
add_name_decoration(type, refname, obj);
175+
add_name_decoration(deco_type, refname, obj);
174176
while (obj->type == OBJ_TAG) {
177+
if (!obj->parsed)
178+
parse_object(the_repository, &obj->oid);
175179
obj = ((struct tag *)obj)->tagged;
176180
if (!obj)
177181
break;
178-
if (!obj->parsed)
179-
parse_object(the_repository, &obj->oid);
180182
add_name_decoration(DECORATION_REF_TAG, refname, obj);
181183
}
182184
return 0;

object.c

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -185,6 +185,24 @@ struct object *lookup_unknown_object(struct repository *r, const struct object_i
185185
return obj;
186186
}
187187

188+
struct object *lookup_object_by_type(struct repository *r,
189+
const struct object_id *oid,
190+
enum object_type type)
191+
{
192+
switch (type) {
193+
case OBJ_COMMIT:
194+
return (struct object *)lookup_commit(r, oid);
195+
case OBJ_TREE:
196+
return (struct object *)lookup_tree(r, oid);
197+
case OBJ_TAG:
198+
return (struct object *)lookup_tag(r, oid);
199+
case OBJ_BLOB:
200+
return (struct object *)lookup_blob(r, oid);
201+
default:
202+
die("BUG: unknown object type %d", type);
203+
}
204+
}
205+
188206
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)
189207
{
190208
struct object *obj;

object.h

Lines changed: 19 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -144,9 +144,27 @@ struct object *parse_object_or_die(const struct object_id *oid, const char *name
144144
*/
145145
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);
146146

147-
/** Returns the object, with potentially excess memory allocated. **/
147+
/*
148+
* Allocate and return an object struct, even if you do not know the type of
149+
* the object. The returned object may have its "type" field set to a real type
150+
* (if somebody previously called lookup_blob(), etc), or it may be set to
151+
* OBJ_NONE. In the latter case, subsequent calls to lookup_blob(), etc, will
152+
* set the type field as appropriate.
153+
*
154+
* Use this when you do not know the expected type of an object and want to
155+
* avoid parsing it for efficiency reasons. Try to avoid it otherwise; it
156+
* may allocate excess memory, since the returned object must be as large as
157+
* the maximum struct of any type.
158+
*/
148159
struct object *lookup_unknown_object(struct repository *r, const struct object_id *oid);
149160

161+
/*
162+
* Dispatch to the appropriate lookup_blob(), lookup_commit(), etc, based on
163+
* "type".
164+
*/
165+
struct object *lookup_object_by_type(struct repository *r, const struct object_id *oid,
166+
enum object_type type);
167+
150168
struct object_list *object_list_insert(struct object *item,
151169
struct object_list **list_p);
152170

pretty.c

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1735,6 +1735,10 @@ static size_t userformat_want_item(struct strbuf *sb, const char *placeholder,
17351735
case 'S':
17361736
w->source = 1;
17371737
break;
1738+
case 'd':
1739+
case 'D':
1740+
w->decorate = 1;
1741+
break;
17381742
}
17391743
return 0;
17401744
}

pretty.h

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -65,12 +65,16 @@ static inline int cmit_fmt_is_mail(enum cmit_fmt fmt)
6565
return (fmt == CMIT_FMT_EMAIL || fmt == CMIT_FMT_MBOXRD);
6666
}
6767

68+
/*
69+
* Examine the user-specified format given by "fmt" (or if NULL, the global one
70+
* previously saved by get_commit_format()), and set flags based on which items
71+
* the format will need when it is expanded.
72+
*/
6873
struct userformat_want {
6974
unsigned notes:1;
7075
unsigned source:1;
76+
unsigned decorate:1;
7177
};
72-
73-
/* Set the flag "w->notes" if there is placeholder %N in "fmt". */
7478
void userformat_find_requirements(const char *fmt, struct userformat_want *w);
7579

7680
/*

reachable.c

Lines changed: 0 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -159,24 +159,6 @@ int add_unseen_recent_objects_to_traversal(struct rev_info *revs,
159159
FOR_EACH_OBJECT_LOCAL_ONLY);
160160
}
161161

162-
static void *lookup_object_by_type(struct repository *r,
163-
const struct object_id *oid,
164-
enum object_type type)
165-
{
166-
switch (type) {
167-
case OBJ_COMMIT:
168-
return lookup_commit(r, oid);
169-
case OBJ_TREE:
170-
return lookup_tree(r, oid);
171-
case OBJ_TAG:
172-
return lookup_tag(r, oid);
173-
case OBJ_BLOB:
174-
return lookup_blob(r, oid);
175-
default:
176-
die("BUG: unknown object type %d", type);
177-
}
178-
}
179-
180162
static int mark_object_seen(const struct object_id *oid,
181163
enum object_type type,
182164
int exclude,

t/t4202-log.sh

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1915,6 +1915,20 @@ test_expect_success '--exclude-promisor-objects does not BUG-crash' '
19151915
test_must_fail git log --exclude-promisor-objects source-a
19161916
'
19171917

1918+
test_expect_success 'log --decorate includes all levels of tag annotated tags' '
1919+
git checkout -b branch &&
1920+
git commit --allow-empty -m "new commit" &&
1921+
git tag lightweight HEAD &&
1922+
git tag -m annotated annotated HEAD &&
1923+
git tag -m double-0 double-0 HEAD &&
1924+
git tag -m double-1 double-1 double-0 &&
1925+
cat >expect <<-\EOF &&
1926+
HEAD -> branch, tag: lightweight, tag: double-1, tag: double-0, tag: annotated
1927+
EOF
1928+
git log -1 --format="%D" >actual &&
1929+
test_cmp expect actual
1930+
'
1931+
19181932
test_expect_success 'log --end-of-options' '
19191933
git update-ref refs/heads/--source HEAD &&
19201934
git log --end-of-options --source >actual &&

0 commit comments

Comments
 (0)