Ronnie Sahlberg wrote:

> This patch series is based on next and expands on the transaction API.

Thanks.  Will pick up in v8 where I left off with v6.

Applies with just one minor conflict on top of a merge of
mh/ref-transaction, rs/ref-update-check-errors-early, and
rs/reflog-exists.  Here's an interdiff against version 6 for those
following along.

> Version 8:
>  - Updates after review by JN
>  - Improve commit messages
>  - Add a patch that adds an err argument to repack_without_refs
>  - Add a patch that adds an err argument to delete_loose_ref
>  - Better document that a _update/_delete/_create failure means the whole
>    transaction has failed and needs rollback.
>
> Version 7:
>  - Updated commit messages per JNs review comments.
>  - Changed REF_ISPRUNING and REF_ISPACKONLY to be private flags and not
>    exposed through refs.h

diff --git a/builtin/commit.c b/builtin/commit.c
index 0f4e1fc..07ccc97 100644
--- a/builtin/commit.c
+++ b/builtin/commit.c
@@ -1684,7 +1684,7 @@ int cmd_commit(int argc, const char **argv, const char 
*prefix)
                                   0, !!current_head, sb.buf) ||
            ref_transaction_commit(transaction, &err)) {
                rollback_index_files();
-               die(_("HEAD: cannot update ref: %s"), err.buf);
+               die("%s", err.buf);
        }
        ref_transaction_free(transaction);
 
diff --git a/builtin/replace.c b/builtin/replace.c
index 47c360c..952b589 100644
--- a/builtin/replace.c
+++ b/builtin/replace.c
@@ -163,7 +163,7 @@ static int replace_object(const char *object_ref, const 
char *replace_ref,
            ref_transaction_update(transaction, ref, repl, prev,
                                   0, !is_null_sha1(prev), NULL) ||
            ref_transaction_commit(transaction, &err))
-               die(_("%s: failed to replace ref: %s"), ref, err.buf);
+               die("%s: failed to replace ref: %s", ref, err.buf);
 
        ref_transaction_free(transaction);
        return 0;
diff --git a/builtin/update-ref.c b/builtin/update-ref.c
index c5aff92..bd7e96f 100644
--- a/builtin/update-ref.c
+++ b/builtin/update-ref.c
@@ -228,7 +228,7 @@ static const char *parse_cmd_create(struct strbuf *input, 
const char *next)
 
        if (ref_transaction_create(transaction, refname, new_sha1,
                                   update_flags, msg))
-               die("failed transaction create for %s", refname);
+               die("cannot create ref '%s'", refname);
 
        update_flags = 0;
        free(refname);
diff --git a/refs.c b/refs.c
index 302a2b3..ed93b75 100644
--- a/refs.c
+++ b/refs.c
@@ -29,6 +29,15 @@ static inline int bad_ref_char(int ch)
        return 0;
 }
 
+/** Used as a flag to ref_transaction_delete when a loose ref is beeing
+ *  pruned.
+ */
+#define REF_ISPRUNING  0x0100
+/** Deletion of a ref that only exists as a packed ref in which case we do not
+ *  need to lock the loose ref during the transaction.
+ */
+#define REF_ISPACKONLY 0x0200
+
 /*
  * Try to read one refname component from the front of refname.  Return
  * the length of the component found, or -1 if the component is not
@@ -2447,12 +2456,12 @@ static int curate_packed_ref_fn(struct ref_entry 
*entry, void *cb_data)
        return 0;
 }
 
-static int repack_without_refs(const char **refnames, int n)
+static int repack_without_refs(const char **refnames, int n, struct strbuf 
*err)
 {
        struct ref_dir *packed;
        struct string_list refs_to_delete = STRING_LIST_INIT_DUP;
        struct string_list_item *ref_to_delete;
-       int i, removed = 0;
+       int i, ret, removed = 0;
 
        /* Look for a packed ref */
        for (i = 0; i < n; i++)
@@ -2465,6 +2474,9 @@ static int repack_without_refs(const char **refnames, int 
n)
 
        if (lock_packed_refs(0)) {
                unable_to_lock_error(git_path("packed-refs"), errno);
+               if (err)
+                       strbuf_addf(err, "cannot delete '%s' from packed refs",
+                                   refnames[i]);
                return error("cannot delete '%s' from packed refs", 
refnames[i]);
        }
        packed = get_packed_refs(&ref_cache);
@@ -2490,20 +2502,28 @@ static int repack_without_refs(const char **refnames, 
int n)
        }
 
        /* Write what remains */
-       return commit_packed_refs();
+       ret = commit_packed_refs();
+       if (ret && err)
+               strbuf_addf(err, "unable to overwrite old ref-pack file");
+       return ret;
 }
 
