Merge branch 'bc/repack'

* bc/repack:
  Documentation/git-repack.txt: document new -A behaviour
  let pack-objects do the writing of unreachable objects as loose objects
  add a force_object_loose() function
  builtin-gc.c: deprecate --prune, it now really has no effect
  git-gc: always use -A when manually repacking
  repack: modify behavior of -A option to leave unreferenced objects unpacked

Conflicts:

	builtin-pack-objects.c
This commit is contained in:
Junio C Hamano 2008-05-23 16:06:01 -07:00
commit e5e9714a10
7 changed files with 154 additions and 34 deletions

View File

@ -8,7 +8,7 @@ git-repack - Pack unpacked objects in a repository
SYNOPSIS
--------
'git-repack' [-a] [-d] [-f] [-l] [-n] [-q] [--window=N] [--depth=N]
'git-repack' [-a] [-A] [-d] [-f] [-l] [-n] [-q] [--window=N] [--depth=N]
DESCRIPTION
-----------
@ -37,6 +37,18 @@ OPTIONS
leaves behind, but `git fsck --full` shows as
dangling.
-A::
Same as `-a`, but any unreachable objects in a previous
pack become loose, unpacked objects, instead of being
left in the old pack. Unreachable objects are never
intentionally added to a pack, even when repacking.
When used with '-d', this option
prevents unreachable objects from being immediately
deleted by way of being left in the old pack and then
removed. Instead, the loose unreachable objects
will be pruned according to normal expiry rules
with the next linkgit:git-gc[1].
-d::
After packing, if the newly created packs make some
existing packs redundant, remove the redundant packs.

View File

@ -219,7 +219,7 @@ int cmd_gc(int argc, const char **argv, const char *prefix)
char buf[80];
struct option builtin_gc_options[] = {
OPT_BOOLEAN(0, "prune", &prune, "prune unreferenced objects"),
OPT_BOOLEAN(0, "prune", &prune, "prune unreferenced objects (deprecated)"),
OPT_BOOLEAN(0, "aggressive", &aggressive, "be more thorough (increased runtime)"),
OPT_BOOLEAN(0, "auto", &auto_gc, "enable auto-gc mode"),
OPT_BOOLEAN('q', "quiet", &quiet, "suppress progress reports"),
@ -249,24 +249,14 @@ int cmd_gc(int argc, const char **argv, const char *prefix)
/*
* Auto-gc should be least intrusive as possible.
*/
prune = 0;
if (!need_to_gc())
return 0;
fprintf(stderr, "Auto packing your repository for optimum "
"performance. You may also\n"
"run \"git gc\" manually. See "
"\"git help gc\" for more information.\n");
} else {
/*
* Use safer (for shared repos) "-A" option to
* repack when not pruning. Auto-gc makes its
* own decision.
*/
if (prune)
append_option(argv_repack, "-a", MAX_ADD);
else
append_option(argv_repack, "-A", MAX_ADD);
}
} else
append_option(argv_repack, "-A", MAX_ADD);
if (pack_refs && run_command_v_opt(argv_pack_refs, RUN_GIT_CMD))
return error(FAILED_RUN, argv_pack_refs[0]);

View File

