Skip to content

Commit 3e6b1d0

Browse files
committed
Make repack less likely to corrupt repository
Some platforms refuse to rename a file that is open. When repacking an already packed repository without adding any new object, the resulting pack will contain the same set of objects as an existing pack, and on such platforms, a newly created packfile cannot replace the existing one. The logic detected this issue but did not try hard enough to recover from it. Especially because the files that needs renaming come in pairs, there potentially are different failure modes that one can be renamed but the others cannot. Asking manual recovery to end users were error prone. This patch tries to make it more robust by first making sure all the existing files that need to be renamed have been renamed before continuing, and attempts to roll back if some failed to rename. This is based on an initial patch by Robin Rosenberg. Signed-off-by: Junio C Hamano <[email protected]>
1 parent 784f8af commit 3e6b1d0

File tree

1 file changed

+67
-20
lines changed

1 file changed

+67
-20
lines changed

git-repack.sh

Lines changed: 67 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -88,32 +88,79 @@ if [ -z "$names" ]; then
8888
echo Nothing new to pack.
8989
fi
9090
fi
91-
for name in $names ; do
92-
fullbases="$fullbases pack-$name"
93-
chmod a-w "$PACKTMP-$name.pack"
94-
chmod a-w "$PACKTMP-$name.idx"
95-
mkdir -p "$PACKDIR" || exit
9691

92+
# Ok we have prepared all new packfiles.
93+
mkdir -p "$PACKDIR" || exit
94+
95+
# First see if there are packs of the same name and if so
96+
# if we can move them out of the way (this can happen if we
97+
# repacked immediately after packing fully.
98+
rollback=
99+
failed=
100+
for name in $names
101+
do
97102
for sfx in pack idx
98103
do
99-
if test -f "$PACKDIR/pack-$name.$sfx"
100-
then
101-
mv -f "$PACKDIR/pack-$name.$sfx" \
102-
"$PACKDIR/old-pack-$name.$sfx"
103-
fi
104-
done &&
104+
file=pack-$name.$sfx
105+
test -f "$PACKDIR/$file" || continue
106+
rm -f "$PACKDIR/old-$file" &&
107+
mv "$PACKDIR/$file" "$PACKDIR/old-$file" || {
108+
failed=t
109+
break
110+
}
111+
rollback="$rollback $file"
112+
done
113+
test -z "$failed" || break
114+
done
115+
116+
# If renaming failed for any of them, roll the ones we have
117+
# already renamed back to their original names.
118+
if test -n "$failed"
119+
then
120+
rollback_failure=
121+
for file in $rollback
122+
do
123+
mv "$PACKDIR/old-$file" "$PACKDIR/$file" ||
124+
rollback_failure="$rollback_failure $file"
125+
done
126+
if test -n "$rollback_failure"
127+
then
128+
echo >&2 "WARNING: Some packs in use have been renamed by"
129+
echo >&2 "WARNING: prefixing old- to their name, in order to"
130+
echo >&2 "WARNING: replace them with the new version of the"
131+
echo >&2 "WARNING: file. But the operation failed, and"
132+
echo >&2 "WARNING: attempt to rename them back to their"
133+
echo >&2 "WARNING: original names also failed."
134+
echo >&2 "WARNING: Please rename them in $PACKDIR manually:"
135+
for file in $rollback_failure
136+
do
137+
echo >&2 "WARNING: old-$file -> $file"
138+
done
139+
fi
140+
exit 1
141+
fi
142+
143+
# Now the ones with the same name are out of the way...
144+
fullbases=
145+
for name in $names
146+
do
147+
fullbases="$fullbases pack-$name"
148+
chmod a-w "$PACKTMP-$name.pack"
149+
chmod a-w "$PACKTMP-$name.idx"
105150
mv -f "$PACKTMP-$name.pack" "$PACKDIR/pack-$name.pack" &&
106-
mv -f "$PACKTMP-$name.idx" "$PACKDIR/pack-$name.idx" &&
107-
test -f "$PACKDIR/pack-$name.pack" &&
108-
test -f "$PACKDIR/pack-$name.idx" || {
109-
echo >&2 "Couldn't replace the existing pack with updated one."
110-
echo >&2 "The original set of packs have been saved as"
111-
echo >&2 "old-pack-$name.{pack,idx} in $PACKDIR."
112-
exit 1
113-
}
114-
rm -f "$PACKDIR/old-pack-$name.pack" "$PACKDIR/old-pack-$name.idx"
151+
mv -f "$PACKTMP-$name.idx" "$PACKDIR/pack-$name.idx" ||
152+
exit
153+
done
154+
155+
# Remove the "old-" files
156+
for name in $names
157+
do
158+
rm -f "$PACKDIR/old-pack-$name.idx"
159+
rm -f "$PACKDIR/old-pack-$name.pack"
115160
done
116161

162+
# End of pack replacement.
163+
117164
if test "$remove_redundant" = t
118165
then
119166
# We know $existing are all redundant.

0 commit comments

Comments
 (0)