git/list[1] front-page[2] threads[3] people[4] search[5] about
 

[PATCH] pack-objects --repack-unpacked

From
Junio C Hamano <gitster@pobox.com>
Date
Sep 8, 2007, 10:01 UTC
Message-ID
<7vodgdzdaj.fsf_-_@gitster.siamese.dyndns.org>
In-Reply-To
<7vwsv36q6p.fsf@gitster.siamese.dyndns.org>

The usual command line that uses "--unpacked=<existing>" option looks like this:

	git pack-objects --non-empty --all --reflog \
        	--unpacked --unpacked=<existing> \
                packname-prefix

This packs loose objects and objects in the named existing packs that are reachable from any and all refs and reflog entries. It is typically used by "git repack -a -d", which then removes the named existing packs from the repository, and has an effect of getting rid of unreachable objects these packs hold.

This adds "--repack-unpacked" option to pack-objects to help combining small packs into one, without losing unreferenced objects that are in the packs. When this option is given in addition to the above command line, we also make sure all the objects in the named existing packs are included in the result.

This allows us to safely remove the packs that were named on the command line after installing the resulting pack in the repository.

Signed-off-by: Junio C Hamano <gitster@pobox.com>
---
 I am too tired to keep staring at this code now.  Fixes,
 improvements, replacements and enhancements, in the code,
 documentation and tests, are very much welcomed.
 builtin-pack-objects.c |   95 +++++++++++++++++++++++++++++++++++++++++++++++-
 1 files changed, 93 insertions(+), 2 deletions(-)
diff --git a/builtin-pack-objects.c b/builtin-pack-objects.c
index 12509fa..9bc2faa 100644
--- a/builtin-pack-objects.c
+++ b/builtin-pack-objects.c
@@ -21,7 +21,7 @@ git-pack-objects [{ -q | --progress | --all-progress }] \n\
 	[--window=N] [--window-memory=N] [--depth=N] \n\
 	[--no-reuse-delta] [--no-reuse-object] [--delta-base-offset] \n\
 	[--non-empty] [--revs [--unpacked | --all]*] [--reflog] \n\
-	[--stdout | base-name] [<ref-list | <object-list]";
+	[--stdout | base-name] [--repack-unpacked] [<ref-list | <object-list]";
 
 struct object_entry {
 	struct pack_idx_entry idx;
@@ -57,7 +57,7 @@ static struct object_entry **written_list;
 static uint32_t nr_objects, nr_alloc, nr_result, nr_written;
 
 static int non_empty;
-static int no_reuse_delta, no_reuse_object;
+static int no_reuse_delta, no_reuse_object, repack_unpacked;
 static int local;
 static int incremental;
 static int allow_ofs_delta;
@@ -1625,15 +1625,21 @@ static void read_object_list_from_stdin(void)
 	}
 }
 
+#define OBJECT_ADDED (1u<<20)
+
 static void show_commit(struct commit *commit)
 {
 	add_object_entry(commit->object.sha1, OBJ_COMMIT, NULL, 0);
+	commit->object.flags |= OBJECT_ADDED;
 }
 
 static void show_object(struct object_array_entry *p)
 {
+	struct object *o = lookup_unknown_object(p->item->sha1);
+
 	add_preferred_base_object(p->name);
 	add_object_entry(p->item->sha1, p->item->type, p->name, 0);
+	o->flags |= OBJECT_ADDED;
 }
 
 static void show_edge(struct commit *commit)
@@ -1641,6 +1647,84 @@ static void show_edge(struct commit *commit)
 	add_preferred_base(commit->object.sha1);
 }
 
