Skip to content

Commit a5619d4

Browse files
committed
Merge branch 'ps/connectivity-optim'
The revision traversal API has been optimized by taking advantage of the commit-graph, when available, to determine if a commit is reachable from any of the existing refs. * ps/connectivity-optim: revision: avoid hitting packfiles when commits are in commit-graph commit-graph: split out function to search commit position revision: stop retrieving reference twice connected: do not sort input revisions revision: separate walk and unsorted flags
2 parents 6c40894 + f559d6d commit a5619d4

File tree

9 files changed

+127
-46
lines changed

9 files changed

+127
-46
lines changed

Documentation/rev-list-options.txt

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -968,14 +968,20 @@ list of the missing objects. Object IDs are prefixed with a ``?'' character.
968968
objects.
969969
endif::git-rev-list[]
970970

971+
--unsorted-input::
972+
Show commits in the order they were given on the command line instead
973+
of sorting them in reverse chronological order by commit time. Cannot
974+
be combined with `--no-walk` or `--no-walk=sorted`.
975+
971976
--no-walk[=(sorted|unsorted)]::
972977
Only show the given commits, but do not traverse their ancestors.
973978
This has no effect if a range is specified. If the argument
974979
`unsorted` is given, the commits are shown in the order they were
975980
given on the command line. Otherwise (if `sorted` or no argument
976981
was given), the commits are shown in reverse chronological order
977982
by commit time.
978-
Cannot be combined with `--graph`.
983+
Cannot be combined with `--graph`. Cannot be combined with
984+
`--unsorted-input` if `sorted` or no argument was given.
979985

980986
--do-walk::
981987
Overrides a previous `--no-walk`.

builtin/log.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -637,7 +637,7 @@ int cmd_show(int argc, const char **argv, const char *prefix)
637637
repo_init_revisions(the_repository, &rev, prefix);
638638
rev.diff = 1;
639639
rev.always_show_header = 1;
640-
rev.no_walk = REVISION_WALK_NO_WALK_SORTED;
640+
rev.no_walk = 1;
641641
rev.diffopt.stat_width = -1; /* Scale to real terminal size */
642642

643643
memset(&opt, 0, sizeof(opt));

builtin/revert.c

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -191,7 +191,8 @@ static int run_sequencer(int argc, const char **argv, struct replay_opts *opts)
191191
struct setup_revision_opt s_r_opt;
192192
opts->revs = xmalloc(sizeof(*opts->revs));
193193
repo_init_revisions(the_repository, opts->revs, NULL);
194-
opts->revs->no_walk = REVISION_WALK_NO_WALK_UNSORTED;
194+
opts->revs->no_walk = 1;
195+
opts->revs->unsorted_input = 1;
195196
if (argc < 2)
196197
usage_with_options(usage_str, options);
197198
if (!strcmp(argv[1], "-"))

commit-graph.c

Lines changed: 52 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -723,7 +723,7 @@ void close_commit_graph(struct raw_object_store *o)
723723
o->commit_graph = NULL;
724724
}
725725

