зеркало из https://github.com/microsoft/git.git
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 ...
This commit is contained in:
Коммит
01d678a226
31
branch.c
31
branch.c
|
@ -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 @@ found_entry:
|
|||
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;
|
||||
|
||||
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);
|
||||
transaction = ref_transaction_begin(&err);
|
||||
if (!transaction) {
|
||||
failure |= error("%s", err.buf);
|
||||
goto cleanup;
|
||||
}
|
||||
for (t = first_tag; t; t = t->next_tag) {
|
||||
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,
|
||||
|
|
243
refs.c
243
refs.c
|
@ -24,6 +24,11 @@ static unsigned char refname_disposition[256] = {
|
|||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 3, 0, 0, 4, 4
|
||||
};
|
||||
|
||||
/*
|
||||
* Used as a flag to ref_transaction_delete when a loose ref is being
|
||||
* pruned.
|
||||
*/
|
||||
#define REF_ISPRUNING 0x0100
|
||||
/*
|
||||
* Try to read one refname component from the front of refname.
|
||||
* Return the length of the component found, or -1 if the component is
|
||||
|
@ -2068,7 +2073,10 @@ int dwim_log(const char *str, int len, unsigned char *sha1, char **log)
|
|||
return logs_found;
|
||||
}
|
||||
|
||||
/* This function should make sure errno is meaningful on error */
|
||||
/*
|
||||
* Locks a "refs/" ref returning the lock on success and NULL on failure.
|
||||
* On failure errno is set to something meaningful.
|
||||
*/
|
||||
static struct ref_lock *lock_ref_sha1_basic(const char *refname,
|
||||
const unsigned char *old_sha1,
|
||||
int flags, int *type_p)
|
||||
|
@ -2169,15 +2177,6 @@ static struct ref_lock *lock_ref_sha1_basic(const char *refname,
|
|||
return NULL;
|
||||
}
|
||||
|
||||
struct ref_lock *lock_ref_sha1(const char *refname, const unsigned char *old_sha1)
|
||||
{
|
||||
char refpath[PATH_MAX];
|
||||
if (check_refname_format(refname, 0))
|
||||
return NULL;
|
||||
strcpy(refpath, mkpath("refs/%s", refname));
|
||||
return lock_ref_sha1_basic(refpath, old_sha1, 0, NULL);
|
||||
}
|
||||
|
||||
struct ref_lock *lock_any_ref_for_update(const char *refname,
|
||||
const unsigned char *old_sha1,
|
||||
int flags, int *type_p)
|
||||
|
@ -2387,13 +2386,25 @@ static void try_remove_empty_parents(char *name)
|
|||
/* make sure nobody touched the ref, and unlink */
|
||||
static void prune_ref(struct ref_to_prune *r)
|
||||
{
|
||||
struct ref_lock *lock = lock_ref_sha1(r->name + 5, r->sha1);
|
||||
struct ref_transaction *transaction;
|
||||
struct strbuf err = STRBUF_INIT;
|
||||
|
||||
if (lock) {
|
||||
unlink_or_warn(git_path("%s", r->name));
|
||||
unlock_ref(lock);
|
||||
try_remove_empty_parents(r->name);
|
||||
if (check_refname_format(r->name + 5, 0))
|
||||
return;
|
||||
|
||||
transaction = ref_transaction_begin(&err);
|
||||
if (!transaction ||
|
||||
ref_transaction_delete(transaction, r->name, r->sha1,
|
||||
REF_ISPRUNING, 1, &err) ||
|
||||
ref_transaction_commit(transaction, NULL, &err)) {
|
||||
ref_transaction_free(transaction);
|
||||
error("%s", err.buf);
|
||||
strbuf_release(&err);
|
||||
return;
|
||||
}
|
||||
ref_transaction_free(transaction);
|
||||
strbuf_release(&err);
|
||||
try_remove_empty_parents(r->name);
|
||||
}
|
||||
|
||||
static void prune_refs(struct ref_to_prune *r)
|
||||
|
@ -2536,11 +2547,6 @@ int repack_without_refs(const char **refnames, int n, struct strbuf *err)
|
|||
return ret;
|
||||
}
|
||||
|
||||
static int repack_without_ref(const char *refname)
|
||||
{
|
||||
return repack_without_refs(&refname, 1, NULL);
|
||||
}
|
||||
|
||||
static int delete_ref_loose(struct ref_lock *lock, int flag)
|
||||
{
|
||||
if (!(flag & REF_ISPACKED) || flag & REF_ISSYMREF) {
|
||||
|
@ -2558,24 +2564,22 @@ static int delete_ref_loose(struct ref_lock *lock, int flag)
|
|||
|
||||
int delete_ref(const char *refname, const unsigned char *sha1, int delopt)
|
||||
{
|
||||
struct ref_lock *lock;
|
||||
int ret = 0, flag = 0;
|
||||
struct ref_transaction *transaction;
|
||||
struct strbuf err = STRBUF_INIT;
|
||||
|
||||
lock = lock_ref_sha1_basic(refname, sha1, delopt, &flag);
|
||||
if (!lock)
|
||||
transaction = ref_transaction_begin(&err);
|
||||
if (!transaction ||
|
||||
ref_transaction_delete(transaction, refname, sha1, delopt,
|
||||
sha1 && !is_null_sha1(sha1), &err) ||
|
||||
ref_transaction_commit(transaction, NULL, &err)) {
|
||||
error("%s", err.buf);
|
||||
ref_transaction_free(transaction);
|
||||
strbuf_release(&err);
|
||||
return 1;
|
||||
ret |= delete_ref_loose(lock, flag);
|
||||
|
||||
/* removing the loose one could have resurrected an earlier
|
||||
* packed one. Also, if it was not loose we need to repack
|
||||
* without it.
|
||||
*/
|
||||
ret |= repack_without_ref(lock->ref_name);
|
||||
|
||||
unlink_or_warn(git_path("logs/%s", lock->ref_name));
|
||||
clear_loose_ref_cache(&ref_cache);
|
||||
unlock_ref(lock);
|
||||
return ret;
|
||||
}
|
||||
ref_transaction_free(transaction);
|
||||
strbuf_release(&err);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
|
@ -3332,43 +3336,6 @@ int for_each_reflog(each_ref_fn fn, void *cb_data)
|
|||
return retval;
|
||||
}
|
||||
|
||||
static struct ref_lock *update_ref_lock(const char *refname,
|
||||
const unsigned char *oldval,
|
||||
int flags, int *type_p,
|
||||
enum action_on_err onerr)
|
||||
{
|
||||
struct ref_lock *lock;
|
||||
lock = lock_any_ref_for_update(refname, oldval, flags, type_p);
|
||||
if (!lock) {
|
||||
const char *str = "Cannot lock the ref '%s'.";
|
||||
switch (onerr) {
|
||||
case UPDATE_REFS_MSG_ON_ERR: error(str, refname); break;
|
||||
case UPDATE_REFS_DIE_ON_ERR: die(str, refname); break;
|
||||
case UPDATE_REFS_QUIET_ON_ERR: break;
|
||||
}
|
||||
}
|
||||
return lock;
|
||||
}
|
||||
|
||||
static int update_ref_write(const char *action, const char *refname,
|
||||
const unsigned char *sha1, struct ref_lock *lock,
|
||||
struct strbuf *err, enum action_on_err onerr)
|
||||
{
|
||||
if (write_ref_sha1(lock, sha1, action) < 0) {
|
||||
const char *str = "Cannot update the ref '%s'.";
|
||||
if (err)
|
||||
strbuf_addf(err, str, refname);
|
||||
|
||||
switch (onerr) {
|
||||
case UPDATE_REFS_MSG_ON_ERR: error(str, refname); break;
|
||||
case UPDATE_REFS_DIE_ON_ERR: die(str, refname); break;
|
||||
case UPDATE_REFS_QUIET_ON_ERR: break;
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Information needed for a single ref update. Set new_sha1 to the
|
||||
* new value or to zero to delete the ref. To check the old value
|
||||
|
@ -3385,6 +3352,21 @@ struct ref_update {
|
|||
const char refname[FLEX_ARRAY];
|
||||
};
|
||||
|
||||
/*
|
||||
* Transaction states.
|
||||
* OPEN: The transaction is in a valid state and can accept new updates.
|
||||
* An OPEN transaction can be committed.
|
||||
* CLOSED: A closed transaction is no longer active and no other operations
|
||||
* than free can be used on it in this state.
|
||||
* A transaction can either become closed by successfully committing
|
||||
* an active transaction or if there is a failure while building
|
||||
* the transaction thus rendering it failed/inactive.
|
||||
*/
|
||||
enum ref_transaction_state {
|
||||
REF_TRANSACTION_OPEN = 0,
|
||||
REF_TRANSACTION_CLOSED = 1
|
||||
};
|
||||
|
||||
/*
|
||||
* Data structure for holding a reference transaction, which can
|
||||
* consist of checks and updates to multiple references, carried out
|
||||
|
@ -3394,9 +3376,10 @@ struct ref_transaction {
|
|||
struct ref_update **updates;
|
||||
size_t alloc;
|
||||
size_t nr;
|
||||
enum ref_transaction_state state;
|
||||
};
|
||||
|
||||
struct ref_transaction *ref_transaction_begin(void)
|
||||
struct ref_transaction *ref_transaction_begin(struct strbuf *err)
|
||||
{
|
||||
return xcalloc(1, sizeof(struct ref_transaction));
|
||||
}
|
||||
|
@ -3436,6 +3419,9 @@ int ref_transaction_update(struct ref_transaction *transaction,
|
|||
{
|
||||
struct ref_update *update;
|
||||
|
||||
if (transaction->state != REF_TRANSACTION_OPEN)
|
||||
die("BUG: update called for transaction that is not open");
|
||||
|
||||
if (have_old && !old_sha1)
|
||||
die("BUG: have_old is true but old_sha1 is NULL");
|
||||
|
||||
|
@ -3448,44 +3434,84 @@ int ref_transaction_update(struct ref_transaction *transaction,
|
|||
return 0;
|
||||
}
|
||||
|
||||
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)
|
||||
{
|
||||
struct ref_update *update = add_update(transaction, refname);
|
||||
struct ref_update *update;
|
||||
|
||||
if (transaction->state != REF_TRANSACTION_OPEN)
|
||||
die("BUG: create called for transaction that is not open");
|
||||
|
||||
if (!new_sha1 || is_null_sha1(new_sha1))
|
||||
die("BUG: create ref with null new_sha1");
|
||||
|
||||
update = add_update(transaction, refname);
|
||||
|
||||
assert(!is_null_sha1(new_sha1));
|
||||
hashcpy(update->new_sha1, new_sha1);
|
||||
hashclr(update->old_sha1);
|
||||
update->flags = flags;
|
||||
update->have_old = 1;
|
||||
return 0;
|
||||
}
|
||||
|
||||
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)
|
||||
{
|
||||
struct ref_update *update = add_update(transaction, refname);
|
||||
struct ref_update *update;
|
||||
|
||||
if (transaction->state != REF_TRANSACTION_OPEN)
|
||||
die("BUG: delete called for transaction that is not open");
|
||||
|
||||
if (have_old && !old_sha1)
|
||||
die("BUG: have_old is true but old_sha1 is NULL");
|
||||
|
||||
update = add_update(transaction, refname);
|
||||
update->flags = flags;
|
||||
update->have_old = have_old;
|
||||
if (have_old) {
|
||||
assert(!is_null_sha1(old_sha1));
|
||||
hashcpy(update->old_sha1, old_sha1);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
int update_ref(const char *action, const char *refname,
|
||||
const unsigned char *sha1, const unsigned char *oldval,
|
||||
int flags, enum action_on_err onerr)
|
||||
{
|
||||
struct ref_lock *lock;
|
||||
lock = update_ref_lock(refname, oldval, flags, NULL, onerr);
|
||||
if (!lock)
|
||||
struct ref_transaction *t;
|
||||
struct strbuf err = STRBUF_INIT;
|
||||
|
||||
t = ref_transaction_begin(&err);
|
||||
if (!t ||
|
||||
ref_transaction_update(t, refname, sha1, oldval, flags,
|
||||
!!oldval, &err) ||
|
||||
ref_transaction_commit(t, action, &err)) {
|
||||
const char *str = "update_ref failed for ref '%s': %s";
|
||||
|
||||
ref_transaction_free(t);
|
||||
switch (onerr) {
|
||||
case UPDATE_REFS_MSG_ON_ERR:
|
||||
error(str, refname, err.buf);
|
||||
break;
|
||||
case UPDATE_REFS_DIE_ON_ERR:
|
||||
die(str, refname, err.buf);
|
||||
break;
|
||||
case UPDATE_REFS_QUIET_ON_ERR:
|
||||
break;
|
||||
}
|
||||
strbuf_release(&err);
|
||||
return 1;
|
||||
return update_ref_write(action, refname, sha1, lock, NULL, onerr);
|
||||
}
|
||||
strbuf_release(&err);
|
||||
ref_transaction_free(t);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int ref_update_compare(const void *r1, const void *r2)
|
||||
|
@ -3519,8 +3545,13 @@ int ref_transaction_commit(struct ref_transaction *transaction,
|
|||
int n = transaction->nr;
|
||||
struct ref_update **updates = transaction->updates;
|
||||
|
||||
if (!n)
|
||||
if (transaction->state != REF_TRANSACTION_OPEN)
|
||||
die("BUG: commit called for transaction that is not open");
|
||||
|
||||
if (!n) {
|
||||
transaction->state = REF_TRANSACTION_CLOSED;
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Allocate work space */
|
||||
delnames = xmalloc(sizeof(*delnames) * n);
|
||||
|
@ -3535,12 +3566,12 @@ int ref_transaction_commit(struct ref_transaction *transaction,
|
|||
for (i = 0; i < n; i++) {
|
||||
struct ref_update *update = updates[i];
|
||||
|
||||
update->lock = update_ref_lock(update->refname,
|
||||
(update->have_old ?
|
||||
update->old_sha1 : NULL),
|
||||
update->flags,
|
||||
&update->type,
|
||||
UPDATE_REFS_QUIET_ON_ERR);
|
||||
update->lock = lock_any_ref_for_update(update->refname,
|
||||
(update->have_old ?
|
||||
update->old_sha1 :
|
||||
NULL),
|
||||
update->flags,
|
||||
&update->type);
|
||||
if (!update->lock) {
|
||||
if (err)
|
||||
strbuf_addf(err, "Cannot lock the ref '%s'.",
|
||||
|
@ -3555,14 +3586,15 @@ int ref_transaction_commit(struct ref_transaction *transaction,
|
|||
struct ref_update *update = updates[i];
|
||||
|
||||
if (!is_null_sha1(update->new_sha1)) {
|
||||
ret = update_ref_write(msg,
|
||||
update->refname,
|
||||
update->new_sha1,
|
||||
update->lock, err,
|
||||
UPDATE_REFS_QUIET_ON_ERR);
|
||||
update->lock = NULL; /* freed by update_ref_write */
|
||||
if (ret)
|
||||
ret = write_ref_sha1(update->lock, update->new_sha1,
|
||||
msg);
|
||||
update->lock = NULL; /* freed by write_ref_sha1 */
|
||||
if (ret) {
|
||||
if (err)
|
||||
strbuf_addf(err, "Cannot update the ref '%s'.",
|
||||
update->refname);
|
||||
goto cleanup;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -3571,8 +3603,9 @@ int ref_transaction_commit(struct ref_transaction *transaction,
|
|||
struct ref_update *update = updates[i];
|
||||
|
||||
if (update->lock) {
|
||||
delnames[delnum++] = update->lock->ref_name;
|
||||
ret |= delete_ref_loose(update->lock, update->type);
|
||||
if (!(update->flags & REF_ISPRUNING))
|
||||
delnames[delnum++] = update->lock->ref_name;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -3582,6 +3615,8 @@ int ref_transaction_commit(struct ref_transaction *transaction,
|
|||
clear_loose_ref_cache(&ref_cache);
|
||||
|
||||
cleanup:
|
||||
transaction->state = REF_TRANSACTION_CLOSED;
|
||||
|
||||
for (i = 0; i < n; i++)
|
||||
if (updates[i]->lock)
|
||||
unlock_ref(updates[i]->lock);
|
||||
|
|
77
refs.h
77
refs.h
|
@ -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);
|
||||
|
|
26
sequencer.c
26
sequencer.c
|
@ -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,
|
||||
|
|
85
walker.c
85
walker.c
|
@ -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)";
|
||||
for (i = 0; i < targets; i++) {
|
||||
if (!write_ref || !write_ref[i])
|
||||
continue;
|
||||
ret = write_ref_sha1(lock[i], &sha1[20 * i], msg);
|
||||
lock[i] = NULL;
|
||||
if (ret)
|
||||
goto unlock_and_fail;
|
||||
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[i])
|
||||
continue;
|
||||
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;
|
||||
ret = 0;
|
||||
|
||||
unlock_and_fail:
|
||||
for (i = 0; i < targets; i++)
|
||||
if (lock[i])
|
||||
unlock_ref(lock[i]);
|
||||
free(to_free);
|
||||
|
||||
return -1;
|
||||
done:
|
||||
ref_transaction_free(transaction);
|
||||
free(msg);
|
||||
free(sha1);
|
||||
strbuf_release(&err);
|
||||
strbuf_release(&refname);
|
||||
return ret;
|
||||
}
|
||||
|
||||
void walker_free(struct walker *walker)
|
||||
|
|
Загрузка…
Ссылка в новой задаче