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 [email protected]
More majordomo info at http://vger.kernel.org/majordomo-info.html