@@ -2,3 +2,13 @@ maintenance.<task>.enabled::
This boolean config option controls whether the maintenance task
with name `<task>` is run when no `--task` option is specified.
By default, only `maintenance.gc.enabled` is true.
+
+maintenance.commit-graph.auto::
+ This integer config option controls how often the `commit-graph` task
+ should be run as part of `git maintenance run --auto`. If zero, then
+ the `commit-graph` task will not run with the `--auto` option. A
+ negative value will force the task to run every time. Otherwise, a
+ positive value implies the command should run when the number of
+ reachable commits that are not in the commit-graph file is at least
+ the value of `maintenance.commit-graph.auto`. The default value is
+ 100.
@@ -28,6 +28,7 @@
#include "blob.h"
#include "tree.h"
#include "promisor-remote.h"
+#include "refs.h"
#define FAILED_RUN "failed to run %s"
@@ -710,6 +711,80 @@ struct maintenance_opts {
int quiet;
};
+/* Remember to update object flag allocation in object.h */
+#define PARENT1 (1u<<16)
+
+static int num_commits_not_in_graph = 0;
+static int limit_commits_not_in_graph = 100;
+
+static int dfs_on_ref(const char *refname,
+ const struct object_id *oid, int flags,
+ void *cb_data)
+{
+ int result = 0;
+ struct object_id peeled;
+ struct commit_list *stack = NULL;
+ struct commit *commit;
+
+ if (!peel_ref(refname, &peeled))
+ oid = &peeled;
+ if (oid_object_info(the_repository, oid, NULL) != OBJ_COMMIT)
+ return 0;
+
+ commit = lookup_commit(the_repository, oid);
+ if (!commit)
+ return 0;
+ if (parse_commit(commit))
+ return 0;
+
+ commit_list_append(commit, &stack);
+
+ while (!result && stack) {
+ struct commit_list *parent;
+
+ commit = pop_commit(&stack);
+
+ for (parent = commit->parents; parent; parent = parent->next) {
+ if (parse_commit(parent->item) ||
+ commit_graph_position(parent->item) != COMMIT_NOT_FROM_GRAPH ||
+ parent->item->object.flags & PARENT1)
+ continue;
+
+ parent->item->object.flags |= PARENT1;
+ num_commits_not_in_graph++;
+
+ if (num_commits_not_in_graph >= limit_commits_not_in_graph) {
+ result = 1;
+ break;
+ }
+
+ commit_list_append(parent->item, &stack);
+ }
+ }
+
+ free_commit_list(stack);
+ return result;
+}
+
+static int should_write_commit_graph(void)
+{
+ int result;
+
+ git_config_get_int("maintenance.commit-graph.auto",
+ &limit_commits_not_in_graph);
+
+ if (!limit_commits_not_in_graph)
+ return 0;
+ if (limit_commits_not_in_graph < 0)
+ return 1;
+
+ result = for_each_ref(dfs_on_ref, NULL);
+
+ clear_commit_marks_all(PARENT1);
+
+ return result;
+}
+
static int run_write_commit_graph(struct maintenance_opts *opts)
{
struct child_process child = CHILD_PROCESS_INIT;
@@ -822,6 +897,7 @@ static struct maintenance_task tasks[] = {
[TASK_COMMIT_GRAPH] = {
"commit-graph",
maintenance_task_commit_graph,
+ should_write_commit_graph,
},
};
@@ -74,6 +74,7 @@ struct object_array {
* list-objects-filter.c: 21
* builtin/fsck.c: 0--3
* builtin/index-pack.c: 2021
+ * builtin/maintenance.c: 16
* builtin/pack-objects.c: 20
* builtin/reflog.c: 10--12
* builtin/show-branch.c: 0-------------------------------------------26