@ -28,7 +28,8 @@ 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\
[--threads=N] [--non-empty] [--revs [--unpacked | --all]*] [--reflog] \n\
[--stdout | base-name] [--include-tag] [--keep-unreachable] \n\
[--stdout | base-name] [--include-tag] \n\
[--keep-unreachable | --unpack-unreachable] \n\
[<ref-list | <object-list]";
struct object_entry {
@ -67,7 +68,7 @@ static uint32_t nr_objects, nr_alloc, nr_result, nr_written;
static int non_empty;
static int reuse_delta = 1, reuse_object = 1;
static int keep_unreachable, include_tag;
static int keep_unreachable, unpack_unreachable, include_tag;
static int local;
static int incremental;
static int allow_ofs_delta;
@ -1946,6 +1947,32 @@ static void add_objects_in_unpacked_packs(struct rev_info *revs)
free(in_pack.array);
}
static void loosen_unused_packed_objects(struct rev_info *revs)
{
struct packed_git *p;
uint32_t i;
const unsigned char *sha1;
for (p = packed_git; p; p = p->next) {
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");
for (i = 0; i < p->num_objects; i++) {
sha1 = nth_packed_object_sha1(p, i);
if (!locate_object_entry(sha1))
if (force_object_loose(sha1, p->mtime))
die("unable to force loose object");
}
}
}
static void get_object_list(int ac, const char **av)
{
struct rev_info revs;
@ -1980,6 +2007,8 @@ static void get_object_list(int ac, const char **av)
if (keep_unreachable)
add_objects_in_unpacked_packs(&revs);
if (unpack_unreachable)
loosen_unused_packed_objects(&revs);
}
static int adjust_perm(const char *path, mode_t mode)
@ -2114,6 +2143,10 @@ int cmd_pack_objects(int argc, const char **argv, const char *prefix)
keep_unreachable = 1;
continue;
}
if (!strcmp("--unpack-unreachable", arg)) {
unpack_unreachable = 1;
continue;
}
if (!strcmp("--include-tag", arg)) {
include_tag = 1;
continue;
@ -2179,6 +2212,9 @@ int cmd_pack_objects(int argc, const char **argv, const char *prefix)
if (!pack_to_stdout && thin)
die("--thin cannot be used to build an indexable pack.");
if (keep_unreachable && unpack_unreachable)
die("--keep-unreachable and --unpack-unreachable are incompatible.");
#ifdef THREADED_DELTA_SEARCH
if (!delta_search_threads) /* --threads=0 means autodetect */
delta_search_threads = online_cpus();

View File

@ -521,6 +521,7 @@ extern void * read_sha1_file(const unsigned char *sha1, enum object_type *type,
extern int hash_sha1_file(const void *buf, unsigned long len, const char *type, unsigned char *sha1);
extern int write_sha1_file(void *buf, unsigned long len, const char *type, unsigned char *return_sha1);
extern int pretend_sha1_file(void *, unsigned long, enum object_type, unsigned char *);
extern int force_object_loose(const unsigned char *sha1, time_t mtime);
extern int check_sha1_signature(const unsigned char *sha1, void *buf, unsigned long size, const char *type);

View File

@ -8,7 +8,7 @@ OPTIONS_SPEC="\
git-repack [options]
--
a pack everything in a single pack
A same as -a, and keep unreachable objects too
A same as -a, and turn unreachable objects loose
d remove redundant packs, and run git-prune-packed
f pass --no-reuse-delta to git-pack-objects
n do not run git-update-server-info
@ -23,7 +23,7 @@ max-pack-size= maximum size of each packfile
SUBDIRECTORY_OK='Yes'
. git-sh-setup
no_update_info= all_into_one= remove_redundant= keep_unreachable=
no_update_info= all_into_one= remove_redundant= unpack_unreachable=
local= quiet= no_reuse= extra=
while test $# != 0
do
@ -31,7 +31,7 @@ do
-n) no_update_info=t ;;
-a) all_into_one=t ;;
-A) all_into_one=t
keep_unreachable=--keep-unreachable ;;
unpack_unreachable=--unpack-unreachable ;;
-d) remove_redundant=t ;;
-q) quiet=-q ;;
-f) no_reuse=--no-reuse-object ;;
@ -79,9 +79,9 @@ case ",$all_into_one," in
if test -z "$args"
then
args='--unpacked --incremental'
elif test -n "$keep_unreachable"
elif test -n "$unpack_unreachable"
then
args="$args $keep_unreachable"
args="$args $unpack_unreachable"
fi
;;
esac

View File