726-
static int bsearch_graph(struct commit_graph *g, struct object_id *oid, uint32_t *pos)
726+
static int bsearch_graph(struct commit_graph *g, const struct object_id *oid, uint32_t *pos)
727727
{
728728
return bsearch_hash(oid->hash, g->chunk_oid_fanout,
729729
g->chunk_oid_lookup, g->hash_len, pos);
@@ -864,26 +864,55 @@ static int fill_commit_in_graph(struct repository *r,
864864
return 1;
865865
}
866866

867-
static int find_commit_in_graph(struct commit *item, struct commit_graph *g, uint32_t *pos)
867+
static int search_commit_pos_in_graph(const struct object_id *id, struct commit_graph *g, uint32_t *pos)
868+
{
869+
struct commit_graph *cur_g = g;
870+
uint32_t lex_index;
871+
872+
while (cur_g && !bsearch_graph(cur_g, id, &lex_index))
873+
cur_g = cur_g->base_graph;
874+
875+
if (cur_g) {
876+
*pos = lex_index + cur_g->num_commits_in_base;
877+
return 1;
878+
}
879+
880+
return 0;
881+
}
882+
883+
static int find_commit_pos_in_graph(struct commit *item, struct commit_graph *g, uint32_t *pos)
868884
{
869885
uint32_t graph_pos = commit_graph_position(item);
870886
if (graph_pos != COMMIT_NOT_FROM_GRAPH) {
871887
*pos = graph_pos;
872888
return 1;
873889
} else {
874-
struct commit_graph *cur_g = g;
875-
uint32_t lex_index;
890+
return search_commit_pos_in_graph(&item->object.oid, g, pos);
891+
}
892+
}
876893

877-
while (cur_g && !bsearch_graph(cur_g, &(item->object.oid), &lex_index))
878-
cur_g = cur_g->base_graph;
894+
struct commit *lookup_commit_in_graph(struct repository *repo, const struct object_id *id)
895+
{
896+
struct commit *commit;
897+
uint32_t pos;
879898

880-
if (cur_g) {
881-
*pos = lex_index + cur_g->num_commits_in_base;
882-
return 1;
883-
}
899+
if (!repo->objects->commit_graph)
900+
return NULL;
901+
if (!search_commit_pos_in_graph(id, repo->objects->commit_graph, &pos))
902+
return NULL;
903+
if (!repo_has_object_file(repo, id))
904+
return NULL;
884905

885-
return 0;
886-
}
906+
commit = lookup_commit(repo, id);
907+
if (!commit)
908+
return NULL;
909+
if (commit->object.parsed)
910+
return commit;
911+
912+
if (!fill_commit_in_graph(repo, commit, repo->objects->commit_graph, pos))
913+
return NULL;
914+
915+
return commit;
887916
}
888917

