Skip to content

Commit 6d8f8eb

Browse files
committed
Merge branch 'ds/commit-graph-with-grafts'
The recently introduced commit-graph auxiliary data is incompatible with mechanisms such as replace & grafts that "breaks" immutable nature of the object reference relationship. Disable optimizations based on its use (and updating existing commit-graph) when these incompatible features are in use in the repository. * ds/commit-graph-with-grafts: commit-graph: close_commit_graph before shallow walk commit-graph: not compatible with uninitialized repo commit-graph: not compatible with grafts commit-graph: not compatible with replace objects test-repository: properly init repo commit-graph: update design document refs.c: upgrade for_each_replace_ref to be a each_repo_ref_fn callback refs.c: migrate internal ref iteration to pass thru repository argument
2 parents 36d767d + 829a321 commit 6d8f8eb

16 files changed

+194
-30
lines changed

Documentation/technical/commit-graph.txt

Lines changed: 15 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -112,12 +112,24 @@ Design Details
112112
- The file format includes parameters for the object ID hash function,
113113
so a future change of hash algorithm does not require a change in format.
114114

115+
- Commit grafts and replace objects can change the shape of the commit
116+
history. The latter can also be enabled/disabled on the fly using
117+
`--no-replace-objects`. This leads to difficultly storing both possible
118+
interpretations of a commit id, especially when computing generation
119+
numbers. The commit-graph will not be read or written when
120+
replace-objects or grafts are present.
121+
122+
- Shallow clones create grafts of commits by dropping their parents. This
123+
leads the commit-graph to think those commits have generation number 1.
124+
If and when those commits are made unshallow, those generation numbers
125+
become invalid. Since shallow clones are intended to restrict the commit
126+
history to a very small set of commits, the commit-graph feature is less
127+
helpful for these clones, anyway. The commit-graph will not be read or
128+
written when shallow commits are present.
129+
115130
Future Work
116131
-----------
117132

118-
- The commit graph feature currently does not honor commit grafts. This can
119-
be remedied by duplicating or refactoring the current graft logic.
120-
121133
- After computing and storing generation numbers, we must make graph
122134
walks aware of generation numbers to gain the performance benefits they
123135
enable. This will mostly be accomplished by swapping a commit-date-ordered

builtin/commit-graph.c

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -120,6 +120,8 @@ static int graph_read(int argc, const char **argv)
120120
return 0;
121121
}
122122