+struct in_pack_object {
+	off_t offset;
+	const unsigned char *sha1;
+};
+
+struct in_pack {
+	int alloc;
+	int nr;
+	struct in_pack_object *array;
+};
+
+static void mark_in_pack_object(const unsigned char *sha1, struct packed_git *p, struct in_pack *in_pack)
+{
+	in_pack->array[in_pack->nr].offset = find_pack_entry_one(sha1, p);
+	in_pack->array[in_pack->nr].sha1 = sha1;
+	in_pack->nr++;
+}
+
+/*
+ * Compare the objects in the offset order, in order to emulate the
+ * "git-rev-list --objects" output that produced the pack originally.
+ */
+static int ofscmp(const void *a_, const void *b_)
+{
+	struct in_pack_object *a = (struct in_pack_object *)a_;
+	struct in_pack_object *b = (struct in_pack_object *)b_;
+
+	if (a->offset < b->offset)
+		return -1;
+	else if (a->offset > b->offset)
+		return 1;
+	else
+		return hashcmp(a->sha1, b->sha1);
+}
+
+static void add_objects_in_unpacked_packs(struct rev_info *revs)
+{
+	struct packed_git *p;
+
+	for (p = packed_git; p; p = p->next) {
+		struct in_pack in_pack;
+		const unsigned char *sha1;
+		struct object *o;
+		uint32_t i;
+
+		for (i = 0; i < revs->num_ignore_packed; i++) {
+			if (matches_pack_name(p, revs->ignore_packed[i]))
+				break;
+		}
+		if (revs->num_ignore_packed <= i)
+			continue;
+		if (open_pack_index(p))
+			die("cannot open pack index");
+
+		in_pack.alloc = p->num_objects;
+		in_pack.nr = 0;
+		in_pack.array = xmalloc(sizeof(in_pack.array[0]) *
+					p->num_objects);
+		for (i = 0; i < p->num_objects; i++) {
+			sha1 = nth_packed_object_sha1(p, i);
+			o = lookup_unknown_object(sha1);
+			if (!(o->flags & OBJECT_ADDED))
+				mark_in_pack_object(sha1, p, &in_pack);
+			o->flags |= OBJECT_ADDED;
+		}
+		if (!in_pack.nr)
+			continue;
+		qsort(in_pack.array, in_pack.nr, sizeof(in_pack.array[0]),
+		      ofscmp);
+		for (i = 0; i < in_pack.nr; i++) {
+			sha1 = in_pack.array[i].sha1;
+			o = lookup_unknown_object(sha1);
+			add_object_entry(sha1, o->type, "", 0);
+		}
+		free(in_pack.array);
+	}
+}
+
 static void get_object_list(int ac, const char **av)
 {
 	struct rev_info revs;
@@ -1672,6 +1756,9 @@ static void get_object_list(int ac, const char **av)
 	prepare_revision_walk(&revs);
 	mark_edges_uninteresting(revs.commits, &revs, show_edge);
 	traverse_commit_list(&revs, show_commit, show_object);
+
+	if (repack_unpacked)
+		add_objects_in_unpacked_packs(&revs);
 }
 
 static int adjust_perm(const char *path, mode_t mode)
@@ -1789,6 +1876,10 @@ int cmd_pack_objects(int argc, const char **argv, const char *prefix)
 			use_internal_rev_list = 1;
 			continue;
 		}
