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:
commit
e5e9714a10
@ -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.
|
||||
|
16
builtin-gc.c
16
builtin-gc.c
@ -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]);
|
||||
|
@ -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();
|
||||
|
1
cache.h
1
cache.h
@ -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);
|
||||
|
||||
|
@ -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
|
||||
|
60
sha1_file.c
60
sha1_file.c
@ -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.
|
||||
|
47
t/t7701-repack-unpack-unreachable.sh
Executable file
47
t/t7701-repack-unpack-unreachable.sh
Executable 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
|
Loading…
Reference in New Issue
Block a user