diff options
Diffstat (limited to 'refs.c')
-rw-r--r-- | refs.c | 402 |
1 files changed, 307 insertions, 95 deletions
@@ -19,12 +19,14 @@ struct ref_lock { * 1: End-of-component * 2: ., look for a preceding . to reject .. in refs * 3: {, look for a preceding @ to reject @{ in refs - * 4: A bad character: ASCII control characters, "~", "^", ":" or SP + * 4: A bad character: ASCII control characters, and + * ":", "?", "[", "\", "^", "~", SP, or TAB + * 5: *, reject unless REFNAME_REFSPEC_PATTERN is set */ static unsigned char refname_disposition[256] = { 1, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, - 4, 0, 0, 0, 0, 0, 0, 0, 0, 0, 4, 0, 0, 0, 2, 1, + 4, 0, 0, 0, 0, 0, 0, 0, 0, 0, 5, 0, 0, 0, 2, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 4, 0, 0, 0, 0, 4, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 4, 4, 0, 4, 0, @@ -63,6 +65,11 @@ static unsigned char refname_disposition[256] = { #define REF_NEEDS_COMMIT 0x20 /* + * 0x40 is REF_FORCE_CREATE_REFLOG, so skip it if you're adding a + * value to ref_update::flags + */ + +/* * 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 legal. It is legal if it is something reasonable to have under @@ -70,12 +77,14 @@ static unsigned char refname_disposition[256] = { * * - any path component of it begins with ".", or * - it has double dots "..", or - * - it has ASCII control character, "~", "^", ":" or SP, anywhere, or - * - it ends with a "/". - * - it ends with ".lock" - * - it contains a "\" (backslash) + * - it has ASCII control characters, or + * - it has ":", "?", "[", "\", "^", "~", SP, or TAB anywhere, or + * - it has "*" anywhere unless REFNAME_REFSPEC_PATTERN is set, or + * - it ends with a "/", or + * - it ends with ".lock", or + * - it contains a "@{" portion */ -static int check_refname_component(const char *refname, int flags) +static int check_refname_component(const char *refname, int *flags) { const char *cp; char last = '\0'; @@ -96,6 +105,16 @@ static int check_refname_component(const char *refname, int flags) break; case 4: return -1; + case 5: + if (!(*flags & REFNAME_REFSPEC_PATTERN)) + return -1; /* refspec can't be a pattern */ + + /* + * Unset the pattern flag so that we only accept + * a single asterisk for one side of refspec. + */ + *flags &= ~ REFNAME_REFSPEC_PATTERN; + break; } last = ch; } @@ -120,18 +139,10 @@ int check_refname_format(const char *refname, int flags) while (1) { /* We are at the start of a path component. */ - component_len = check_refname_component(refname, flags); - if (component_len <= 0) { - if ((flags & REFNAME_REFSPEC_PATTERN) && - refname[0] == '*' && - (refname[1] == '\0' || refname[1] == '/')) { - /* Accept one wildcard as a full refname component. */ - flags &= ~REFNAME_REFSPEC_PATTERN; - component_len = 1; - } else { - return -1; - } - } + component_len = check_refname_component(refname, &flags); + if (component_len <= 0) + return -1; + component_count++; if (refname[component_len] == '\0') break; @@ -1314,7 +1325,13 @@ static struct ref_dir *get_packed_refs(struct ref_cache *refs) return get_packed_ref_dir(get_packed_ref_cache(refs)); } -void add_packed_ref(const char *refname, const unsigned char *sha1) +/* + * Add a reference to the in-memory packed reference cache. This may + * only be called while the packed-refs file is locked (see + * lock_packed_refs()). To actually write the packed-refs file, call + * commit_packed_refs(). + */ +static void add_packed_ref(const char *refname, const unsigned char *sha1) { struct packed_ref_cache *packed_ref_cache = get_packed_ref_cache(&ref_cache); @@ -1741,9 +1758,11 @@ const char *resolve_ref_unsafe(const char *refname, int resolve_flags, return ret; } -char *resolve_refdup(const char *ref, int resolve_flags, unsigned char *sha1, int *flags) +char *resolve_refdup(const char *refname, int resolve_flags, + unsigned char *sha1, int *flags) { - return xstrdup_or_null(resolve_ref_unsafe(ref, resolve_flags, sha1, flags)); + return xstrdup_or_null(resolve_ref_unsafe(refname, resolve_flags, + sha1, flags)); } /* The argument to filter_refs */ @@ -2122,7 +2141,8 @@ int for_each_remote_ref_submodule(const char *submodule, each_ref_fn fn, void *c int for_each_replace_ref(each_ref_fn fn, void *cb_data) { - return do_for_each_ref(&ref_cache, "refs/replace/", fn, 13, 0, cb_data); + return do_for_each_ref(&ref_cache, git_replace_ref_base, fn, + strlen(git_replace_ref_base), 0, cb_data); } int head_ref_namespaced(each_ref_fn fn, void *cb_data) @@ -2530,8 +2550,12 @@ static int write_packed_entry_fn(struct ref_entry *entry, void *cb_data) return 0; } -/* This should return a meaningful errno on failure */ -int lock_packed_refs(int flags) +/* + * Lock the packed-refs file for writing. Flags is passed to + * hold_lock_file_for_update(). Return 0 on success. On errors, set + * errno appropriately and return a nonzero value. + */ +static int lock_packed_refs(int flags) { static int timeout_configured = 0; static int timeout_value = 1000; @@ -2561,10 +2585,12 @@ int lock_packed_refs(int flags) } /* - * Commit the packed refs changes. - * On error we must make sure that errno contains a meaningful value. + * Write the current version of the packed refs cache from memory to + * disk. The packed-refs file must already be locked for writing (see + * lock_packed_refs()). Return zero on success. On errors, set errno + * and return a nonzero value */ -int commit_packed_refs(void) +static int commit_packed_refs(void) { struct packed_ref_cache *packed_ref_cache = get_packed_ref_cache(&ref_cache); @@ -2593,7 +2619,12 @@ int commit_packed_refs(void) return error; } -void rollback_packed_refs(void) +/* + * Rollback the lockfile for the packed-refs file, and discard the + * in-memory packed reference cache. (The packed-refs file will be + * read anew if it is needed again after this function is called.) + */ +static void rollback_packed_refs(void) { struct packed_ref_cache *packed_ref_cache = get_packed_ref_cache(&ref_cache); @@ -2751,7 +2782,14 @@ int pack_refs(unsigned int flags) return 0; } -int repack_without_refs(struct string_list *refnames, struct strbuf *err) +/* + * Rewrite the packed-refs file, omitting any refs listed in + * 'refnames'. On error, leave packed-refs unchanged, write an error + * message to 'err', and return a nonzero value. + * + * The refs in 'refnames' needn't be sorted. `err` must not be NULL. + */ +static int repack_without_refs(struct string_list *refnames, struct strbuf *err) { struct ref_dir *packed; struct string_list_item *refname; @@ -2816,15 +2854,15 @@ static int delete_ref_loose(struct ref_lock *lock, int flag, struct strbuf *err) return 0; } -int delete_ref(const char *refname, const unsigned char *sha1, unsigned int flags) +int delete_ref(const char *refname, const unsigned char *old_sha1, + unsigned int flags) { struct ref_transaction *transaction; struct strbuf err = STRBUF_INIT; transaction = ref_transaction_begin(&err); if (!transaction || - ref_transaction_delete(transaction, refname, - (sha1 && !is_null_sha1(sha1)) ? sha1 : NULL, + ref_transaction_delete(transaction, refname, old_sha1, flags, NULL, &err) || ref_transaction_commit(transaction, &err)) { error("%s", err.buf); @@ -2837,6 +2875,44 @@ int delete_ref(const char *refname, const unsigned char *sha1, unsigned int flag return 0; } +int delete_refs(struct string_list *refnames) +{ + struct strbuf err = STRBUF_INIT; + int i, result = 0; + + if (!refnames->nr) + return 0; + + result = repack_without_refs(refnames, &err); + if (result) { + /* + * If we failed to rewrite the packed-refs file, then + * it is unsafe to try to remove loose refs, because + * doing so might expose an obsolete packed value for + * a reference that might even point at an object that + * has been garbage collected. + */ + if (refnames->nr == 1) + error(_("could not delete reference %s: %s"), + refnames->items[0].string, err.buf); + else + error(_("could not delete references: %s"), err.buf); + + goto out; + } + + for (i = 0; i < refnames->nr; i++) { + const char *refname = refnames->items[i].string; + + if (delete_ref(refname, NULL, 0)) + result |= error(_("could not remove reference %s"), refname); + } + +out: + strbuf_release(&err); + return result; +} + /* * People using contrib's git-new-workdir have .git/logs/refs -> * /some/other/path/.git/logs/refs, and that may live on another device. @@ -2910,9 +2986,11 @@ static int rename_ref_available(const char *oldname, const char *newname) return ret; } -static int write_ref_to_lockfile(struct ref_lock *lock, const unsigned char *sha1); +static int write_ref_to_lockfile(struct ref_lock *lock, + const unsigned char *sha1, struct strbuf *err); static int commit_ref_update(struct ref_lock *lock, - const unsigned char *sha1, const char *logmsg); + const unsigned char *sha1, const char *logmsg, + int flags, struct strbuf *err); int rename_ref(const char *oldrefname, const char *newrefname, const char *logmsg) { @@ -2973,9 +3051,10 @@ int rename_ref(const char *oldrefname, const char *newrefname, const char *logms } hashcpy(lock->old_oid.hash, orig_sha1); - if (write_ref_to_lockfile(lock, orig_sha1) || - commit_ref_update(lock, orig_sha1, logmsg)) { - error("unable to write current sha1 into %s", newrefname); + if (write_ref_to_lockfile(lock, orig_sha1, &err) || + commit_ref_update(lock, orig_sha1, logmsg, 0, &err)) { + error("unable to write current sha1 into %s: %s", newrefname, err.buf); + strbuf_release(&err); goto rollback; } @@ -2991,9 +3070,11 @@ int rename_ref(const char *oldrefname, const char *newrefname, const char *logms flag = log_all_ref_updates; log_all_ref_updates = 0; - if (write_ref_to_lockfile(lock, orig_sha1) || - commit_ref_update(lock, orig_sha1, NULL)) - error("unable to write current sha1 into %s", oldrefname); + if (write_ref_to_lockfile(lock, orig_sha1, &err) || + commit_ref_update(lock, orig_sha1, NULL, 0, &err)) { + error("unable to write current sha1 into %s: %s", oldrefname, err.buf); + strbuf_release(&err); + } log_all_ref_updates = flag; rollbacklog: @@ -3048,8 +3129,23 @@ static int copy_msg(char *buf, const char *msg) return cp - buf; } -/* This function must set a meaningful errno on failure */ -int log_ref_setup(const char *refname, struct strbuf *sb_logfile) +static int should_autocreate_reflog(const char *refname) +{ + if (!log_all_ref_updates) + return 0; + return starts_with(refname, "refs/heads/") || + starts_with(refname, "refs/remotes/") || + starts_with(refname, "refs/notes/") || + !strcmp(refname, "HEAD"); +} + +/* + * Create a reflog for a ref. If force_create = 0, the reflog will + * only be created for certain refs (those for which + * should_autocreate_reflog returns non-zero. Otherwise, create it + * regardless of the ref name. Fill in *err and return -1 on failure. + */ +static int log_ref_setup(const char *refname, struct strbuf *sb_logfile, struct strbuf *err, int force_create) { int logfd, oflags = O_APPEND | O_WRONLY; char *logfile; @@ -3058,15 +3154,10 @@ int log_ref_setup(const char *refname, struct strbuf *sb_logfile) logfile = sb_logfile->buf; /* make sure the rest of the function can't change "logfile" */ sb_logfile = NULL; - if (log_all_ref_updates && - (starts_with(refname, "refs/heads/") || - starts_with(refname, "refs/remotes/") || - starts_with(refname, "refs/notes/") || - !strcmp(refname, "HEAD"))) { + if (force_create || should_autocreate_reflog(refname)) { if (safe_create_leading_directories(logfile) < 0) { - int save_errno = errno; - error("unable to create directory for %s", logfile); - errno = save_errno; + strbuf_addf(err, "unable to create directory for %s: " + "%s", logfile, strerror(errno)); return -1; } oflags |= O_CREAT; @@ -3079,20 +3170,16 @@ int log_ref_setup(const char *refname, struct strbuf *sb_logfile) if (errno == EISDIR) { if (remove_empty_directories(logfile)) { - int save_errno = errno; - error("There are still logs under '%s'", - logfile); - errno = save_errno; + strbuf_addf(err, "There are still logs under " + "'%s'", logfile); return -1; } logfd = open(logfile, oflags, 0666); } if (logfd < 0) { - int save_errno = errno; - error("Unable to append to %s: %s", logfile, - strerror(errno)); - errno = save_errno; + strbuf_addf(err, "unable to append to %s: %s", + logfile, strerror(errno)); return -1; } } @@ -3102,6 +3189,17 @@ int log_ref_setup(const char *refname, struct strbuf *sb_logfile) return 0; } + +int safe_create_reflog(const char *refname, int force_create, struct strbuf *err) +{ + int ret; + struct strbuf sb = STRBUF_INIT; + + ret = log_ref_setup(refname, &sb, err, force_create); + strbuf_release(&sb); + return ret; +} + static int log_ref_write_fd(int fd, const unsigned char *old_sha1, const unsigned char *new_sha1, const char *committer, const char *msg) @@ -3130,7 +3228,8 @@ static int log_ref_write_fd(int fd, const unsigned char *old_sha1, static int log_ref_write_1(const char *refname, const unsigned char *old_sha1, const unsigned char *new_sha1, const char *msg, - struct strbuf *sb_log_file) + struct strbuf *sb_log_file, int flags, + struct strbuf *err) { int logfd, result, oflags = O_APPEND | O_WRONLY; char *log_file; @@ -3138,7 +3237,8 @@ static int log_ref_write_1(const char *refname, const unsigned char *old_sha1, if (log_all_ref_updates < 0) log_all_ref_updates = !is_bare_repository(); - result = log_ref_setup(refname, sb_log_file); + result = log_ref_setup(refname, sb_log_file, err, flags & REF_FORCE_CREATE_REFLOG); + if (result) return result; log_file = sb_log_file->buf; @@ -3151,26 +3251,26 @@ static int log_ref_write_1(const char *refname, const unsigned char *old_sha1, result = log_ref_write_fd(logfd, old_sha1, new_sha1, git_committer_info(0), msg); if (result) { - int save_errno = errno; + strbuf_addf(err, "unable to append to %s: %s", log_file, + strerror(errno)); close(logfd); - error("Unable to append to %s", log_file); - errno = save_errno; return -1; } if (close(logfd)) { - int save_errno = errno; - error("Unable to append to %s", log_file); - errno = save_errno; + strbuf_addf(err, "unable to append to %s: %s", log_file, + strerror(errno)); return -1; } return 0; } static int log_ref_write(const char *refname, const unsigned char *old_sha1, - const unsigned char *new_sha1, const char *msg) + const unsigned char *new_sha1, const char *msg, + int flags, struct strbuf *err) { struct strbuf sb = STRBUF_INIT; - int ret = log_ref_write_1(refname, old_sha1, new_sha1, msg, &sb); + int ret = log_ref_write_1(refname, old_sha1, new_sha1, msg, &sb, flags, + err); strbuf_release(&sb); return ret; } @@ -3182,36 +3282,36 @@ int is_branch(const char *refname) /* * Write sha1 into the open lockfile, then close the lockfile. On - * errors, rollback the lockfile and set errno to reflect the problem. + * errors, rollback the lockfile, fill in *err and + * return -1. */ static int write_ref_to_lockfile(struct ref_lock *lock, - const unsigned char *sha1) + const unsigned char *sha1, struct strbuf *err) { static char term = '\n'; struct object *o; o = parse_object(sha1); if (!o) { - error("Trying to write ref %s with nonexistent object %s", - lock->ref_name, sha1_to_hex(sha1)); + strbuf_addf(err, + "Trying to write ref %s with nonexistent object %s", + lock->ref_name, sha1_to_hex(sha1)); unlock_ref(lock); - errno = EINVAL; return -1; } if (o->type != OBJ_COMMIT && is_branch(lock->ref_name)) { - error("Trying to write non-commit object %s to branch %s", - sha1_to_hex(sha1), lock->ref_name); + strbuf_addf(err, + "Trying to write non-commit object %s to branch %s", + sha1_to_hex(sha1), lock->ref_name); unlock_ref(lock); - errno = EINVAL; return -1; } if (write_in_full(lock->lk->fd, sha1_to_hex(sha1), 40) != 40 || write_in_full(lock->lk->fd, &term, 1) != 1 || close_ref(lock) < 0) { - int save_errno = errno; - error("Couldn't write %s", lock->lk->filename.buf); + strbuf_addf(err, + "Couldn't write %s", lock->lk->filename.buf); unlock_ref(lock); - errno = save_errno; return -1; } return 0; @@ -3223,12 +3323,17 @@ static int write_ref_to_lockfile(struct ref_lock *lock, * necessary, using the specified lockmsg (which can be NULL). */ static int commit_ref_update(struct ref_lock *lock, - const unsigned char *sha1, const char *logmsg) + const unsigned char *sha1, const char *logmsg, + int flags, struct strbuf *err) { clear_loose_ref_cache(&ref_cache); - if (log_ref_write(lock->ref_name, lock->old_oid.hash, sha1, logmsg) < 0 || + if (log_ref_write(lock->ref_name, lock->old_oid.hash, sha1, logmsg, flags, err) < 0 || (strcmp(lock->ref_name, lock->orig_ref_name) && - log_ref_write(lock->orig_ref_name, lock->old_oid.hash, sha1, logmsg) < 0)) { + log_ref_write(lock->orig_ref_name, lock->old_oid.hash, sha1, logmsg, flags, err) < 0)) { + char *old_msg = strbuf_detach(err, NULL); + strbuf_addf(err, "Cannot update the ref '%s': %s", + lock->ref_name, old_msg); + free(old_msg); unlock_ref(lock); return -1; } @@ -3251,14 +3356,21 @@ static int commit_ref_update(struct ref_lock *lock, head_ref = resolve_ref_unsafe("HEAD", RESOLVE_REF_READING, head_sha1, &head_flag); if (head_ref && (head_flag & REF_ISSYMREF) && - !strcmp(head_ref, lock->ref_name)) - log_ref_write("HEAD", lock->old_oid.hash, sha1, logmsg); + !strcmp(head_ref, lock->ref_name)) { + struct strbuf log_err = STRBUF_INIT; + if (log_ref_write("HEAD", lock->old_oid.hash, sha1, + logmsg, 0, &log_err)) { + error("%s", log_err.buf); + strbuf_release(&log_err); + } + } } if (commit_ref(lock)) { error("Couldn't set %s", lock->ref_name); unlock_ref(lock); return -1; } + unlock_ref(lock); return 0; } @@ -3271,6 +3383,7 @@ int create_symref(const char *ref_target, const char *refs_heads_master, int fd, len, written; char *git_HEAD = git_pathdup("%s", ref_target); unsigned char old_sha1[20], new_sha1[20]; + struct strbuf err = STRBUF_INIT; if (logmsg && read_ref(ref_target, old_sha1)) hashclr(old_sha1); @@ -3319,8 +3432,11 @@ int create_symref(const char *ref_target, const char *refs_heads_master, #ifndef NO_SYMLINK_HEAD done: #endif - if (logmsg && !read_ref(refs_heads_master, new_sha1)) - log_ref_write(ref_target, old_sha1, new_sha1, logmsg); + if (logmsg && !read_ref(refs_heads_master, new_sha1) && + log_ref_write(ref_target, old_sha1, new_sha1, logmsg, 0, &err)) { + error("%s", err.buf); + strbuf_release(&err); + } free(git_HEAD); return 0; @@ -3371,14 +3487,14 @@ static int read_ref_at_ent(unsigned char *osha1, unsigned char *nsha1, hashcpy(cb->sha1, nsha1); if (hashcmp(cb->osha1, nsha1)) warning("Log for ref %s has gap after %s.", - cb->refname, show_date(cb->date, cb->tz, DATE_RFC2822)); + cb->refname, show_date(cb->date, cb->tz, DATE_MODE(RFC2822))); } else if (cb->date == cb->at_time) hashcpy(cb->sha1, nsha1); else if (hashcmp(nsha1, cb->sha1)) warning("Log for ref %s unexpectedly ended on %s.", cb->refname, show_date(cb->date, cb->tz, - DATE_RFC2822)); + DATE_MODE(RFC2822))); hashcpy(cb->osha1, osha1); hashcpy(cb->nsha1, nsha1); cb->found_it = 1; @@ -3956,14 +4072,19 @@ int ref_transaction_commit(struct ref_transaction *transaction, * value, so we don't need to write it. */ } else if (write_ref_to_lockfile(update->lock, - update->new_sha1)) { + update->new_sha1, + err)) { + char *write_err = strbuf_detach(err, NULL); + /* * The lock was freed upon failure of * write_ref_to_lockfile(): */ update->lock = NULL; - strbuf_addf(err, "cannot update the ref '%s'.", - update->refname); + strbuf_addf(err, + "cannot update the ref '%s': %s", + update->refname, write_err); + free(write_err); ret = TRANSACTION_GENERIC_ERROR; goto cleanup; } else { @@ -3989,11 +4110,10 @@ int ref_transaction_commit(struct ref_transaction *transaction, if (update->flags & REF_NEEDS_COMMIT) { if (commit_ref_update(update->lock, - update->new_sha1, update->msg)) { + update->new_sha1, update->msg, + update->flags, err)) { /* freed by commit_ref_update(): */ update->lock = NULL; - strbuf_addf(err, "Cannot update the ref '%s'.", - update->refname); ret = TRANSACTION_GENERIC_ERROR; goto cleanup; } else { @@ -4038,6 +4158,98 @@ cleanup: return ret; } +static int ref_present(const char *refname, + const struct object_id *oid, int flags, void *cb_data) +{ + struct string_list *affected_refnames = cb_data; + + return string_list_has_string(affected_refnames, refname); +} + +int initial_ref_transaction_commit(struct ref_transaction *transaction, + struct strbuf *err) +{ + struct ref_dir *loose_refs = get_loose_refs(&ref_cache); + struct ref_dir *packed_refs = get_packed_refs(&ref_cache); + int ret = 0, i; + int n = transaction->nr; + struct ref_update **updates = transaction->updates; + struct string_list affected_refnames = STRING_LIST_INIT_NODUP; + + assert(err); + + if (transaction->state != REF_TRANSACTION_OPEN) + die("BUG: commit called for transaction that is not open"); + + /* Fail if a refname appears more than once in the transaction: */ + for (i = 0; i < n; i++) + string_list_append(&affected_refnames, updates[i]->refname); + string_list_sort(&affected_refnames); + if (ref_update_reject_duplicates(&affected_refnames, err)) { + ret = TRANSACTION_GENERIC_ERROR; + goto cleanup; + } + + /* + * It's really undefined to call this function in an active + * repository or when there are existing references: we are + * only locking and changing packed-refs, so (1) any + * simultaneous processes might try to change a reference at + * the same time we do, and (2) any existing loose versions of + * the references that we are setting would have precedence + * over our values. But some remote helpers create the remote + * "HEAD" and "master" branches before calling this function, + * so here we really only check that none of the references + * that we are creating already exists. + */ + if (for_each_rawref(ref_present, &affected_refnames)) + die("BUG: initial ref transaction called with existing refs"); + + for (i = 0; i < n; i++) { + struct ref_update *update = updates[i]; + + if ((update->flags & REF_HAVE_OLD) && + !is_null_sha1(update->old_sha1)) + die("BUG: initial ref transaction with old_sha1 set"); + if (verify_refname_available(update->refname, + &affected_refnames, NULL, + loose_refs, err) || + verify_refname_available(update->refname, + &affected_refnames, NULL, + packed_refs, err)) { + ret = TRANSACTION_NAME_CONFLICT; + goto cleanup; + } + } + + if (lock_packed_refs(0)) { + strbuf_addf(err, "unable to lock packed-refs file: %s", + strerror(errno)); + ret = TRANSACTION_GENERIC_ERROR; + goto cleanup; + } + + for (i = 0; i < n; i++) { + struct ref_update *update = updates[i]; + + if ((update->flags & REF_HAVE_NEW) && + !is_null_sha1(update->new_sha1)) + add_packed_ref(update->refname, update->new_sha1); + } + + if (commit_packed_refs()) { + strbuf_addf(err, "unable to commit packed-refs file: %s", + strerror(errno)); + ret = TRANSACTION_GENERIC_ERROR; + goto cleanup; + } + +cleanup: + transaction->state = REF_TRANSACTION_CLOSED; + string_list_clear(&affected_refnames, 0); + return ret; +} + char *shorten_unambiguous_ref(const char *refname, int strict) { int i; |