-static int delete_ref_loose(struct ref_lock *lock, int flag)
+static int delete_ref_loose(struct ref_lock *lock, int flag, struct strbuf 
*err)
 {
        if (!(flag & REF_ISPACKED) || flag & REF_ISSYMREF) {
                /* loose */
-               int err, i = strlen(lock->lk->filename) - 5; /* .lock */
+               int res, i = strlen(lock->lk->filename) - 5; /* .lock */
 
                lock->lk->filename[i] = 0;
-               err = unlink_or_warn(lock->lk->filename);
+               res = unlink_or_warn(lock->lk->filename);
                lock->lk->filename[i] = '.';
-               if (err && errno != ENOENT)
+               if (res && errno != ENOENT) {
+                       if (err)
+                               strbuf_addf(err,
+                                           "failed to delete loose ref '%s'",
+                                           lock->lk->filename);
                        return 1;
+               }
        }
        return 0;
 }
@@ -3483,7 +3503,7 @@ int ref_transaction_commit(struct ref_transaction 
*transaction,
                                                   delnames, delnum);
                if (!update->lock) {
                        if (err)
-                               strbuf_addf(err ,"Cannot lock the ref '%s'.",
+                               strbuf_addf(err, "Cannot lock the ref '%s'.",
                                            update->refname);
                        ret = 1;
                        goto cleanup;
@@ -3516,13 +3536,14 @@ int ref_transaction_commit(struct ref_transaction 
*transaction,
                        continue;
 
                if (update->lock) {
-                       ret |= delete_ref_loose(update->lock, update->type);
+                       ret |= delete_ref_loose(update->lock, update->type,
+                                               err);
                        if (!(update->flags & REF_ISPRUNING))
                                delnames[delnum++] = update->lock->ref_name;
                }
        }
 
-       ret |= repack_without_refs(delnames, delnum);
+       ret |= repack_without_refs(delnames, delnum, err);
        for (i = 0; i < delnum; i++)
                unlink_or_warn(git_path("logs/%s", delnames[i]));
        clear_loose_ref_cache(&ref_cache);
diff --git a/refs.h b/refs.h
index 03b4a7e..0e6d416 100644
--- a/refs.h
+++ b/refs.h
@@ -134,10 +134,6 @@ extern int peel_ref(const char *refname, unsigned char 
*sha1);
 
 /** Locks any ref (for 'HEAD' type refs). */
 #define REF_NODEREF    0x01
-/** Deleting a loose ref during prune */
-#define REF_ISPRUNING  0x02
-/** Deletion of a ref that only exists as a packed ref */
-#define REF_ISPACKONLY 0x04
 extern struct ref_lock *lock_any_ref_for_update(const char *refname,
                                                const unsigned char *old_sha1,
                                                int flags, int *type_p);
@@ -240,6 +236,9 @@ void ref_transaction_rollback(struct ref_transaction 
*transaction);
  * be deleted.  If have_old is true, then old_sha1 holds the value
  * that the reference should have had before the update, or zeros if
  * it must not have existed beforehand.
+ * Function returns 0 on success and non-zero on failure. A failure to update
+ * means that the transaction as a whole has failed and will need to be
+ * rolled back.
  */
 int ref_transaction_update(struct ref_transaction *transaction,
                           const char *refname,
@@ -252,6 +251,9 @@ int ref_transaction_update(struct ref_transaction 
*transaction,
  * that the reference should have after the update; it must not be the
  * null SHA-1.  It is verified that the reference does not exist
  * already.
+ * Function returns 0 on success and non-zero on failure. A failure to create
+ * means that the transaction as a whole has failed and will need to be
+ * rolled back.
  */
 int ref_transaction_create(struct ref_transaction *transaction,
                           const char *refname,
@@ -262,6 +264,9 @@ int ref_transaction_create(struct ref_transaction 
*transaction,
  * Add a reference deletion to transaction.  If have_old is true, then
  * old_sha1 holds the value that the reference should have had before
  * the update (which must not be the null SHA-1).
+ * Function returns 0 on success and non-zero on failure. A failure to delete
+ * means that the transaction as a whole has failed and will need to be
+ * rolled back.
  */
 int ref_transaction_delete(struct ref_transaction *transaction,
                           const char *refname,
@@ -272,7 +277,7 @@ int ref_transaction_delete(struct ref_transaction 
*transaction,
  * Commit all of the changes that have been queued in transaction, as
  * atomically as possible.  Return a nonzero value if there is a
  * problem. If err is non-NULL we will add an error string to it to explain
- * why the transaction failed.
+ * why the transaction failed. The string does not end in newline.
  */
 int ref_transaction_commit(struct ref_transaction *transaction,
                           struct strbuf *err);
--
To unsubscribe from this list: send the line "unsubscribe git" in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html

Reply via email to