889918
static int parse_commit_in_graph_one(struct repository *r,
@@ -895,7 +924,7 @@ static int parse_commit_in_graph_one(struct repository *r,
895924
if (item->object.parsed)
896925
return 1;
897926

898-
if (find_commit_in_graph(item, g, &pos))
927+
if (find_commit_pos_in_graph(item, g, &pos))
899928
return fill_commit_in_graph(r, item, g, pos);
900929

901930
return 0;
@@ -921,7 +950,7 @@ void load_commit_graph_info(struct repository *r, struct commit *item)
921950
uint32_t pos;
922951
if (!prepare_commit_graph(r))
923952
return;
924-
if (find_commit_in_graph(item, r->objects->commit_graph, &pos))
953+
if (find_commit_pos_in_graph(item, r->objects->commit_graph, &pos))
925954
fill_commit_graph_info(item, r->objects->commit_graph, pos);
926955
}
927956

@@ -1091,9 +1120,9 @@ static int write_graph_chunk_data(struct hashfile *f,
10911120
edge_value += ctx->new_num_commits_in_base;
10921121
else if (ctx->new_base_graph) {
10931122
uint32_t pos;
1094-
if (find_commit_in_graph(parent->item,
1095-
ctx->new_base_graph,
1096-
&pos))
1123+
if (find_commit_pos_in_graph(parent->item,
1124+
ctx->new_base_graph,
1125+
&pos))
10971126
edge_value = pos;
10981127
}
10991128

@@ -1122,9 +1151,9 @@ static int write_graph_chunk_data(struct hashfile *f,
11221151
edge_value += ctx->new_num_commits_in_base;
11231152
else if (ctx->new_base_graph) {
11241153
uint32_t pos;
1125-
if (find_commit_in_graph(parent->item,
1126-
ctx->new_base_graph,
1127-
&pos))
1154+
if (find_commit_pos_in_graph(parent->item,
1155+
ctx->new_base_graph,
1156+
&pos))
11281157
edge_value = pos;
11291158
}
11301159

@@ -1235,9 +1264,9 @@ static int write_graph_chunk_extra_edges(struct hashfile *f,
12351264
edge_value += ctx->new_num_commits_in_base;
12361265
else if (ctx->new_base_graph) {
12371266
uint32_t pos;
1238-
if (find_commit_in_graph(parent->item,
1239-
ctx->new_base_graph,
1240-
&pos))
1267+
if (find_commit_pos_in_graph(parent->item,
1268+
ctx->new_base_graph,
1269+
&pos))
12411270
edge_value = pos;
12421271
}
12431272

commit-graph.h

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -40,6 +40,14 @@ int open_commit_graph(const char *graph_file, int *fd, struct stat *st);
4040
*/
4141
int parse_commit_in_graph(struct repository *r, struct commit *item);
4242

43+
/*
44+
* Look up the given commit ID in the commit-graph. This will only return a
45+
* commit if the ID exists both in the graph and in the object database such
46+
* that we don't return commits whose object has been pruned. Otherwise, this
47+
* function returns `NULL`.
48+
*/
49+
struct commit *lookup_commit_in_graph(struct repository *repo, const struct object_id *id);
50+
4351
/*
4452
* It is possible that we loaded commit contents from the commit buffer,
4553
* but we also want to ensure the commit-graph content is correctly

connected.c

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -106,6 +106,7 @@ int check_connected(oid_iterate_fn fn, void *cb_data,
106106
if (opt->progress)
107107
strvec_pushf(&rev_list.args, "--progress=%s",
108108
_("Checking connectivity"));
109+
strvec_push(&rev_list.args, "--unsorted-input");
109110

110111
rev_list.git_cmd = 1;
111112
rev_list.env = opt->env;

revision.c

Lines changed: 23 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -360,20 +360,18 @@ static struct object *get_reference(struct rev_info *revs, const char *name,
360360
unsigned int flags)
361361
{
362362
struct object *object;
363+
struct commit *commit;
363364

364365
/*
365-
* If the repository has commit graphs, repo_parse_commit() avoids
366-
* reading the object buffer, so use it whenever possible.
366+
* If the repository has commit graphs, we try to opportunistically
367+
* look up the object ID in those graphs. Like this, we can avoid
368+
* parsing commit data from disk.
367369
*/
368-
if (oid_object_info(revs->repo, oid, NULL) == OBJ_COMMIT) {
369-
struct commit *c = lookup_commit(revs->repo, oid);
370-
if (!repo_parse_commit(revs->repo, c))
371-
object = (struct object *) c;
372-
else
373-
object = NULL;
374-
} else {
370+
commit = lookup_commit_in_graph(revs->repo, oid);
371+
if (commit)
372+
object = &commit->object;
373+
else
375374
object = parse_object(revs->repo, oid);
376-
}
377375

378376
if (!object) {
379377
if (revs->ignore_missing)
@@ -1534,7 +1532,7 @@ static int handle_one_ref(const char *path, const struct object_id *oid,
15341532

15351533
object = get_reference(cb->all_revs, path, oid, cb->all_flags);
15361534
add_rev_cmdline(cb->all_revs, object, path, REV_CMD_REF, cb->all_flags);
1537-
add_pending_oid(cb->all_revs, path, oid, cb->all_flags);
1535+
add_pending_object(cb->all_revs, object, path);
15381536
return 0;
15391537
}
15401538

@@ -2256,6 +2254,10 @@ static int handle_revision_opt(struct rev_info *revs, int argc, const char **arg
22562254
} else if (!strcmp(arg, "--author-date-order")) {
22572255
revs->sort_order = REV_SORT_BY_AUTHOR_DATE;
22582256
revs->topo_order = 1;
2257+
} else if (!strcmp(arg, "--unsorted-input")) {
2258+
if (revs->no_walk)
2259+
die(_("--unsorted-input is incompatible with --no-walk"));
2260+
revs->unsorted_input = 1;
22592261
} else if (!strcmp(arg, "--early-output")) {
22602262
revs->early_output = 100;
22612263
revs->topo_order = 1;
@@ -2651,16 +2653,22 @@ static int handle_revision_pseudo_opt(const char *submodule,
26512653
} else if (!strcmp(arg, "--not")) {
26522654
*flags ^= UNINTERESTING | BOTTOM;
26532655
} else if (!strcmp(arg, "--no-walk")) {
2654-
revs->no_walk = REVISION_WALK_NO_WALK_SORTED;
2656+
if (!revs->no_walk && revs->unsorted_input)
2657+
die(_("--no-walk is incompatible with --unsorted-input"));
2658+
revs->no_walk = 1;
26552659
} else if (skip_prefix(arg, "--no-walk=", &optarg)) {
2660+
if (!revs->no_walk && revs->unsorted_input)
2661+
die(_("--no-walk is incompatible with --unsorted-input"));
2662+
26562663
/*
26572664
* Detached form ("--no-walk X" as opposed to "--no-walk=X")
26582665
* not allowed, since the argument is optional.
26592666
*/
2667+
revs->no_walk = 1;
26602668
if (!strcmp(optarg, "sorted"))
2661-
revs->no_walk = REVISION_WALK_NO_WALK_SORTED;
2669+
revs->unsorted_input = 0;
26622670
else if (!strcmp(optarg, "unsorted"))
2663-
revs->no_walk = REVISION_WALK_NO_WALK_UNSORTED;
2671+
revs->unsorted_input = 1;
26642672
else
26652673
return error("invalid argument to --no-walk");
26662674
} else if (!strcmp(arg, "--do-walk")) {
@@ -3584,7 +3592,7 @@ int prepare_revision_walk(struct rev_info *revs)
35843592

35853593
if (!revs->reflog_info)
35863594
prepare_to_use_bloom_filter(revs);
3587-
if (revs->no_walk != REVISION_WALK_NO_WALK_UNSORTED)
3595+
if (!revs->unsorted_input)
35883596
commit_list_sort_by_date(&revs->commits);
35893597
if (revs->no_walk)
35903598
return 0;

revision.h

Lines changed: 2 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -79,10 +79,6 @@ struct rev_cmdline_info {
7979
} *rev;
8080
};
8181

82-
#define REVISION_WALK_WALK 0
83-
#define REVISION_WALK_NO_WALK_SORTED 1
84-
#define REVISION_WALK_NO_WALK_UNSORTED 2
85-
8682
struct oidset;
8783
struct topo_walk_info;
8884

@@ -129,7 +125,8 @@ struct rev_info {
129125
/* Traversal flags */
130126
unsigned int dense:1,
131127
prune:1,
132-
no_walk:2,
128+
no_walk:1,
129+
unsorted_input:1,
133130
remove_empty_trees:1,
134131
simplify_history:1,
135132
show_pulls:1,

t/t6000-rev-list-misc.sh

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -169,4 +169,35 @@ test_expect_success 'rev-list --count --objects' '
169169
test_line_count = $count actual
170170
'
171171

172+
test_expect_success 'rev-list --unsorted-input results in different sorting' '
173+
git rev-list --unsorted-input HEAD HEAD~ >first &&
174+
git rev-list --unsorted-input HEAD~ HEAD >second &&
175+
! test_cmp first second &&
176+
sort first >first.sorted &&
177+
sort second >second.sorted &&
178+
test_cmp first.sorted second.sorted
179+
'
180+
181+
test_expect_success 'rev-list --unsorted-input incompatible with --no-walk' '
182+
cat >expect <<-EOF &&
183+
fatal: --no-walk is incompatible with --unsorted-input
184+
EOF
185+
test_must_fail git rev-list --unsorted-input --no-walk HEAD 2>error &&
186+
test_cmp expect error &&
187+
test_must_fail git rev-list --unsorted-input --no-walk=sorted HEAD 2>error &&
188+
test_cmp expect error &&
189+
test_must_fail git rev-list --unsorted-input --no-walk=unsorted HEAD 2>error &&
190+
test_cmp expect error &&
191+
192+
cat >expect <<-EOF &&
193+
fatal: --unsorted-input is incompatible with --no-walk
194+
EOF
195+
test_must_fail git rev-list --no-walk --unsorted-input HEAD 2>error &&
196+
test_cmp expect error &&
197+
test_must_fail git rev-list --no-walk=sorted --unsorted-input HEAD 2>error &&
198+
test_cmp expect error &&
199+
test_must_fail git rev-list --no-walk=unsorted --unsorted-input HEAD 2>error &&
200+
test_cmp expect error
201+
'
202+
172203
test_done

0 commit comments

Comments
 (0)