log: clean unneeded objects during `log --remerge-diff`

The --remerge-diff option will need to create new blobs and trees representing the "automatic merge" state. If one is traversing a long project history, one can easily get hundreds of thousands of loose objects generated during `log --remerge-diff`. However, none of those loose objects are needed after we have completed our diff operation; they can be summarily deleted. Add a new helper function to tmp_objdir to discard all the contained objects, and call it after each merge is handled. Signed-off-by: Elijah Newren <newren@gmail.com> Signed-off-by: Junio C Hamano <gitster@pobox.com>

Elijah Newren committed Feb 2, 2022 at 02:37 UTC 7b90ab467a658b2fb1b7c15c7d634e06f35f4ef2
5 files changed +28 -7
builtin/log.c
+7 -6
@@ -422,13 +422,12 @@ static int cmd_log_walk(struct rev_info *rev)
422 struct commit *commit;
423 int saved_nrl = 0;
424 int saved_dcctc = 0;
425 - struct tmp_objdir *remerge_objdir = NULL;
425
426 if (rev->remerge_diff) {
428 - remerge_objdir = tmp_objdir_create("remerge-diff");
429 - if (!remerge_objdir)
427 + rev->remerge_objdir = tmp_objdir_create("remerge-diff");
428 + if (!rev->remerge_objdir)
429 die(_("unable to create temporary object directory"));
431 - tmp_objdir_replace_primary_odb(remerge_objdir, 1);
430 + tmp_objdir_replace_primary_odb(rev->remerge_objdir, 1);
431 }
432
433 if (rev->early_output)
@@ -473,8 +472,10 @@ static int cmd_log_walk(struct rev_info *rev)
472 rev->diffopt.no_free = 0;
473 diff_free(&rev->diffopt);
474
476 - if (rev->remerge_diff)
477 - tmp_objdir_destroy(remerge_objdir);
475 + if (rev->remerge_diff) {
476 + tmp_objdir_destroy(rev->remerge_objdir);
477 + rev->remerge_objdir = NULL;
478 + }
479
480 if (rev->diffopt.output_format & DIFF_FORMAT_CHECKDIFF &&
481 rev->diffopt.flags.check_failed) {
log-tree.c
+7 -1
@@ -4,6 +4,7 @@
4 #include "diff.h"
5 #include "object-store.h"
6 #include "repository.h"
7 +#include "tmp-objdir.h"
8 #include "commit.h"
9 #include "tag.h"
10 #include "graph.h"
@@ -946,7 +947,12 @@ static int do_remerge_diff(struct rev_info *opt,
947 strbuf_release(&parent1_desc);
948 strbuf_release(&parent2_desc);
949 merge_finalize(&o, &res);
949 - /* TODO: clean up the temporary object directory */
950 +
951 + /* Clean up the contents of the temporary object directory */
952 + if (opt->remerge_objdir)
953 + tmp_objdir_discard_objects(opt->remerge_objdir);
954 + else
955 + BUG("did a remerge diff without remerge_objdir?!?");
956
957 return !opt->loginfo;
958 }
revision.h
+3
@@ -318,6 +318,9 @@ struct rev_info {
318
319 /* misc. flags related to '--no-kept-objects' */
320 unsigned keep_pack_cache_flags;
321 +
322 + /* Location where temporary objects for remerge-diff are written. */
323 + struct tmp_objdir *remerge_objdir;
324 };
325
326 int ref_excluded(struct string_list *, const char *path);
tmp-objdir.c
+5
@@ -79,6 +79,11 @@ static void remove_tmp_objdir_on_signal(int signo)
79 raise(signo);
80 }
81
82 +void tmp_objdir_discard_objects(struct tmp_objdir *t)
83 +{
84 + remove_dir_recursively(&t->path, REMOVE_DIR_KEEP_TOPLEVEL);
85 +}
86 +
87 /*
88 * These env_* functions are for setting up the child environment; the
89 * "replace" variant overrides the value of any existing variable with that
tmp-objdir.h
+6
@@ -46,6 +46,12 @@ int tmp_objdir_migrate(struct tmp_objdir *);
46 */
47 int tmp_objdir_destroy(struct tmp_objdir *);
48
49 +/*
50 + * Remove all objects from the temporary object directory, while leaving it
51 + * around so more objects can be added.
52 + */
53 +void tmp_objdir_discard_objects(struct tmp_objdir *);
54 +
55 /*
56 * Add the temporary object directory as an alternate object store in the
57 * current process.