summaryrefslogtreecommitdiff
path: root/refs.c
diff options
context:
space:
mode:
authorMichael Haggerty <mhagger@alum.mit.edu>2015-02-17 18:00:21 +0100
committerJunio C Hamano <gitster@pobox.com>2015-02-17 11:24:59 -0800
commit16180334015ab44b0310b9d896e554a66c36a1a4 (patch)
tree367a45d10a3186a88121c42d28551650d814be94 /refs.c
parent60294596ba6bf2f63506ffad60b9a94fc04612a1 (diff)
downloadgit-16180334015ab44b0310b9d896e554a66c36a1a4.tar.gz
ref_transaction_verify(): new function to check a reference's value
If NULL is passed to ref_transaction_update()'s new_sha1 parameter, then just verify old_sha1 (under lock) without trying to change the new value of the reference. Use this functionality to add a new function ref_transaction_verify(), which checks the current value of the reference under lock but doesn't change it. Use ref_transaction_verify() in the implementation of "git update-ref --stdin"'s "verify" command to avoid the awkward need to "update" the reference to its existing value. Signed-off-by: Michael Haggerty <mhagger@alum.mit.edu> Reviewed-by: Stefan Beller <sbeller@google.com> Signed-off-by: Junio C Hamano <gitster@pobox.com>
Diffstat (limited to 'refs.c')
-rw-r--r--refs.c47
1 files changed, 39 insertions, 8 deletions
diff --git a/refs.c b/refs.c
index d5bfd11790..1aaba3f7f7 100644
--- a/refs.c
+++ b/refs.c
@@ -47,10 +47,16 @@ 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,6 +3725,19 @@ int ref_transaction_delete(struct ref_transaction *transaction,
flags, msg, err);
}
+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 *action, const char *refname,
const unsigned char *sha1, const unsigned char *oldval,
unsigned int flags, enum action_on_err onerr)
@@ -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);
}