Updated git-gc --auto series.
cover Updated git-gc --auto series.
An updated series of "git-gc --auto", on top of 'next', consisting of 8 patches, will follow this message.
Differences from the previous round are:
- Earlier if you have too many unreachable loose objects, automated gc would have tried to "repack -d -l" which would not improve the situation at all every time it was run. It now at least warns upon such a situation;
- pack-objects learned --keep-unreachable option which helps "repack -a -d" not to lose packed but unreachable objects while repacking existing packs into a new pack;
- repack learned -A option which is similar to -a but gives --keep-unreachable to underlying pack-objects;
- "git-gc --auto" runs "git-repack -A -d -l" when there are too many packs in the repository;
- These changes are documented ;-)
PATCH 1/8 Export matches_pack_name() and fix its return value
The function sounds boolean; make it behave as one, not "0 for success, non-zero for failure".
--- cache.h | 1 + sha1_file.c | 14 +++++++------- 2 files changed, 8 insertions(+), 7 deletions(-)
cache.h +1 -0
@@ -529,6 +529,7 @@ extern void *unpack_entry(struct packed_git *, off_t, enum object_type *, unsignextern unsigned long unpack_object_header_gently (const unsigned char *buf,unsigned long len,enum object_type *type,unsigned long *sizep);extern unsigned long get_size_from_delta (struct packed_git *,struct pack_window **,off_t );extern const char *packed_object_info_detail (struct packed_git *,off_t ,unsigned long *,unsigned long *,unsigned int *,unsigned char *); +extern int matches_pack_name (struct packed_git *p,const char *name);/* Dumb servers support */ extern int update_server_info (int );
sha1_file.c +7 -7
@@ -1684,22 +1684,22 @@ off_t find_pack_entry_one(const unsigned char *sha1,return 0 ; } -static int matches_pack_name (struct packed_git *p,const char *ig) +int matches_pack_name (struct packed_git *p,const char *name) {const char *last_c, *c; -if (!strcmp (p->pack_name, ig)) -return 0 ; +if (!strcmp (p->pack_name, name)) +return 1 ;for (c = p->pack_name, last_c = c; *c;)if (*c =='/' ) last_c = ++c;else ++c; -if (!strcmp (last_c, ig)) -return 0 ; +if (!strcmp (last_c, name)) +return 1 ; -return 1 ; +return 0 ; }static int find_pack_entry (const unsigned char *sha1,struct pack_entry *e,const char **ignore_packed)
@@ -1717,7 +1717,7 @@ static int find_pack_entry(const unsigned char *sha1, struct pack_entry *e, consif (ignore_packed) {const char **ig;for (ig = ignore_packed; *ig; ig++) -if (!matches_pack_name (p, *ig)) +if (matches_pack_name (p, *ig))break ;if (*ig) goto next;
Signature · 1 line
1.5.3.1.967.g6bb01
PATCH 2/8 pack-objects --keep-unreachable
In reply to Junio C HamanoThis new option is meant to be used in conjunction with the options "git repack -a -d" usually invokes the underlying pack-objects. When this option is given, objects unreachable from the refs in packs named with --unpacked= option are added to the resulting pack, in addition to the reachable objects that are not in packs marked with *.keep files.
--- builtin-pack-objects.c | 95 +++++++++++++++++++++++++++++++++++++++++++++++- 1 files changed, 93 insertions(+), 2 deletions(-)
builtin-pack-objects.c +93 -2
@@ -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] [--keep-unreachable] [<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, keep_unreachable;static int local;static int incremental;static int allow_ofs_delta;
@@ -1625,15 +1625,19 @@ 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) {add_preferred_base_object (p->name);add_object_entry (p->item->sha1, p->item->type, p->name,0 ); + p->item->flags |=OBJECT_ADDED ; }static void show_edge (struct commit *commit)
@@ -1641,6 +1645,86 @@ static void show_edge(struct commit *commit)add_preferred_base (commit->object.sha1); } +struct in_pack_object { +off_t offset; +struct object *object; +}; + +struct in_pack { +int alloc; +int nr; +struct in_pack_object *array; +}; + +static void mark_in_pack_object (struct object *object,struct packed_git *p,struct in_pack *in_pack) +{ + in_pack->array[in_pack->nr].offset =find_pack_entry_one (object->sha1, p); + in_pack->array[in_pack->nr].object = object; + 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->object->sha1, b->object->sha1); +} + +static void add_objects_in_unpacked_packs (struct rev_info *revs) +{ +struct packed_git *p; +struct in_pack in_pack; +uint32_t i; + +memset (&in_pack,0 ,sizeof (in_pack)); + +for (p = packed_git; p; p = p->next) { +const unsigned char *sha1; +struct object *o; + +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" ); + +ALLOC_GROW (in_pack.array, + in_pack.nr + p->num_objects, + in_pack.alloc); + +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 (o, p, &in_pack); + o->flags |=OBJECT_ADDED ; + } + } + +if (in_pack.nr) { +qsort (in_pack.array, in_pack.nr,sizeof (in_pack.array[0 ]), + ofscmp); +for (i =0 ; i < in_pack.nr; i++) { +struct object *o = in_pack.array[i].object; +add_object_entry (o->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 (keep_unreachable) +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 ("--keep-unreachable" , arg)) { + keep_unreachable =1 ; +continue ; + } if (!strcmp("--unpacked", arg) || !prefixcmp(arg, "--unpacked=") || !strcmp("--reflog", arg) ||
Signature · 1 line
1.5.3.1.967.g6bb01
PATCH 3/8 repack -A -d: use --keep-unreachable when repacking
In reply to Junio C HamanoThis is a safer variant of "repack -a -d" that does not drop unreachable objects that are in packs.
--- git-repack.sh | 14 +++++++++++--- 1 files changed, 11 insertions(+), 3 deletions(-)
git-repack.sh +11 -3
@@ -3,17 +3,19 @@ # Copyright (c) 2005 Linus Torvalds # -USAGE='[-a] [-d] [-f] [-l] [-n] [-q] [--max-pack-size=N] [--window=N] [--window-memory=N] [--depth=N]' +USAGE='[-a|-A] [-d] [-f] [-l] [-n] [-q] [--max-pack-size=N] [--window=N] [--window-memory=N] [--depth=N]' SUBDIRECTORY_OK='Yes' . git-sh-setup -no_update_info= all_into_one= remove_redundant= +no_update_info= all_into_one= remove_redundant= keep_unreachable= local= quiet= no_reuse= extra= while case "$#" in 0) break ;; esac do case "$1" in -n) no_update_info=t ;; -a) all_into_one=t ;; + -A) all_into_one=t + keep_unreachable=t ;; -d) remove_redundant=t ;; -q) quiet=-q ;; -f) no_reuse=--no-reuse-object ;;
@@ -59,7 +61,13 @@ case ",$all_into_one," in fi done fi - [ -z "$args" ] && args='--unpacked --incremental' + if test -z "$args" + then + args='--unpacked --incremental' + elif test -n "$keep_unreachable" + then + args="$args --keep-unreachable" + fi ;; esac
Signature · 1 line
1.5.3.1.967.g6bb01
PATCH 4/8 git-gc --auto: move threshold check to need_to_gc() function.
In reply to Junio C HamanoThat is where we decide if we are going to run gc
automatically.
--- builtin-gc.c | 9 +++++++-- 1 files changed, 7 insertions(+), 2 deletions(-)
builtin-gc.c +7 -2
@@ -80,6 +80,13 @@ static int need_to_gc(void)int num_loose =0 ;int needed =0 ; +/* +* Setting gc.auto to 0 or negative can disable the +* automatic gc +*/ +if (gc_auto_threshold <=0 ) +return 0 ; +if (sizeof (path) <=snprintf (path,sizeof (path),"%s/17" , objdir)) {warning ("insanely long object directory %.*s" ,50 , objdir);return 0 ;
@@ -129,8 +136,6 @@ int cmd_gc(int argc, const char **argv, const char *prefix)continue ; }if (!strcmp (arg,"--auto" )) { -if (gc_auto_threshold <=0 ) -return 0 ; auto_gc =1 ;continue ; }
Signature · 1 line
1.5.3.1.967.g6bb01
PATCH 5/8 git-gc --auto: add documentation.
In reply to Junio C HamanoThis documents the auto-packing of loose objects performed by git-gc --auto.
--- Documentation/config.txt | 7 +++++++ Documentation/git-gc.txt | 11 ++++++++++- 2 files changed, 17 insertions(+), 1 deletions(-)
Documentation/config.txt +7 -0
@@ -439,6 +439,13 @@ gc.aggressiveWindow:: algorithm used by 'git gc --aggressive'. This defaults to 10. +gc.auto:: + When there are approximately more than this many loose + objects in the repository, `git gc --auto` that is + invoked by some Porcelain commands will create a new + pack and prune them. Setting this to 0 disables the + auto garbage collection. + gc.packrefs:: `git gc` does not run `git pack-refs` in a bare repository by default so that older dumb-transport clients can still fetch
Documentation/git-gc.txt +10 -1
@@ -8,7 +8,7 @@ git-gc - Cleanup unnecessary files and optimize the local repository SYNOPSIS -------- -'git-gc' [--prune] [--aggressive] +'git-gc' [--prune] [--aggressive] [--auto] DESCRIPTION -----------
@@ -43,6 +43,15 @@ OPTIONS persistent, so this option only needs to be used occasionally; every few hundred changesets or so. +--auto:: + With this option, `git gc` checks if there are too many + loose objects in the repository and runs + gitlink:git-repack[1] with `-d -l` option to pack them. + The threshold is set with `gc.auto` configuration + variable, and can be disabled by setting it to 0. Some + Porcelain commands use this after they perform operation + that could create many loose objects automatically. + Configuration -------------
Signature · 1 line
1.5.3.1.967.g6bb01
PATCH 6/8 git-gc --auto: protect ourselves from accumulated cruft
In reply to Junio C HamanoDeciding to run "repack -d -l" when there are too many loose objects would backfire when there are too many loose objects that are unreachable, because repacking that way would never improve the situation. Detect that case by checking the number of loose objects again after automatic garbage collection runs, and issue an warning to run "prune" manually.
--- builtin-gc.c | 25 +++++++++++++++++-------- 1 files changed, 17 insertions(+), 8 deletions(-)
builtin-gc.c +17 -8
@@ -64,7 +64,7 @@ static void append_option(const char **cmd, const char *opt, int max_length) cmd[i] =NULL ; } -static int need_to_gc (void ) +static int too_many_loose_objects (void ) {/* * Quickly check if a "gc" is needed, by estimating how
@@ -80,13 +80,6 @@ static int need_to_gc(void)int num_loose =0 ;int needed =0 ; -/* -* Setting gc.auto to 0 or negative can disable the -* automatic gc -*/ -if (gc_auto_threshold <=0 ) -return 0 ; -if (sizeof (path) <=snprintf (path,sizeof (path),"%s/17" , objdir)) {warning ("insanely long object directory %.*s" ,50 , objdir);return 0 ;
@@ -109,6 +102,18 @@ static int need_to_gc(void)return needed; } +static int need_to_gc (void ) +{ +/* +* Setting gc.auto to 0 or negative can disable the +* automatic gc +*/ +if (gc_auto_threshold <=0 ) +return 0 ; + +return too_many_loose_objects (); +} +int cmd_gc (int argc,const char **argv,const char *prefix) {int i;
@@ -170,5 +175,9 @@ int cmd_gc(int argc, const char **argv, const char *prefix)if (run_command_v_opt (argv_rerere,RUN_GIT_CMD ))return error (FAILED_RUN , argv_rerere[0 ]); +if (auto_gc &&too_many_loose_objects ()) +warning ("There are too many unreachable loose objects; " +"run 'git prune' to remove them." ); +return 0 ; }
Signature · 1 line
1.5.3.1.967.g6bb01
PATCH 7/8 git-gc --auto: restructure the way "repack" command line is built.
In reply to Junio C HamanoWe used to build the command line to run repack outside of need_to_gc() but with the next patch we would want to tweak the command line depending on the nature of need.
--- builtin-gc.c | 15 ++++++++++----- 1 files changed, 10 insertions(+), 5 deletions(-)
builtin-gc.c +10 -5
@@ -29,8 +29,6 @@ static const char *argv_repack[MAX_ADD] = {"repack", "-a", "-d", "-l", NULL};static const char *argv_prune[] = {"prune" ,NULL };static const char *argv_rerere[] = {"rerere" ,"gc" ,NULL }; -static const char *argv_repack_auto[] = {"repack" ,"-d" ,"-l" ,NULL }; -static int gc_config (const char *var,const char *value) {if (!strcmp (var,"gc.packrefs" )) {
@@ -104,6 +102,8 @@ static int too_many_loose_objects(void)static int need_to_gc (void ) { +int ac =0 ; +/* * Setting gc.auto to 0 or negative can disable the * automatic gc
@@ -111,7 +111,14 @@ static int need_to_gc(void)if (gc_auto_threshold <=0 )return 0 ; -return too_many_loose_objects (); +if (!too_many_loose_objects ()) +return 0 ; + + argv_repack[ac++] ="repack" ; + argv_repack[ac++] ="-d" ; + argv_repack[ac++] ="-l" ; + argv_repack[ac++] =NULL ; +return 1 ; }int cmd_gc (int argc,const char **argv,const char *prefix)
@@ -154,8 +161,6 @@ int cmd_gc(int argc, const char **argv, const char *prefix)* Auto-gc should be least intrusive as possible. */ prune =0 ; -for (i =0 ; i <ARRAY_SIZE (argv_repack_auto); i++) - argv_repack[i] = argv_repack_auto[i];if (!need_to_gc ())return 0 ; }
Signature · 1 line
1.5.3.1.967.g6bb01
PATCH 8/8 git-gc --auto: run "repack -A -d -l" as necessary.
In reply to Junio C HamanoThis teaches "git-gc --auto" to consolidate many packs into one without losing unreachable objects in them by using "repack -A" when there are too many packfiles that are not marked with *.keep in the repository. gc.autopacklimit configuration can be used to set the maximum number of packs a repository is allowed to have before this mechanism kicks in.
--- Documentation/config.txt | 9 +++++- Documentation/git-gc.txt | 7 +++++- builtin-gc.c | 57 +++++++++++++++++++++++++++++++++++++++++----- 3 files changed, 64 insertions(+), 9 deletions(-)
Documentation/config.txt +7 -2
@@ -443,8 +443,13 @@ gc.auto:: When there are approximately more than this many loose objects in the repository, `git gc --auto` that is invoked by some Porcelain commands will create a new - pack and prune them. Setting this to 0 disables the - auto garbage collection. + pack and prune them. Setting this to 0 disables this. + +gc.autopacklimit:: + When there are more than this many packs that are not + marked with `*.keep` file in the repository, `git gc + --auto` consolidates them into one larger pack. Setting + this to 0 disables this. gc.packrefs:: `git gc` does not run `git pack-refs` in a bare repository by
Documentation/git-gc.txt +6 -1
@@ -47,10 +47,15 @@ OPTIONS With this option, `git gc` checks if there are too many loose objects in the repository and runs gitlink:git-repack[1] with `-d -l` option to pack them. - The threshold is set with `gc.auto` configuration + The threshold for loose objects is set with `gc.auto` configuration variable, and can be disabled by setting it to 0. Some Porcelain commands use this after they perform operation that could create many loose objects automatically. + Additionally, when there are too many packs are present, + they are consolidated into one larger pack by running + the `git-repack` command with `-A` option. The + threshold for number of packs is set with + `gc.autopacklimit` configuration variable. Configuration -------------
builtin-gc.c +51 -6
90 lines not on this page · raw message
Signature · 1 line
1.5.3.1.967.g6bb01