Commit 01d678a2 authored by Junio C Hamano's avatar Junio C Hamano

Merge branch 'rs/ref-transaction-1'

The second batch of the transactional ref update series.

* rs/ref-transaction-1: (22 commits)
  update-ref --stdin: pass transaction around explicitly
  update-ref --stdin: narrow scope of err strbuf
  refs.c: make delete_ref use a transaction
  refs.c: make prune_ref use a transaction to delete the ref
  refs.c: remove lock_ref_sha1
  refs.c: remove the update_ref_write function
  refs.c: remove the update_ref_lock function
  refs.c: make lock_ref_sha1 static
  walker.c: use ref transaction for ref updates
  fast-import.c: use a ref transaction when dumping tags
  receive-pack.c: use a reference transaction for updating the refs
  refs.c: change update_ref to use a transaction
  branch.c: use ref transaction for all ref updates
  fast-import.c: change update_branch to use ref transactions
  sequencer.c: use ref transactions for all ref updates
  commit.c: use ref transactions for updates
  replace.c: use the ref transaction functions for updates
  tag.c: use ref transactions when doing updates
  refs.c: add transaction.status and track OPEN/CLOSED
  refs.c: make ref_transaction_begin take an err argument
  ...
parents 5e1dc488 88499b29
......@@ -210,7 +210,6 @@ void create_branch(const char *head,
int force, int reflog, int clobber_head,
int quiet, enum branch_track track)
{
struct ref_lock *lock = NULL;
struct commit *commit;
unsigned char sha1[20];
char *real_ref, msg[PATH_MAX + 20];
......@@ -269,15 +268,6 @@ void create_branch(const char *head,
die(_("Not a valid branch point: '%s'."), start_name);
hashcpy(sha1, commit->object.sha1);
if (!dont_change_ref) {
lock = lock_any_ref_for_update(ref.buf, NULL, 0, NULL);
if (!lock)
die_errno(_("Failed to lock ref for update"));
}
if (reflog)
log_all_ref_updates = 1;
if (forcing)
snprintf(msg, sizeof msg, "branch: Reset to %s",
start_name);
......@@ -285,13 +275,26 @@ void create_branch(const char *head,
snprintf(msg, sizeof msg, "branch: Created from %s",
start_name);
if (reflog)
log_all_ref_updates = 1;
if (!dont_change_ref) {
struct ref_transaction *transaction;
struct strbuf err = STRBUF_INIT;
transaction = ref_transaction_begin(&err);
if (!transaction ||
ref_transaction_update(transaction, ref.buf, sha1,
null_sha1, 0, !forcing, &err) ||
ref_transaction_commit(transaction, msg, &err))
die("%s", err.buf);
ref_transaction_free(transaction);
strbuf_release(&err);
}
if (real_ref && track)
setup_tracking(ref.buf + 11, real_ref, track, quiet);
if (!dont_change_ref)
if (write_ref_sha1(lock, sha1, msg) < 0)
die_errno(_("Failed to write ref"));
strbuf_release(&ref);
free(real_ref);
}
......
......@@ -1651,11 +1651,12 @@ int cmd_commit(int argc, const char **argv, const char *prefix)
const char *index_file, *reflog_msg;
char *nl;
unsigned char sha1[20];
struct ref_lock *ref_lock;
struct commit_list *parents = NULL, **pptr = &parents;
struct stat statbuf;
struct commit *current_head = NULL;
struct commit_extra_header *extra = NULL;
struct ref_transaction *transaction;
struct strbuf err = STRBUF_INIT;
if (argc == 2 && !strcmp(argv[1], "-h"))
usage_with_options(builtin_commit_usage, builtin_commit_options);
......@@ -1777,16 +1778,6 @@ int cmd_commit(int argc, const char **argv, const char *prefix)
strbuf_release(&author_ident);
free_commit_extra_headers(extra);
ref_lock = lock_any_ref_for_update("HEAD",
!current_head
? NULL
: current_head->object.sha1,
0, NULL);
if (!ref_lock) {
rollback_index_files();
die(_("cannot lock HEAD ref"));
}
nl = strchr(sb.buf, '\n');
if (nl)
strbuf_setlen(&sb, nl + 1 - sb.buf);
......@@ -1795,10 +1786,17 @@ int cmd_commit(int argc, const char **argv, const char *prefix)
strbuf_insert(&sb, 0, reflog_msg, strlen(reflog_msg));
strbuf_insert(&sb, strlen(reflog_msg), ": ", 2);
if (write_ref_sha1(ref_lock, sha1, sb.buf) < 0) {
transaction = ref_transaction_begin(&err);
if (!transaction ||
ref_transaction_update(transaction, "HEAD", sha1,
current_head
? current_head->object.sha1 : NULL,
0, !!current_head, &err) ||
ref_transaction_commit(transaction, sb.buf, &err)) {
rollback_index_files();
die(_("cannot update HEAD ref"));
die("%s", err.buf);
}
ref_transaction_free(transaction);
unlink(git_path("CHERRY_PICK_HEAD"));
unlink(git_path("REVERT_HEAD"));
......@@ -1827,5 +1825,6 @@ int cmd_commit(int argc, const char **argv, const char *prefix)
if (!quiet)
print_summary(prefix, sha1, !current_head);
strbuf_release(&err);
return 0;
}
......@@ -473,7 +473,6 @@ static const char *update(struct command *cmd, struct shallow_info *si)
const char *namespaced_name;
unsigned char *old_sha1 = cmd->old_sha1;
unsigned char *new_sha1 = cmd->new_sha1;
struct ref_lock *lock;
/* only refs/... are allowed */
if (!starts_with(name, "refs/") || check_refname_format(name + 5, 0)) {
......@@ -574,19 +573,27 @@ static const char *update(struct command *cmd, struct shallow_info *si)
return NULL; /* good */
}
else {
struct strbuf err = STRBUF_INIT;
struct ref_transaction *transaction;
if (shallow_update && si->shallow_ref[cmd->index] &&
update_shallow_ref(cmd, si))
return "shallow error";
lock = lock_any_ref_for_update(namespaced_name, old_sha1,
0, NULL);
if (!lock) {
rp_error("failed to lock %s", name);
return "failed to lock";
}
if (write_ref_sha1(lock, new_sha1, "push")) {
return "failed to write"; /* error() already called */
transaction = ref_transaction_begin(&err);
if (!transaction ||
ref_transaction_update(transaction, namespaced_name,
new_sha1, old_sha1, 0, 1, &err) ||
ref_transaction_commit(transaction, "push", &err)) {
ref_transaction_free(transaction);
rp_error("%s", err.buf);
strbuf_release(&err);
return "failed to update ref";
}
ref_transaction_free(transaction);
strbuf_release(&err);
return NULL; /* good */
}
}
......
......@@ -155,7 +155,8 @@ static int replace_object_sha1(const char *object_ref,
unsigned char prev[20];
enum object_type obj_type, repl_type;
char ref[PATH_MAX];
struct ref_lock *lock;
struct ref_transaction *transaction;
struct strbuf err = STRBUF_INIT;
obj_type = sha1_object_info(object, NULL);
repl_type = sha1_object_info(repl, NULL);
......@@ -168,12 +169,13 @@ static int replace_object_sha1(const char *object_ref,
check_ref_valid(object, prev, ref, sizeof(ref), force);
lock = lock_any_ref_for_update(ref, prev, 0, NULL);
if (!lock)
die("%s: cannot lock the ref", ref);
if (write_ref_sha1(lock, repl, NULL) < 0)
die("%s: cannot update the ref", ref);
transaction = ref_transaction_begin(&err);
if (!transaction ||
ref_transaction_update(transaction, ref, repl, prev, 0, 1, &err) ||
ref_transaction_commit(transaction, NULL, &err))
die("%s", err.buf);
ref_transaction_free(transaction);
return 0;
}
......
......@@ -576,7 +576,6 @@ int cmd_tag(int argc, const char **argv, const char *prefix)
struct strbuf ref = STRBUF_INIT;
unsigned char object[20], prev[20];
const char *object_ref, *tag;
struct ref_lock *lock;
struct create_tag_options opt;
char *cleanup_arg = NULL;
int annotate = 0, force = 0, lines = -1;
......@@ -584,6 +583,8 @@ int cmd_tag(int argc, const char **argv, const char *prefix)
const char *msgfile = NULL, *keyid = NULL;
struct msg_arg msg = { 0, STRBUF_INIT };
struct commit_list *with_commit = NULL;
struct ref_transaction *transaction;
struct strbuf err = STRBUF_INIT;
struct option options[] = {
OPT_CMDMODE('l', "list", &cmdmode, N_("list tag names"), 'l'),
{ OPTION_INTEGER, 'n', NULL, &lines, N_("n"),
......@@ -729,14 +730,17 @@ int cmd_tag(int argc, const char **argv, const char *prefix)
if (annotate)
create_tag(object, tag, &buf, &opt, prev, object);
lock = lock_any_ref_for_update(ref.buf, prev, 0, NULL);
if (!lock)
die(_("%s: cannot lock the ref"), ref.buf);
if (write_ref_sha1(lock, object, NULL) < 0)
die(_("%s: cannot update the ref"), ref.buf);
transaction = ref_transaction_begin(&err);
if (!transaction ||
ref_transaction_update(transaction, ref.buf, object, prev,
0, 1, &err) ||
ref_transaction_commit(transaction, NULL, &err))
die("%s", err.buf);
ref_transaction_free(transaction);
if (force && !is_null_sha1(prev) && hashcmp(prev, object))
printf(_("Updated tag '%s' (was %s)\n"), tag, find_unique_abbrev(prev, DEFAULT_ABBREV));
strbuf_release(&err);
strbuf_release(&buf);
strbuf_release(&ref);
return 0;
......
......@@ -12,11 +12,8 @@ static const char * const git_update_ref_usage[] = {
NULL
};
static struct ref_transaction *transaction;
static char line_termination = '\n';
static int update_flags;
static struct strbuf err = STRBUF_INIT;
/*
* Parse one whitespace- or NUL-terminated, possibly C-quoted argument
......@@ -177,8 +174,10 @@ static int parse_next_sha1(struct strbuf *input, const char **next,
* depending on how line_termination is set.
*/
static const char *parse_cmd_update(struct strbuf *input, const char *next)
static const char *parse_cmd_update(struct ref_transaction *transaction,
struct strbuf *input, const char *next)
{
struct strbuf err = STRBUF_INIT;
char *refname;
unsigned char new_sha1[20];
unsigned char old_sha1[20];
......@@ -204,12 +203,15 @@ static const char *parse_cmd_update(struct strbuf *input, const char *next)
update_flags = 0;
free(refname);
strbuf_release(&err);
return next;
}
static const char *parse_cmd_create(struct strbuf *input, const char *next)
static const char *parse_cmd_create(struct ref_transaction *transaction,
struct strbuf *input, const char *next)
{
struct strbuf err = STRBUF_INIT;
char *refname;
unsigned char new_sha1[20];
......@@ -226,16 +228,21 @@ static const char *parse_cmd_create(struct strbuf *input, const char *next)
if (*next != line_termination)
die("create %s: extra input: %s", refname, next);
ref_transaction_create(transaction, refname, new_sha1, update_flags);
if (ref_transaction_create(transaction, refname, new_sha1,
update_flags, &err))
die("%s", err.buf);
update_flags = 0;
free(refname);
strbuf_release(&err);
return next;
}
static const char *parse_cmd_delete(struct strbuf *input, const char *next)
static const char *parse_cmd_delete(struct ref_transaction *transaction,
struct strbuf *input, const char *next)
{
struct strbuf err = STRBUF_INIT;
char *refname;
unsigned char old_sha1[20];
int have_old;
......@@ -256,17 +263,21 @@ static const char *parse_cmd_delete(struct strbuf *input, const char *next)
if (*next != line_termination)
die("delete %s: extra input: %s", refname, next);
ref_transaction_delete(transaction, refname, old_sha1,
update_flags, have_old);
if (ref_transaction_delete(transaction, refname, old_sha1,
update_flags, have_old, &err))
die("%s", err.buf);
update_flags = 0;
free(refname);
strbuf_release(&err);
return next;
}
static const char *parse_cmd_verify(struct strbuf *input, const char *next)
static const char *parse_cmd_verify(struct ref_transaction *transaction,
struct strbuf *input, const char *next)
{
struct strbuf err = STRBUF_INIT;
char *refname;
unsigned char new_sha1[20];
unsigned char old_sha1[20];
......@@ -294,6 +305,7 @@ static const char *parse_cmd_verify(struct strbuf *input, const char *next)
update_flags = 0;
free(refname);
strbuf_release(&err);
return next;
}
......@@ -307,7 +319,7 @@ static const char *parse_cmd_option(struct strbuf *input, const char *next)
return next + 8;
}
static void update_refs_stdin(void)
static void update_refs_stdin(struct ref_transaction *transaction)
{
struct strbuf input = STRBUF_INIT;
const char *next;
......@@ -322,13 +334,13 @@ static void update_refs_stdin(void)
else if (isspace(*next))
die("whitespace before command: %s", next);
else if (starts_with(next, "update "))
next = parse_cmd_update(&input, next + 7);
next = parse_cmd_update(transaction, &input, next + 7);
else if (starts_with(next, "create "))
next = parse_cmd_create(&input, next + 7);
next = parse_cmd_create(transaction, &input, next + 7);
else if (starts_with(next, "delete "))
next = parse_cmd_delete(&input, next + 7);
next = parse_cmd_delete(transaction, &input, next + 7);
else if (starts_with(next, "verify "))
next = parse_cmd_verify(&input, next + 7);
next = parse_cmd_verify(transaction, &input, next + 7);
else if (starts_with(next, "option "))
next = parse_cmd_option(&input, next + 7);
else
......@@ -362,15 +374,21 @@ int cmd_update_ref(int argc, const char **argv, const char *prefix)
die("Refusing to perform update with empty message.");
if (read_stdin) {
transaction = ref_transaction_begin();
struct strbuf err = STRBUF_INIT;
struct ref_transaction *transaction;
transaction = ref_transaction_begin(&err);
if (!transaction)
die("%s", err.buf);
if (delete || no_deref || argc > 0)
usage_with_options(git_update_ref_usage, options);
if (end_null)
line_termination = '\0';
update_refs_stdin();
update_refs_stdin(transaction);
if (ref_transaction_commit(transaction, msg, &err))
die("%s", err.buf);
ref_transaction_free(transaction);
strbuf_release(&err);
return 0;
}
......
......@@ -1679,8 +1679,9 @@ static int tree_content_get(
static int update_branch(struct branch *b)
{
static const char *msg = "fast-import";
struct ref_lock *lock;
struct ref_transaction *transaction;
unsigned char old_sha1[20];
struct strbuf err = STRBUF_INIT;
if (read_ref(b->name, old_sha1))
hashclr(old_sha1);
......@@ -1689,29 +1690,33 @@ static int update_branch(struct branch *b)
delete_ref(b->name, old_sha1, 0);
return 0;
}
lock = lock_any_ref_for_update(b->name, old_sha1, 0, NULL);
if (!lock)
return error("Unable to lock %s", b->name);
if (!force_update && !is_null_sha1(old_sha1)) {
struct commit *old_cmit, *new_cmit;
old_cmit = lookup_commit_reference_gently(old_sha1, 0);
new_cmit = lookup_commit_reference_gently(b->sha1, 0);
if (!old_cmit || !new_cmit) {
unlock_ref(lock);
if (!old_cmit || !new_cmit)
return error("Branch %s is missing commits.", b->name);
}
if (!in_merge_bases(old_cmit, new_cmit)) {
unlock_ref(lock);
warning("Not updating %s"
" (new tip %s does not contain %s)",
b->name, sha1_to_hex(b->sha1), sha1_to_hex(old_sha1));
return -1;
}
}
if (write_ref_sha1(lock, b->sha1, msg) < 0)
return error("Unable to update %s", b->name);
transaction = ref_transaction_begin(&err);
if (!transaction ||
ref_transaction_update(transaction, b->name, b->sha1, old_sha1,
0, 1, &err) ||
ref_transaction_commit(transaction, msg, &err)) {
ref_transaction_free(transaction);
error("%s", err.buf);
strbuf_release(&err);
return -1;
}
ref_transaction_free(transaction);
strbuf_release(&err);
return 0;
}
......@@ -1730,15 +1735,32 @@ static void dump_tags(void)
{
static const char *msg = "fast-import";
struct tag *t;
struct ref_lock *lock;
char ref_name[PATH_MAX];
struct strbuf ref_name = STRBUF_INIT;
struct strbuf err = STRBUF_INIT;
struct ref_transaction *transaction;
transaction = ref_transaction_begin(&err);
if (!transaction) {
failure |= error("%s", err.buf);
goto cleanup;
}
for (t = first_tag; t; t = t->next_tag) {
sprintf(ref_name, "tags/%s", t->name);
lock = lock_ref_sha1(ref_name, NULL);
if (!lock || write_ref_sha1(lock, t->sha1, msg) < 0)
failure |= error("Unable to update %s", ref_name);
strbuf_reset(&ref_name);
strbuf_addf(&ref_name, "refs/tags/%s", t->name);
if (ref_transaction_update(transaction, ref_name.buf, t->sha1,
NULL, 0, 0, &err)) {
failure |= error("%s", err.buf);
goto cleanup;
}
}
if (ref_transaction_commit(transaction, msg, &err))
failure |= error("%s", err.buf);
cleanup:
ref_transaction_free(transaction);
strbuf_release(&ref_name);
strbuf_release(&err);
}
static void dump_marks_helper(FILE *f,
......
This diff is collapsed.
......@@ -10,6 +10,38 @@ struct ref_lock {
int force_write;
};
/*
* A ref_transaction represents a collection of ref updates
* that should succeed or fail together.
*
* Calling sequence
* ----------------
* - Allocate and initialize a `struct ref_transaction` by calling
* `ref_transaction_begin()`.
*
* - List intended ref updates by calling functions like
* `ref_transaction_update()` and `ref_transaction_create()`.
*
* - Call `ref_transaction_commit()` to execute the transaction.
* If this succeeds, the ref updates will have taken place and
* the transaction cannot be rolled back.
*
* - At any time call `ref_transaction_free()` to discard the
* transaction and free associated resources. In particular,
* this rolls back the transaction if it has not been
* successfully committed.
*
* Error handling
* --------------
*
* On error, transaction functions append a message about what
* went wrong to the 'err' argument. The message mentions what
* ref was being updated (if any) when the error occurred so it
* can be passed to 'die' or 'error' as-is.
*
* The message is appended to err without first clearing err.
* err will not be '\n' terminated.
*/
struct ref_transaction;
/*
......@@ -141,14 +173,17 @@ extern int is_branch(const char *refname);
extern int peel_ref(const char *refname, unsigned char *sha1);
/*
* Locks a "refs/" ref returning the lock on success and NULL on failure.
* On failure errno is set to something meaningful.
* Flags controlling lock_any_ref_for_update(), ref_transaction_update(),
* ref_transaction_create(), etc.
* REF_NODEREF: act on the ref directly, instead of dereferencing
* symbolic references.
*
* Flags >= 0x100 are reserved for internal use.
*/
extern struct ref_lock *lock_ref_sha1(const char *refname, const unsigned char *old_sha1);
/** Locks any ref (for 'HEAD' type refs). */
#define REF_NODEREF 0x01
/* errno is set to something meaningful on failure */
/*
* This function sets errno to something meaningful on failure.
*/
extern struct ref_lock *lock_any_ref_for_update(const char *refname,
const unsigned char *old_sha1,
int flags, int *type_p);
......@@ -232,7 +267,7 @@ enum action_on_err {
* Begin a reference transaction. The reference transaction must
* be freed by calling ref_transaction_free().
*/
struct ref_transaction *ref_transaction_begin(void);
struct ref_transaction *ref_transaction_begin(struct strbuf *err);
/*
* The following functions add a reference check or update to a
......@@ -250,7 +285,7 @@ struct ref_transaction *ref_transaction_begin(void);
* 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. On failure the err buffer will be updated.
* rolled back.
*/
int ref_transaction_update(struct ref_transaction *transaction,
const char *refname,
......@@ -264,28 +299,34 @@ 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.
*/
void ref_transaction_create(struct ref_transaction *transaction,
const char *refname,
const unsigned char *new_sha1,
int flags);
int ref_transaction_create(struct ref_transaction *transaction,
const char *refname,
const unsigned char *new_sha1,
int flags,
struct strbuf *err);
/*
* 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.
*/
void ref_transaction_delete(struct ref_transaction *transaction,
const char *refname,
const unsigned char *old_sha1,
int flags, int have_old);
int ref_transaction_delete(struct ref_transaction *transaction,
const char *refname,
const unsigned char *old_sha1,
int flags, int have_old,
struct strbuf *err);
/*
* 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. The string does not end in newline.
*/
int ref_transaction_commit(struct ref_transaction *transaction,
const char *msg, struct strbuf *err);
......
......@@ -237,23 +237,33 @@ static int error_dirty_index(struct replay_opts *opts)
static int fast_forward_to(const unsigned char *to, const unsigned char *from,
int unborn, struct replay_opts *opts)
{
struct ref_lock *ref_lock;
struct ref_transaction *transaction;
struct strbuf sb = STRBUF_INIT;
int ret;
struct strbuf err = STRBUF_INIT;
read_cache();
if (checkout_fast_forward(from, to, 1))
exit(128); /* the callee should have complained already */
ref_lock = lock_any_ref_for_update("HEAD", unborn ? null_sha1 : from,
0, NULL);
if (!ref_lock)
return error(_("Failed to lock HEAD during fast_forward_to"));
strbuf_addf(&sb, "%s: fast-forward", action_name(opts));
ret = write_ref_sha1(ref_lock, to, sb.buf);
transaction = ref_transaction_begin(&err);
if (!transaction ||
ref_transaction_update(transaction, "HEAD",
to, unborn ? null_sha1 : from,
0, 1, &err) ||
ref_transaction_commit(transaction, sb.buf, &err)) {
ref_transaction_free(transaction);
error("%s", err.buf);
strbuf_release(&sb);
strbuf_release(&err);
return -1;
}
strbuf_release(&sb);
return ret;
strbuf_release(&err);
ref_transaction_free(transaction);
return 0;
}
static int do_recursive_merge(struct commit *base, struct commit *next,
......
......@@ -251,64 +251,73 @@ void walker_targets_free(int targets, char **target, const char **write_ref)
int walker_fetch(struct walker *walker, int targets, char **target,
const char **write_ref, const char *write_ref_log_details)
{
struct ref_lock **lock = xcalloc(targets, sizeof(struct ref_lock *));
struct strbuf refname = STRBUF_INIT;
struct strbuf err = STRBUF_INIT;
struct ref_transaction *transaction = NULL;
unsigned char *sha1 = xmalloc(targets * 20);
const char *msg;
char *to_free = NULL;
int ret;
int i;
char *msg = NULL;
int i, ret = -1;
save_commit_buffer = 0;
for (i = 0; i < targets; i++) {
if (!write_ref || !write_ref[i])
continue;
lock[i] = lock_ref_sha1(write_ref[i], NULL);
if (!lock[i]) {
error("Can't lock ref %s", write_ref[i]);
goto unlock_and_fail;
if (write_ref) {
transaction = ref_transaction_begin(&err);
if (!transaction) {
error("%s", err.buf);
goto done;
}
}
if (!walker->get_recover)
for_each_ref(mark_complete, NULL);
for (i = 0; i < targets; i++) {
if (interpret_target(walker, target[i], &sha1[20 * i])) {
error("Could not interpret response from server '%s' as something to pull", target[i]);
goto unlock_and_fail;
goto done;
}
if (process(walker, lookup_unknown_object(&sha1[20 * i])))
goto unlock_and_fail;
goto done;
}
if (loop(walker))
goto unlock_and_fail;
if (write_ref_log_details)
msg = to_free = xstrfmt("fetch from %s", write_ref_log_details);
else
msg = "fetch (unknown)";
goto done;
if (!write_ref) {
ret = 0;
goto done;
}
if (write_ref_log_details) {
msg = xstrfmt("fetch from %s", write_ref_log_details);
} else {
msg = NULL;
}
for (i = 0; i < targets; i++) {
if (!write_ref || !write_ref[i])
if (!write_ref[i])
continue;
ret = write_ref_sha1(lock[i], &sha1[20 * i], msg);
lock[i] = NULL;
if (ret)
goto unlock_and_fail;
strbuf_reset(&refname);
strbuf_addf(&refname, "refs/%s", write_ref[i]);
if (ref_transaction_update(transaction, refname.buf,
&sha1[20 * i], NULL, 0, 0,
&err)) {
error("%s", err.buf);
goto done;
}
}
if (ref_transaction_commit(transaction,
msg ? msg : "fetch (unknown)",
&err)) {
error("%s", err.buf);
goto done;
}
free(to_free);
return 0;
unlock_and_fail:
for (i = 0; i < targets; i++)
if (lock[i])
unlock_ref(lock[i]);
free(to_free);
ret = 0;
return -1;
done:
ref_transaction_free(transaction);