initial_ref_transaction_commit(): function for initial ref creation

"git clone" uses shortcuts when creating the initial set of references: * It writes them directly to packed-refs. * It doesn't lock the individual references (though it does lock the packed-refs file). * It doesn't check for refname conflicts between two new references or between one new reference and any hypothetical old ones. * It doesn't create reflog entries for the reference creations. This functionality was implemented in builtin/clone.c. But really that file shouldn't have such intimate knowledge of how references are stored. So provide a new function in the refs API, initial_ref_transaction_commit(), which can be used for initial reference creation. The new function is based on the ref_transaction interface. This means that we can make some other functions private to the refs module. That will be done in a followup commit. It would seem to make sense to add a test here that there are no existing references, because that is how the function *should* be used. But in fact, the "testgit" remote helper appears to call it *after* having set up refs/remotes/<name>/HEAD and refs/remotes/<name>/master, so we can't be so strict. For now, the function trusts its caller to only call it when it makes sense. Future commits will add some more limited sanity checks. Signed-off-by: Michael Haggerty <mhagger@alum.mit.edu> Signed-off-by: Junio C Hamano <gitster@pobox.com>

Michael Haggerty committed Jun 22, 2015 at 16:03 UTC 58f233ce1ed67bbc31a429fde5c65d5050fdbd7d
3 files changed +75 -4
builtin/clone.c
+14 -4
@@ -491,16 +491,26 @@ static void write_remote_refs(const struct ref *local_refs)
491 {
492 const struct ref *r;
493
494 - lock_packed_refs(LOCK_DIE_ON_ERROR);
494 + struct ref_transaction *t;
495 + struct strbuf err = STRBUF_INIT;
496 +
497 + t = ref_transaction_begin(&err);
498 + if (!t)
499 + die("%s", err.buf);
500
501 for (r = local_refs; r; r = r->next) {
502 if (!r->peer_ref)
503 continue;
499 - add_packed_ref(r->peer_ref->name, r->old_sha1);
504 + if (ref_transaction_create(t, r->peer_ref->name, r->old_sha1,
505 + 0, NULL, &err))
506 + die("%s", err.buf);
507 }
508
502 - if (commit_packed_refs())
503 - die_errno("unable to overwrite old ref-pack file");
509 + if (initial_ref_transaction_commit(t, &err))
510 + die("%s", err.buf);
511 +
512 + strbuf_release(&err);
513 + ref_transaction_free(t);
514 }
515
516 static void write_followtags(const struct ref *refs, const char *msg)
refs.c
+47
@@ -4076,6 +4076,53 @@ cleanup:
4076 return ret;
4077 }
4078
4079 +int initial_ref_transaction_commit(struct ref_transaction *transaction,
4080 + struct strbuf *err)
4081 +{
4082 + int ret = 0, i;
4083 + int n = transaction->nr;
4084 + struct ref_update **updates = transaction->updates;
4085 +
4086 + assert(err);
4087 +
4088 + if (transaction->state != REF_TRANSACTION_OPEN)
4089 + die("BUG: commit called for transaction that is not open");
4090 +
4091 + for (i = 0; i < n; i++) {
4092 + struct ref_update *update = updates[i];
4093 +
4094 + if ((update->flags & REF_HAVE_OLD) &&
4095 + !is_null_sha1(update->old_sha1))
4096 + die("BUG: initial ref transaction with old_sha1 set");
4097 + }
4098 +
4099 + if (lock_packed_refs(0)) {
4100 + strbuf_addf(err, "unable to lock packed-refs file: %s",
4101 + strerror(errno));
4102 + ret = TRANSACTION_GENERIC_ERROR;
4103 + goto cleanup;
4104 + }
4105 +
4106 + for (i = 0; i < n; i++) {
4107 + struct ref_update *update = updates[i];
4108 +
4109 + if ((update->flags & REF_HAVE_NEW) &&
4110 + !is_null_sha1(update->new_sha1))
4111 + add_packed_ref(update->refname, update->new_sha1);
4112 + }
4113 +
4114 + if (commit_packed_refs()) {
4115 + strbuf_addf(err, "unable to commit packed-refs file: %s",
4116 + strerror(errno));
4117 + ret = TRANSACTION_GENERIC_ERROR;
4118 + goto cleanup;
4119 + }
4120 +
4121 +cleanup:
4122 + transaction->state = REF_TRANSACTION_CLOSED;
4123 + return ret;
4124 +}
4125 +
4126 char *shorten_unambiguous_ref(const char *refname, int strict)
4127 {
4128 int i;
refs.h
+14
@@ -365,6 +365,20 @@ int ref_transaction_verify(struct ref_transaction *transaction,
365 int ref_transaction_commit(struct ref_transaction *transaction,
366 struct strbuf *err);
367
368 +/*
369 + * Like ref_transaction_commit(), but optimized for creating
370 + * references when originally initializing a repository (e.g., by "git
371 + * clone"). It writes the new references directly to packed-refs
372 + * without locking the individual references.
373 + *
374 + * It is a bug to call this function when there might be other
375 + * processes accessing the repository or if there are existing
376 + * references that might conflict with the ones being created. All
377 + * old_sha1 values must either be absent or NULL_SHA1.
378 + */
379 +int initial_ref_transaction_commit(struct ref_transaction *transaction,
380 + struct strbuf *err);
381 +
382 /*
383 * Free an existing transaction and all associated data.
384 */