+		if (!strcmp("--repack-unpacked", arg)) {
+			repack_unpacked = 1;
+			continue;
+		}
 		if (!strcmp("--unpacked", arg) ||
 		    !prefixcmp(arg, "--unpacked=") ||
 		    !strcmp("--reflog", arg) ||
Previous: Junio C HamanoNext: Johannes Sixt
Message 61 of 97 in “People unaware of the importance of "git gc"?”
  1. Linus TorvaldsSep 5, 2007
  2. Martin LanghoffSep 5, 2007
  3. Karl HasselströmSep 5, 2007
  4. Junio C HamanoSep 5, 2007
  5. Tomash BrechkoSep 5, 2007
  6. Johan HerlandSep 5, 2007
  7. Matthieu MoySep 5, 2007
  8. Johan HerlandSep 5, 2007
  9. David KastrupSep 5, 2007
  10. Pierre HabouzitSep 5, 2007
  11. David KastrupSep 5, 2007
  12. Matthieu MoySep 5, 2007
  13. Wincent ColaiutaSep 5, 2007
  14. Pierre HabouzitSep 5, 2007
  15. Junio C HamanoSep 5, 2007
  16. Steven GrimmSep 5, 2007
  17. Junio C HamanoSep 5, 2007
  18. Martin LanghoffSep 5, 2007
  19. Matthieu MoySep 5, 2007
  20. Johan De MessemaekerSep 5, 2007
  21. Matthieu MoySep 5, 2007
  22. Jeff KingSep 5, 2007
  23. David KastrupSep 5, 2007
  24. Pierre HabouzitSep 5, 2007
  25. NixSep 5, 2007
  26. Steven GrimmSep 5, 2007
  27. NixSep 5, 2007
  28. Nicolas PitreSep 5, 2007
  29. Junio C HamanoSep 5, 2007
  30. Nicolas PitreSep 5, 2007
  31. NixSep 5, 2007
  32. Junio C HamanoSep 5, 2007
  33. Nicolas PitreSep 5, 2007
  34. Junio C HamanoSep 5, 2007
  35. Carlos RicaSep 6, 2007
  36. David KastrupSep 6, 2007
  37. Junio C HamanoSep 5, 2007
  38. Invoke "git gc --auto" from commit, merge, am and rebase.Junio C Hamano, Sep 5, 2007
  39. Shawn O. PearceSep 6, 2007
  40. Invoke "git gc --auto" from "git add" and "git fetch"Junio C Hamano, Sep 5, 2007
  41. Johannes SchindelinSep 6, 2007
  42. Alex RiesenSep 5, 2007
  43. Russ DillSep 6, 2007
  44. Shawn O. PearceSep 6, 2007
  45. Andreas EricssonSep 6, 2007
  46. Shawn O. PearceSep 6, 2007
  47. Steven GrimmSep 6, 2007
  48. Shawn O. PearceSep 6, 2007
  49. Johannes SchindelinSep 6, 2007
  50. Junio C HamanoSep 6, 2007
  51. Linus TorvaldsSep 6, 2007
  52. Steven GrimmSep 6, 2007
  53. Subject: [PATCH] git-merge-packJunio C Hamano, Sep 6, 2007
  54. Linus TorvaldsSep 6, 2007
  55. Nicolas PitreSep 7, 2007
  56. Junio C HamanoSep 7, 2007
  57. Nicolas PitreSep 7, 2007
  58. Shawn O. PearceSep 7, 2007
  59. Junio C HamanoSep 7, 2007
  60. make sha1_file.c::matches_pack_name() available to othersJunio C Hamano, Sep 8, 2007
  61. pack-objects --repack-unpackedJunio C Hamano, Sep 8, 2007
  62. Johannes SixtSep 7, 2007
  63. Junio C HamanoSep 7, 2007
  64. Andy ParkinsSep 7, 2007
  65. Shawn O. PearceSep 7, 2007
  66. Johannes SchindelinSep 7, 2007
  67. What's so special about objects/17/ ?Ævar Arnfjörð Bjarmason, Oct 7, 2018
  68. Johannes SixtOct 7, 2018
  69. Ævar Arnfjörð BjarmasonOct 7, 2018
  70. Johannes SixtOct 7, 2018
  71. Junio C HamanoOct 8, 2018
  72. Junio C HamanoOct 7, 2018
  73. Junio C HamanoOct 7, 2018
  74. Stefan BellerOct 8, 2018
  75. Junio C HamanoOct 9, 2018
  76. Stefan BellerOct 9, 2018
  77. Junio C HamanoOct 10, 2018
  78. Stefan BellerOct 10, 2018
  79. Ævar Arnfjörð BjarmasonOct 8, 2018
  80. Junio C HamanoOct 9, 2018
  81. Stefan BellerOct 9, 2018
  82. David KastrupSep 5, 2007
  83. Govind SalinasSep 5, 2007
  84. Carl WorthSep 5, 2007
  85. Jing XueSep 5, 2007
  86. Steven GrimmSep 5, 2007
  87. NixSep 5, 2007
  88. J. Bruce FieldsSep 5, 2007
  89. Brandon CaseySep 5, 2007
  90. David KastrupSep 5, 2007
  91. J. Bruce FieldsSep 5, 2007
  92. David KastrupSep 5, 2007
  93. Mike HommeySep 5, 2007
  94. Alex RiesenSep 5, 2007
  95. Steven GrimmSep 5, 2007
  96. David KastrupSep 5, 2007
  97. Fwd: [PATCH] Invoke "git gc --auto" from "git add" and "git fetch"Govind Salinas, Sep 5, 2007

Read the whole thread, see it on lore, or plain text.

$ cat FOOTERMessages come from the public archive at lore.kernel.org/git, fetched every hour. The front page is chosen and written each morning by an AI editor and can be wrong; the threads themselves are the record. About and API. For agents: an MCP server at https://gitlist.dev/mcp, and any thread, story or person page as Markdown by adding .md to its URL (or sending Accept: text/markdown). Details in /llms.txt.