@matheusbsbs / matheus-bagliano / commits / 3e6b1d0abc
Fork 0

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 <gitster@pobox.com>

Junio C Hamano committed Feb 10, 2009 at 12:16 UTC 3e6b1d0abcd58f0b2b106212ce0a0e07a6de342f
1 file changed +67 -20
git-repack.sh
+67 -20
@@ -88,32 +88,79 @@ if [ -z "$names" ]; then
88 echo Nothing new to pack.
89 fi
90 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
91
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
102 for sfx in pack idx
103 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"
150 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"
160 done
161
162 +# End of pack replacement.
163 +
164 if test "$remove_redundant" = t
165 then
166 # We know $existing are all redundant.