@ -2102,26 +2102,16 @@ int hash_sha1_file(const void *buf, unsigned long len, const char *type,
return 0;
}
int write_sha1_file(void *buf, unsigned long len, const char *type, unsigned char *returnsha1)
static int write_loose_object(const unsigned char *sha1, char *hdr, int hdrlen,
void *buf, unsigned long len, time_t mtime)
{
int size, ret;
int fd, size, ret;
unsigned char *compressed;
z_stream stream;
unsigned char sha1[20];
char *filename;
static char tmpfile[PATH_MAX];
char hdr[32];
int fd, hdrlen;
/* Normally if we have it in the pack then we do not bother writing
* it out into .git/objects/??/?{38} file.
*/
write_sha1_file_prepare(buf, len, type, sha1, hdr, &hdrlen);
filename = sha1_file_name(sha1);
if (returnsha1)
hashcpy(returnsha1, sha1);
if (has_sha1_file(sha1))
return 0;
fd = open(filename, O_RDONLY);
if (fd >= 0) {
/*
@ -2182,9 +2172,53 @@ int write_sha1_file(void *buf, unsigned long len, const char *type, unsigned cha
die("unable to write sha1 file");
free(compressed);
if (mtime) {
struct utimbuf utb;
utb.actime = mtime;
utb.modtime = mtime;
if (utime(tmpfile, &utb) < 0)
warning("failed utime() on %s: %s",
tmpfile, strerror(errno));
}
return move_temp_to_file(tmpfile, filename);
}
int write_sha1_file(void *buf, unsigned long len, const char *type, unsigned char *returnsha1)
{
unsigned char sha1[20];
char hdr[32];
int hdrlen;
/* Normally if we have it in the pack then we do not bother writing
* it out into .git/objects/??/?{38} file.
*/
write_sha1_file_prepare(buf, len, type, sha1, hdr, &hdrlen);
if (returnsha1)
hashcpy(returnsha1, sha1);
if (has_sha1_file(sha1))
return 0;
return write_loose_object(sha1, hdr, hdrlen, buf, len, 0);
}
int force_object_loose(const unsigned char *sha1, time_t mtime)
{
struct stat st;
void *buf;
unsigned long len;
enum object_type type;
char hdr[32];
int hdrlen;
if (find_sha1_file(sha1, &st))
return 0;
buf = read_packed_sha1(sha1, &type, &len);
if (!buf)
return error("cannot read sha1_file for %s", sha1_to_hex(sha1));
hdrlen = sprintf(hdr, "%s %lu", typename(type), len) + 1;
return write_loose_object(sha1, hdr, hdrlen, buf, len, mtime);
}
/*
* We need to unpack and recompress the object for writing
* it out to a different file.

View File

@ -0,0 +1,47 @@
#!/bin/sh
test_description='git-repack works correctly'
. ./test-lib.sh
test_expect_success '-A option leaves unreachable objects unpacked' '
echo content > file1 &&
git add . &&
git commit -m initial_commit &&
# create a transient branch with unique content
git checkout -b transient_branch &&
echo more content >> file1 &&
# record the objects created in the database for file, commit, tree
fsha1=$(git hash-object file1) &&
git commit -a -m more_content &&
csha1=$(git rev-parse HEAD^{commit}) &&
tsha1=$(git rev-parse HEAD^{tree}) &&
git checkout master &&
echo even more content >> file1 &&
git commit -a -m even_more_content &&
# delete the transient branch
git branch -D transient_branch &&
# pack the repo
git repack -A -d -l &&
# verify objects are packed in repository
test 3 = $(git verify-pack -v -- .git/objects/pack/*.idx |
grep -e "^$fsha1 " -e "^$csha1 " -e "^$tsha1 " |
sort | uniq | wc -l) &&
git show $fsha1 &&
git show $csha1 &&
git show $tsha1 &&
# now expire the reflog
sleep 1 &&
git reflog expire --expire-unreachable=now --all &&
# and repack
git repack -A -d -l &&
# verify objects are retained unpacked
test 0 = $(git verify-pack -v -- .git/objects/pack/*.idx |
grep -e "^$fsha1 " -e "^$csha1 " -e "^$tsha1 " |
sort | uniq | wc -l) &&
git show $fsha1 &&
git show $csha1 &&
git show $tsha1
'
test_done