123+
extern int read_replace_refs;
124+
123125
static int graph_write(int argc, const char **argv)
124126
{
125127
struct string_list *pack_indexes = NULL;
@@ -150,6 +152,8 @@ static int graph_write(int argc, const char **argv)
150152
if (!opts.obj_dir)
151153
opts.obj_dir = get_object_directory();
152154

155+
read_replace_refs = 0;
156+
153157
if (opts.reachable) {
154158
write_commit_graph_reachable(opts.obj_dir, opts.append, 1);
155159
return 0;

builtin/replace.c

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -39,7 +39,8 @@ struct show_data {
3939
enum replace_format format;
4040
};
4141

42-
static int show_reference(const char *refname, const struct object_id *oid,
42+
static int show_reference(struct repository *r, const char *refname,
43+
const struct object_id *oid,
4344
int flag, void *cb_data)
4445
{
4546
struct show_data *data = cb_data;
@@ -56,9 +57,8 @@ static int show_reference(const char *refname, const struct object_id *oid,
5657
if (get_oid(refname, &object))
5758
return error(_("failed to resolve '%s' as a valid ref"), refname);
5859

59-
obj_type = oid_object_info(the_repository, &object,
60-
NULL);
61-
repl_type = oid_object_info(the_repository, oid, NULL);
60+
obj_type = oid_object_info(r, &object, NULL);
61+
repl_type = oid_object_info(r, oid, NULL);
6262

6363
printf("%s (%s) -> %s (%s)\n", refname, type_name(obj_type),
6464
oid_to_hex(oid), type_name(repl_type));

commit-graph.c

Lines changed: 34 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,8 @@
1313
#include "commit-graph.h"
1414
#include "object-store.h"
1515
#include "alloc.h"
16+
#include "hashmap.h"
17+
#include "replace-object.h"
1618
#include "progress.h"
1719

1820
#define GRAPH_SIGNATURE 0x43475048 /* "CGPH" */
@@ -57,6 +59,28 @@ static struct commit_graph *alloc_commit_graph(void)
5759
return g;
5860
}
5961

62+
extern int read_replace_refs;
63+
64+
static int commit_graph_compatible(struct repository *r)
65+
{
66+
if (!r->gitdir)
67+
return 0;
68+
69+
if (read_replace_refs) {
70+
prepare_replace_object(r);
71+
if (hashmap_get_size(&r->objects->replace_map->map))
72+
return 0;
73+
}
74+
75+
prepare_commit_graft(r);
76+
if (r->parsed_objects && r->parsed_objects->grafts_nr)
77+
return 0;
78+
if (is_repository_shallow(r))
79+
return 0;
80+
81+
return 1;
82+
}
83+
6084
struct commit_graph *load_commit_graph_one(const char *graph_file)
6185
{
6286
void *graph_map;
@@ -225,6 +249,9 @@ static int prepare_commit_graph(struct repository *r)
225249
*/
226250
return 0;
227251

252+
if (!commit_graph_compatible(r))
253+
return 0;
254+
228255
obj_dir = r->objects->objectdir;
229256
prepare_commit_graph_one(r, obj_dir);
230257
prepare_alt_odb(r);
@@ -253,10 +280,10 @@ int generation_numbers_enabled(struct repository *r)
253280
return !!first_generation;
254281
}
255282

256-
static void close_commit_graph(void)
283+
void close_commit_graph(struct repository *r)
257284
{
258-
free_commit_graph(the_repository->objects->commit_graph);
259-
the_repository->objects->commit_graph = NULL;
285+
free_commit_graph(r->objects->commit_graph);
286+
r->objects->commit_graph = NULL;
260287
}
261288

262289
static int bsearch_graph(struct commit_graph *g, struct object_id *oid, uint32_t *pos)
@@ -737,6 +764,9 @@ void write_commit_graph(const char *obj_dir,
737764
struct commit_list *parent;
738765
struct progress *progress = NULL;
739766

767+
if (!commit_graph_compatible(the_repository))
768+
return;
769+
740770
oids.nr = 0;
741771
oids.alloc = approximate_object_count() / 4;
742772
oids.progress = NULL;
@@ -908,7 +938,7 @@ void write_commit_graph(const char *obj_dir,
908938
write_graph_chunk_data(f, GRAPH_OID_LEN, commits.list, commits.nr);
909939
write_graph_chunk_large_edges(f, commits.list, commits.nr);
910940

911-
close_commit_graph();
941+
close_commit_graph(the_repository);
912942
finalize_hashfile(f, NULL, CSUM_HASH_IN_STREAM | CSUM_FSYNC);
913943
commit_lock_file(&lk);
914944

commit-graph.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -69,6 +69,7 @@ void write_commit_graph(const char *obj_dir,
6969

7070
int verify_commit_graph(struct repository *r, struct commit_graph *g);
7171

72+
void close_commit_graph(struct repository *);
7273
void free_commit_graph(struct commit_graph *);
7374

7475
#endif

commit.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -209,7 +209,7 @@ static int read_graft_file(struct repository *r, const char *graft_file)
209209
return 0;
210210
}
211211

212-
static void prepare_commit_graft(struct repository *r)
212+
void prepare_commit_graft(struct repository *r)
213213
{
214214
char *graft_file;
215215

commit.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -202,6 +202,7 @@ typedef int (*each_commit_graft_fn)(const struct commit_graft *, void *);
202202

203203
struct commit_graft *read_graft_line(struct strbuf *line);
204204
int register_commit_graft(struct repository *r, struct commit_graft *, int);
205+
void prepare_commit_graft(struct repository *r);
205206
struct commit_graft *lookup_commit_graft(struct repository *r, const struct object_id *oid);
206207

207208
/* largest positive number a signed 32-bit integer can contain */

refs.c

Lines changed: 41 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1394,17 +1394,50 @@ struct ref_iterator *refs_ref_iterator_begin(
13941394
* non-zero value, stop the iteration and return that value;
13951395
* otherwise, return 0.
13961396
*/
1397+
static int do_for_each_repo_ref(struct repository *r, const char *prefix,
1398+
each_repo_ref_fn fn, int trim, int flags,
1399+
void *cb_data)
1400+
{
1401+
struct ref_iterator *iter;
1402+
struct ref_store *refs = get_main_ref_store(r);
1403+
1404+
if (!refs)
1405+
return 0;
1406+
1407+
iter = refs_ref_iterator_begin(refs, prefix, trim, flags);
1408+
1409+
return do_for_each_repo_ref_iterator(r, iter, fn, cb_data);
1410+
}
1411+
1412+
struct do_for_each_ref_help {
1413+
each_ref_fn *fn;
1414+
void *cb_data;
1415+
};
1416+
1417+
static int do_for_each_ref_helper(struct repository *r,
1418+
const char *refname,
1419+
const struct object_id *oid,
1420+
int flags,
1421+
void *cb_data)
1422+
{
1423+
struct do_for_each_ref_help *hp = cb_data;
1424+
1425+
return hp->fn(refname, oid, flags, hp->cb_data);
1426+
}
1427+
13971428
static int do_for_each_ref(struct ref_store *refs, const char *prefix,
13981429
each_ref_fn fn, int trim, int flags, void *cb_data)
13991430
{
14001431
struct ref_iterator *iter;
1432+
struct do_for_each_ref_help hp = { fn, cb_data };
14011433

14021434
if (!refs)
14031435
return 0;
14041436

14051437
iter = refs_ref_iterator_begin(refs, prefix, trim, flags);
14061438

1407-
return do_for_each_ref_iterator(iter, fn, cb_data);
1439+
return do_for_each_repo_ref_iterator(the_repository, iter,
1440+
do_for_each_ref_helper, &hp);
14081441
}
14091442

14101443
int refs_for_each_ref(struct ref_store *refs, each_ref_fn fn, void *cb_data)
@@ -1449,12 +1482,11 @@ int refs_for_each_fullref_in(struct ref_store *refs, const char *prefix,
14491482
return do_for_each_ref(refs, prefix, fn, 0, flag, cb_data);
14501483
}
14511484

1452-
int for_each_replace_ref(struct repository *r, each_ref_fn fn, void *cb_data)
1485+
int for_each_replace_ref(struct repository *r, each_repo_ref_fn fn, void *cb_data)
14531486
{
1454-
return do_for_each_ref(get_main_ref_store(r),
1455-
git_replace_ref_base, fn,
1456-
strlen(git_replace_ref_base),
1457-
DO_FOR_EACH_INCLUDE_BROKEN, cb_data);
1487+
return do_for_each_repo_ref(r, git_replace_ref_base, fn,
1488+
strlen(git_replace_ref_base),
1489+
DO_FOR_EACH_INCLUDE_BROKEN, cb_data);
14581490
}
14591491

14601492
int for_each_namespaced_ref(each_ref_fn fn, void *cb_data)
@@ -2033,10 +2065,12 @@ int refs_verify_refname_available(struct ref_store *refs,
20332065
int refs_for_each_reflog(struct ref_store *refs, each_ref_fn fn, void *cb_data)
20342066
{
20352067
struct ref_iterator *iter;
2068+
struct do_for_each_ref_help hp = { fn, cb_data };
20362069

20372070
iter = refs->be->reflog_iterator_begin(refs);
20382071

2039-
return do_for_each_ref_iterator(iter, fn, cb_data);
2072+
return do_for_each_repo_ref_iterator(the_repository, iter,
2073+
do_for_each_ref_helper, &hp);
20402074
}
20412075

20422076
int for_each_reflog(each_ref_fn fn, void *cb_data)

refs.h

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -276,6 +276,16 @@ struct ref_transaction;
276276
typedef int each_ref_fn(const char *refname,
277277
const struct object_id *oid, int flags, void *cb_data);
278278

279+
/*
280+
* The same as each_ref_fn, but also with a repository argument that
281+
* contains the repository associated with the callback.
282+
*/
283+
typedef int each_repo_ref_fn(struct repository *r,
284+
const char *refname,
285+
const struct object_id *oid,
286+
int flags,
287+
void *cb_data);
288+
279289
/*
280290
* The following functions invoke the specified callback function for
281291
* each reference indicated. If the function ever returns a nonzero
@@ -309,7 +319,7 @@ int for_each_fullref_in(const char *prefix, each_ref_fn fn, void *cb_data,
309319
int for_each_tag_ref(each_ref_fn fn, void *cb_data);
310320
int for_each_branch_ref(each_ref_fn fn, void *cb_data);
311321
int for_each_remote_ref(each_ref_fn fn, void *cb_data);
312-
int for_each_replace_ref(struct repository *r, each_ref_fn fn, void *cb_data);
322+
int for_each_replace_ref(struct repository *r, each_repo_ref_fn fn, void *cb_data);
313323
int for_each_glob_ref(each_ref_fn fn, const char *pattern, void *cb_data);
314324
int for_each_glob_ref_in(each_ref_fn fn, const char *pattern,
315325
const char *prefix, void *cb_data);

refs/iterator.c

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -407,15 +407,15 @@ struct ref_iterator *prefix_ref_iterator_begin(struct ref_iterator *iter0,
407407

408408
struct ref_iterator *current_ref_iter = NULL;
409409

410-
int do_for_each_ref_iterator(struct ref_iterator *iter,
411-
each_ref_fn fn, void *cb_data)
410+
int do_for_each_repo_ref_iterator(struct repository *r, struct ref_iterator *iter,
411+
each_repo_ref_fn fn, void *cb_data)
412412
{
413413
int retval = 0, ok;
414414
struct ref_iterator *old_ref_iter = current_ref_iter;
415415

416416
current_ref_iter = iter;
417417
while ((ok = ref_iterator_advance(iter)) == ITER_OK) {
418-
retval = fn(iter->refname, iter->oid, iter->flags, cb_data);
418+
retval = fn(r, iter->refname, iter->oid, iter->flags, cb_data);
419419
if (retval) {
420420
/*
421421
* If ref_iterator_abort() returns ITER_ERROR,

0 commit comments

Comments
 (0)