3 # Keep track of the last time we modified the object store
5 # Beware, we MAY be running in a chroot!
9 # Make sure the current directory is where we expect to be
10 [ "${GIT_DIR+set}" != "set" ] ||
{ [ -n "$GIT_DIR" ] && [ -d "$GIT_DIR" ]; } ||
unset GIT_DIR
11 [ -n "$GIT_DIR" ] || GIT_DIR
="$(git rev-parse --git-dir)"
12 [ -n "$GIT_DIR" ] && cd -P "${GIT_DIR:-.}" ||
exit 1
13 case "${PWD%/*}" in */worktrees
)
16 # But it COULD just be a coincidence...
17 [ -s commondir
] && [ -s HEAD
] &&
18 _cmndir
= && read -r _cmndir
<commondir
2>/dev
/null
&&
19 [ -n "$_cmndir" ] && [ -d "$_cmndir" ]
21 # ...it is not, fix it!
22 cd -P "$_cmndir" ||
exit 1
25 GIT_DIR
="." GIT_PREFIX
= && export GIT_DIR
28 case "$PWD" in *?
/mob
)
30 GIROCCO_PERSONAL_MOB
=1
35 if [ -x @perlbin@
]; then
36 # We are NOT inside the chroot
38 list_packs
() { command "$basedir/bin/list_packs" "$@"; }
39 strftime
() { command "$basedir/bin/strftime" "$@"; }
42 git config gitweb.lastreceive
"$(date '+%a, %d %b %Y %T %z')"
44 # Read the incoming refs and freshen old loose objects
45 # If we waited until post-receive a gc could have already nuked them
46 # We freshen the new ref in case it's being resurrected to protect it from gc
47 # We probably do not need to do it for new refs as Git tries to do that,
48 # but since we're already doing it for old refs (which Git does not do),
49 # it's almost no extra work for new refs, just in case. We also attempt to
50 # make all packs user and group writable so they can be touched/renamed later.
52 # Starting with Git v2.11.0 receive-pack packs/objects end up in a quarantine
53 # object directory that is just discarded immediately if pre-receive declines
54 # to accept the push. This is a good thing. However, it means that the
55 # incoming objects are NOT located in objects/... as GIT_OBJECT_DIRECTORY and
56 # GIT_QUARANTINE_PATH are both set to the quarantine objects directory and the
57 # original objects directory is appended to GIT_ALTERNATE_OBJECT_DIRECTORIES
58 # (but it will just be the absolute path to objects). The simple bottom line
59 # is that we should also try everything in the GIT_QUARANTINE_PATH directory if
61 [ -z "$GIT_QUARANTINE_PATH" ] ||
[ -d "$GIT_QUARANTINE_PATH" ] ||
unset GIT_QUARANTINE_PATH
63 # We also record changes to a ref log. We do it here rather than in
64 # post-receive so that we can guarantee all potential changes are recorded in
65 # the log before they take place. It's possible that the update hook will
66 # ultimately deny one or more updates but waiting until post-receive could
67 # result in updates being left out of the log.
70 octet
="$hexdig$hexdig"
71 octet4
="$octet$octet$octet$octet"
72 octet20
="$octet4$octet4$octet4$octet4$octet4"
74 find -L "$1" -maxdepth 1 -type f
! -perm -ug+rw
,o
+r \
75 -name "pack-$octet20*.*" -exec chmod ug
+rw
,o
+r
'{}' + ||
:
77 _make_packs_ugrw objects
/pack
78 if [ -n "$GIT_QUARANTINE_PATH" ]; then
79 # gc.sh will be unable remove stale incoming-* dirs without this
80 chmod ug
+rwx
,o
+rx
"$GIT_QUARANTINE_PATH" "$GIT_QUARANTINE_PATH/pack" >/dev
/null
2>&1 ||
:
81 chmod g
+s
"$GIT_QUARANTINE_PATH" "$GIT_QUARANTINE_PATH/pack" >/dev
/null
2>&1 ||
:
82 _make_packs_ugrw
"$GIT_QUARANTINE_PATH/pack"
85 # Trigger a mini-gc if there are at least 20 packs present.
86 # Our current pack that contains this push's data will have a .keep while
87 # this hook is running so it will be excluded from the count, but the count
88 # is only an approximate guide anyway and being off by one or two will not
89 # cause any performance problems. We could drop the check to 19 instead to
90 # compensate but there could be other simultaneous pushes and it's highly
91 # unlikely that it would end up making any difference anyway. We also
92 # deliberately ignore anything in the "$GIT_QUARANTINE_PATH/pack" area because
93 # at this point it will have a .keep (if it exists) and because of the way
94 # it's created there can never be more than one pack in there anyway.
95 # The mini-gc code contains the logic to sort out small packs vs. non-small
96 # packs and which should be combined in what order so we do not need to
97 # do any more complicated testing here.
98 if ! [ -e .needsgc
]; then
100 { packs
="$(list_packs --quiet --count --exclude-no-idx --exclude-keep objects/pack || :)" ||
:; } 2>/dev
/null
101 if [ -n "$packs" ] && [ "$packs" -ge 20 ]; then
106 # Make sure we have a reflogs directory and abort the update if we cannot
107 # create one. Normally project creation will make sure this directory exists.
108 [ -d reflogs
] || mkdir
-p reflogs
>/dev
/null
2>&1 ||
:
111 # Multiple push operations could be occurring simultaneously so we need to
112 # guarantee they do not step on one another and we do this by generating a
113 # unique log file name. We use a microseconds timestamp and the current process
114 # id and we guarantee that this process is kept alive for the entire microsecond
115 # of the timestamp thereby guaranteeing that we are the only possible process
116 # that could use that pid during that particular microsecond (ignoring leap seconds).
117 # To do this we need to sleep until the microsecond turns over, grab the timestamp
118 # and then sleep until the microsecond turns over again. This will introduce a
119 # guaranteed 2 microsecond delay into every push. This should not generally be
120 # noticeable. The strftime utility does this for us when using %N with current time.
121 # We always use UTC for the timestamp so that chroot and non-chroot match up.
122 # Log entries are the lines sent to the pre-receive hook with hhmmss prepended.
123 lognamets
="$(TZ=UTC strftime '%Y%m%d_%H%M%S%N')"
124 lognamets
="${lognamets%???}"
125 loghhmmss
="${lognamets##*_}"
126 loghhmmss
="${loghhmmss%??????}"
128 # We write to a temp ref log and then move it into place so that the reflogs
129 # collector can assume that log files with their final name are immutable
130 logname
="reflogs/$lognamets.$$"
131 lognametmp
="reflogs/tmp_$lognamets.$$"
133 while read -r old new ref
; do
134 echo "$loghhmmss $old $new $ref" >&3
136 if [ "$old" != "0000000000000000000000000000000000000000" ]; then
137 # freshen mod time on recently unref'd loose objects
140 args
="$args 'objects/$shard/$fn'"
141 [ -z "$GIT_QUARANTINE_DIRECTORY" ] || args
="$args '$GIT_QUARANTINE_DIRECTORY/$shard/$fn'"
143 if [ "$new" != "0000000000000000000000000000000000000000" ]; then
144 # prevent imminent pruning of a ref being resurrected
147 args
="$args 'objects/$shard/$fn'"
148 [ -z "$GIT_QUARANTINE_DIRECTORY" ] || args
="$args '$GIT_QUARANTINE_DIRECTORY/$shard/$fn'"
150 eval "chmod ug+w $args" 2>/dev
/null ||
:
151 eval "touch -c $args" 2>/dev
/null ||
:
153 mv "$lognametmp" "$logname"
155 # While unlikely, it is conceivable that several ref updates have occurred that
156 # did not actually push any packs. In that case we could build up a large
157 # number of log files so request a mini gc if there are 50 or more of them now.
158 if ! [ -e .needsgc
]; then
160 { logfiles
="$(($(find -L reflogs -maxdepth 1 -type f -print | wc -l || :)+0))" ||
:; } 2>/dev
/null
161 if [ -n "$logfiles" ] && [ "$logfiles" -ge 50 ]; then