files_transaction_finish(): delete reflogs before references
authorMichael Haggerty <mhagger@alum.mit.edu>
Fri, 8 Sep 2017 13:51:53 +0000 (15:51 +0200)
committerJunio C Hamano <gitster@pobox.com>
Fri, 8 Sep 2017 18:18:04 +0000 (03:18 +0900)
If the deletion steps unexpectedly fail, it is less bad to leave a
reference without its reflog than it is to leave a reflog without its
reference, since the latter is an invalid repository state.

Signed-off-by: Michael Haggerty <mhagger@alum.mit.edu>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
refs/files-backend.c
index 29eb5e826f6a5b52c2a16752624f1e68d6014eab..961424a4ea7e9d08f65e053243ad2def93456feb 100644 (file)
@@ -2636,6 +2636,27 @@ static int files_transaction_finish(struct ref_store *ref_store,
                }
        }
 
+       /*
+        * Now that updates are safely completed, we can perform
+        * deletes. First delete the reflogs of any references that
+        * will be deleted, since (in the unexpected event of an
+        * error) leaving a reference without a reflog is less bad
+        * than leaving a reflog without a reference (the latter is a
+        * mildly invalid repository state):
+        */
+       for (i = 0; i < transaction->nr; i++) {
+               struct ref_update *update = transaction->updates[i];
+               if (update->flags & REF_DELETING &&
+                   !(update->flags & REF_LOG_ONLY) &&
+                   !(update->flags & REF_ISPRUNING)) {
+                       strbuf_reset(&sb);
+                       files_reflog_path(refs, &sb, update->refname);
+                       if (!unlink_or_warn(sb.buf))
+                               try_remove_empty_parents(refs, update->refname,
+                                                        REMOVE_EMPTY_PARENTS_REFLOG);
+               }
+       }
+
        /*
         * Perform deletes now that updates are safely completed.
         *
@@ -2672,20 +2693,6 @@ static int files_transaction_finish(struct ref_store *ref_store,
                }
        }
 
-       /* Delete the reflogs of any references that were deleted: */
-       for (i = 0; i < transaction->nr; i++) {
-               struct ref_update *update = transaction->updates[i];
-               if (update->flags & REF_DELETING &&
-                   !(update->flags & REF_LOG_ONLY) &&
-                   !(update->flags & REF_ISPRUNING)) {
-                       strbuf_reset(&sb);
-                       files_reflog_path(refs, &sb, update->refname);
-                       if (!unlink_or_warn(sb.buf))
-                               try_remove_empty_parents(refs, update->refname,
-                                                        REMOVE_EMPTY_PARENTS_REFLOG);
-               }
-       }
-
        clear_loose_ref_cache(refs);
 
 cleanup: