mirror of
https://github.com/git/git
synced 2024-08-27 19:49:21 +00:00
![Jeff King](/assets/img/avatar_default.png)
When we pack everything into one big pack with "git repack -Ad", any unreferenced objects in to-be-deleted packs are exploded into loose objects, with the intent that they will be examined and possibly cleaned up by the next run of "git prune". Since the exploded objects will receive the mtime of the pack from which they come, if the source pack is old, those loose objects will end up pruned immediately. In that case, it is much more efficient to skip the exploding step entirely for these objects. This patch teaches pack-objects to receive the expiration information and avoid writing these objects out. It also teaches "git gc" to pass the value of gc.pruneexpire to repack (which in turn learns to pass it along to pack-objects) so that this optimization happens automatically during "git gc" and "git gc --auto". Signed-off-by: Jeff King <peff@peff.net> Acked-by: Nicolas Pitre <nico@fluxnic.net> Signed-off-by: Junio C Hamano <gitster@pobox.com>
195 lines
4.9 KiB
Bash
Executable file
195 lines
4.9 KiB
Bash
Executable file
#!/bin/sh
|
|
#
|
|
# Copyright (c) 2005 Linus Torvalds
|
|
#
|
|
|
|
OPTIONS_KEEPDASHDASH=
|
|
OPTIONS_SPEC="\
|
|
git repack [options]
|
|
--
|
|
a pack everything in a single pack
|
|
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
|
|
F pass --no-reuse-object to git-pack-objects
|
|
n do not run git-update-server-info
|
|
q,quiet be quiet
|
|
l pass --local to git-pack-objects
|
|
unpack-unreachable= with -A, do not loosen objects older than this
|
|
Packing constraints
|
|
window= size of the window used for delta compression
|
|
window-memory= same as the above, but limit memory size instead of entries count
|
|
depth= limits the maximum delta depth
|
|
max-pack-size= maximum size of each packfile
|
|
"
|
|
SUBDIRECTORY_OK='Yes'
|
|
. git-sh-setup
|
|
|
|
no_update_info= all_into_one= remove_redundant= unpack_unreachable=
|
|
local= no_reuse= extra=
|
|
while test $# != 0
|
|
do
|
|
case "$1" in
|
|
-n) no_update_info=t ;;
|
|
-a) all_into_one=t ;;
|
|
-A) all_into_one=t
|
|
unpack_unreachable=--unpack-unreachable ;;
|
|
--unpack-unreachable)
|
|
unpack_unreachable="--unpack-unreachable=$2"; shift ;;
|
|
-d) remove_redundant=t ;;
|
|
-q) GIT_QUIET=t ;;
|
|
-f) no_reuse=--no-reuse-delta ;;
|
|
-F) no_reuse=--no-reuse-object ;;
|
|
-l) local=--local ;;
|
|
--max-pack-size|--window|--window-memory|--depth)
|
|
extra="$extra $1=$2"; shift ;;
|
|
--) shift; break;;
|
|
*) usage ;;
|
|
esac
|
|
shift
|
|
done
|
|
|
|
case "`git config --bool repack.usedeltabaseoffset || echo true`" in
|
|
true)
|
|
extra="$extra --delta-base-offset" ;;
|
|
esac
|
|
|
|
PACKDIR="$GIT_OBJECT_DIRECTORY/pack"
|
|
PACKTMP="$PACKDIR/.tmp-$$-pack"
|
|
rm -f "$PACKTMP"-*
|
|
trap 'rm -f "$PACKTMP"-*' 0 1 2 3 15
|
|
|
|
# There will be more repacking strategies to come...
|
|
case ",$all_into_one," in
|
|
,,)
|
|
args='--unpacked --incremental'
|
|
;;
|
|
,t,)
|
|
args= existing=
|
|
if [ -d "$PACKDIR" ]; then
|
|
for e in `cd "$PACKDIR" && find . -type f -name '*.pack' \
|
|
| sed -e 's/^\.\///' -e 's/\.pack$//'`
|
|
do
|
|
if [ -e "$PACKDIR/$e.keep" ]; then
|
|
: keep
|
|
else
|
|
existing="$existing $e"
|
|
fi
|
|
done
|
|
if test -n "$existing" -a -n "$unpack_unreachable" -a \
|
|
-n "$remove_redundant"
|
|
then
|
|
# This may have arbitrary user arguments, so we
|
|
# have to protect it against whitespace splitting
|
|
# when it gets run as "pack-objects $args" later.
|
|
# Fortunately, we know it's an approxidate, so we
|
|
# can just use dots instead.
|
|
args="$args $(echo "$unpack_unreachable" | tr ' ' .)"
|
|
fi
|
|
fi
|
|
;;
|
|
esac
|
|
|
|
mkdir -p "$PACKDIR" || exit
|
|
|
|
args="$args $local ${GIT_QUIET:+-q} $no_reuse$extra"
|
|
names=$(git pack-objects --keep-true-parents --honor-pack-keep --non-empty --all --reflog $args </dev/null "$PACKTMP") ||
|
|
exit 1
|
|
if [ -z "$names" ]; then
|
|
say Nothing new to pack.
|
|
fi
|
|
|
|
# Ok we have prepared all new packfiles.
|
|
|
|
# First see if there are packs of the same name and if so
|
|
# if we can move them out of the way (this can happen if we
|
|
# repacked immediately after packing fully.
|
|
rollback=
|
|
failed=
|
|
for name in $names
|
|
do
|
|
for sfx in pack idx
|
|
do
|
|
file=pack-$name.$sfx
|
|
test -f "$PACKDIR/$file" || continue
|
|
rm -f "$PACKDIR/old-$file" &&
|
|
mv "$PACKDIR/$file" "$PACKDIR/old-$file" || {
|
|
failed=t
|
|
break
|
|
}
|
|
rollback="$rollback $file"
|
|
done
|
|
test -z "$failed" || break
|
|
done
|
|
|
|
# If renaming failed for any of them, roll the ones we have
|
|
# already renamed back to their original names.
|
|
if test -n "$failed"
|
|
then
|
|
rollback_failure=
|
|
for file in $rollback
|
|
do
|
|
mv "$PACKDIR/old-$file" "$PACKDIR/$file" ||
|
|
rollback_failure="$rollback_failure $file"
|
|
done
|
|
if test -n "$rollback_failure"
|
|
then
|
|
echo >&2 "WARNING: Some packs in use have been renamed by"
|
|
echo >&2 "WARNING: prefixing old- to their name, in order to"
|
|
echo >&2 "WARNING: replace them with the new version of the"
|
|
echo >&2 "WARNING: file. But the operation failed, and"
|
|
echo >&2 "WARNING: attempt to rename them back to their"
|
|
echo >&2 "WARNING: original names also failed."
|
|
echo >&2 "WARNING: Please rename them in $PACKDIR manually:"
|
|
for file in $rollback_failure
|
|
do
|
|
echo >&2 "WARNING: old-$file -> $file"
|
|
done
|
|
fi
|
|
exit 1
|
|
fi
|
|
|
|
# Now the ones with the same name are out of the way...
|
|
fullbases=
|
|
for name in $names
|
|
do
|
|
fullbases="$fullbases pack-$name"
|
|
chmod a-w "$PACKTMP-$name.pack"
|
|
chmod a-w "$PACKTMP-$name.idx"
|
|
mv -f "$PACKTMP-$name.pack" "$PACKDIR/pack-$name.pack" &&
|
|
mv -f "$PACKTMP-$name.idx" "$PACKDIR/pack-$name.idx" ||
|
|
exit
|
|
done
|
|
|
|
# Remove the "old-" files
|
|
for name in $names
|
|
do
|
|
rm -f "$PACKDIR/old-pack-$name.idx"
|
|
rm -f "$PACKDIR/old-pack-$name.pack"
|
|
done
|
|
|
|
# End of pack replacement.
|
|
|
|
if test "$remove_redundant" = t
|
|
then
|
|
# We know $existing are all redundant.
|
|
if [ -n "$existing" ]
|
|
then
|
|
( cd "$PACKDIR" &&
|
|
for e in $existing
|
|
do
|
|
case " $fullbases " in
|
|
*" $e "*) ;;
|
|
*) rm -f "$e.pack" "$e.idx" "$e.keep" ;;
|
|
esac
|
|
done
|
|
)
|
|
fi
|
|
git prune-packed ${GIT_QUIET:+-q}
|
|
fi
|
|
|
|
case "$no_update_info" in
|
|
t) : ;;
|
|
*) git update-server-info ;;
|
|
esac
|