Merge branch 'mk/diff-shortstat-dirstat-fix'
[gitweb.git] / refs.c
diff --git a/refs.c b/refs.c
index d5bfd1179044b9a6aeec1492a31d2a907b951d36..8d46b08055ef9cb151c1868a0354fd906b0bcddf 100644 (file)
--- a/refs.c
+++ b/refs.c
@@ -46,11 +46,17 @@ static unsigned char refname_disposition[256] = {
  */
 #define REF_ISPRUNING  0x04
 
+/*
+ * Used as a flag in ref_update::flags when the reference should be
+ * updated to new_sha1.
+ */
+#define REF_HAVE_NEW   0x08
+
 /*
  * Used as a flag in ref_update::flags when old_sha1 should be
  * checked.
  */
-#define REF_HAVE_OLD   0x08
+#define REF_HAVE_OLD   0x10
 
 /*
  * Try to read one refname component from the front of refname.
@@ -3577,10 +3583,17 @@ int for_each_reflog(each_ref_fn fn, void *cb_data)
  * not exist before update.
  */
 struct ref_update {
+       /*
+        * If (flags & REF_HAVE_NEW), set the reference to this value:
+        */
        unsigned char new_sha1[20];
+       /*
+        * If (flags & REF_HAVE_OLD), check that the reference
+        * previously had this value:
+        */
        unsigned char old_sha1[20];
        /*
-        * One or more of REF_HAVE_OLD, REF_NODEREF,
+        * One or more of REF_HAVE_NEW, REF_HAVE_OLD, REF_NODEREF,
         * REF_DELETING, and REF_ISPRUNING:
         */
        unsigned int flags;
@@ -3665,7 +3678,7 @@ int ref_transaction_update(struct ref_transaction *transaction,
        if (transaction->state != REF_TRANSACTION_OPEN)
                die("BUG: update called for transaction that is not open");
 
-       if (!is_null_sha1(new_sha1) &&
+       if (new_sha1 && !is_null_sha1(new_sha1) &&
            check_refname_format(refname, REFNAME_ALLOW_ONELEVEL)) {
                strbuf_addf(err, "refusing to update ref with bad name %s",
                            refname);
@@ -3673,7 +3686,10 @@ int ref_transaction_update(struct ref_transaction *transaction,
        }
 
        update = add_update(transaction, refname);
-       hashcpy(update->new_sha1, new_sha1);
+       if (new_sha1) {
+               hashcpy(update->new_sha1, new_sha1);
+               flags |= REF_HAVE_NEW;
+       }
        if (old_sha1) {
                hashcpy(update->old_sha1, old_sha1);
                flags |= REF_HAVE_OLD;
@@ -3709,8 +3725,21 @@ int ref_transaction_delete(struct ref_transaction *transaction,
                                      flags, msg, err);
 }
 
-int update_ref(const char *action, const char *refname,
-              const unsigned char *sha1, const unsigned char *oldval,
+int ref_transaction_verify(struct ref_transaction *transaction,
+                          const char *refname,
+                          const unsigned char *old_sha1,
+                          unsigned int flags,
+                          struct strbuf *err)
+{
+       if (!old_sha1)
+               die("BUG: verify called with old_sha1 set to NULL");
+       return ref_transaction_update(transaction, refname,
+                                     NULL, old_sha1,
+                                     flags, NULL, err);
+}
+
+int update_ref(const char *msg, const char *refname,
+              const unsigned char *new_sha1, const unsigned char *old_sha1,
               unsigned int flags, enum action_on_err onerr)
 {
        struct ref_transaction *t;
@@ -3718,8 +3747,8 @@ int update_ref(const char *action, const char *refname,
 
        t = ref_transaction_begin(&err);
        if (!t ||
-           ref_transaction_update(t, refname, sha1, oldval,
-                                  flags, action, &err) ||
+           ref_transaction_update(t, refname, new_sha1, old_sha1,
+                                  flags, msg, &err) ||
            ref_transaction_commit(t, &err)) {
                const char *str = "update_ref failed for ref '%s': %s";
 
@@ -3797,7 +3826,7 @@ int ref_transaction_commit(struct ref_transaction *transaction,
                struct ref_update *update = updates[i];
                unsigned int flags = update->flags;
 
-               if (is_null_sha1(update->new_sha1))
+               if ((flags & REF_HAVE_NEW) && is_null_sha1(update->new_sha1))
                        flags |= REF_DELETING;
                update->lock = lock_ref_sha1_basic(
                                update->refname,
@@ -3819,8 +3848,9 @@ int ref_transaction_commit(struct ref_transaction *transaction,
        /* Perform updates first so live commits remain referenced */
        for (i = 0; i < n; i++) {
                struct ref_update *update = updates[i];
+               int flags = update->flags;
 
-               if (!is_null_sha1(update->new_sha1)) {
+               if ((flags & REF_HAVE_NEW) && !is_null_sha1(update->new_sha1)) {
                        if (write_ref_sha1(update->lock, update->new_sha1,
                                           update->msg)) {
                                update->lock = NULL; /* freed by write_ref_sha1 */
@@ -3836,14 +3866,15 @@ int ref_transaction_commit(struct ref_transaction *transaction,
        /* Perform deletes now that updates are safely completed */
        for (i = 0; i < n; i++) {
                struct ref_update *update = updates[i];
+               int flags = update->flags;
 
-               if (update->lock) {
+               if ((flags & REF_HAVE_NEW) && is_null_sha1(update->new_sha1)) {
                        if (delete_ref_loose(update->lock, update->type, err)) {
                                ret = TRANSACTION_GENERIC_ERROR;
                                goto cleanup;
                        }
 
-                       if (!(update->flags & REF_ISPRUNING))
+                       if (!(flags & REF_ISPRUNING))
                                string_list_append(&refs_to_delete,
                                                   update->lock->ref_name);
                }