* 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,
*/
#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
*
* - 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';
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;
}
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;
*/
static struct packed_ref_cache *get_packed_ref_cache(struct ref_cache *refs)
{
- const char *packed_refs_file;
+ char *packed_refs_file;
if (*refs->name)
- packed_refs_file = git_path_submodule(refs->name, "packed-refs");
+ packed_refs_file = git_pathdup_submodule(refs->name, "packed-refs");
else
- packed_refs_file = git_path("packed-refs");
+ packed_refs_file = git_pathdup("packed-refs");
if (refs->packed &&
!stat_validity_check(&refs->packed->validity, packed_refs_file))
fclose(f);
}
}
+ free(packed_refs_file);
return refs->packed;
}
{
struct ref_cache *refs = dir->ref_cache;
DIR *d;
- const char *path;
struct dirent *de;
int dirnamelen = strlen(dirname);
struct strbuf refname;
+ struct strbuf path = STRBUF_INIT;
+ size_t path_baselen;
if (*refs->name)
- path = git_path_submodule(refs->name, "%s", dirname);
+ strbuf_git_path_submodule(&path, refs->name, "%s", dirname);
else
- path = git_path("%s", dirname);
+ strbuf_git_path(&path, "%s", dirname);
+ path_baselen = path.len;
- d = opendir(path);
- if (!d)
+ d = opendir(path.buf);
+ if (!d) {
+ strbuf_release(&path);
return;
+ }
strbuf_init(&refname, dirnamelen + 257);
strbuf_add(&refname, dirname, dirnamelen);
unsigned char sha1[20];
struct stat st;
int flag;
- const char *refdir;
if (de->d_name[0] == '.')
continue;
if (ends_with(de->d_name, ".lock"))
continue;
strbuf_addstr(&refname, de->d_name);
- refdir = *refs->name
- ? git_path_submodule(refs->name, "%s", refname.buf)
- : git_path("%s", refname.buf);
- if (stat(refdir, &st) < 0) {
+ strbuf_addstr(&path, de->d_name);
+ if (stat(path.buf, &st) < 0) {
; /* silently ignore */
} else if (S_ISDIR(st.st_mode)) {
strbuf_addch(&refname, '/');
create_ref_entry(refname.buf, sha1, flag, 0));
}
strbuf_setlen(&refname, dirnamelen);
+ strbuf_setlen(&path, path_baselen);
}
strbuf_release(&refname);
+ strbuf_release(&path);
closedir(d);
}
{
int fd, len;
char buffer[128], *p;
- const char *path;
+ char *path;
if (recursion > MAXDEPTH || strlen(refname) > MAXREFLEN)
return -1;
path = *refs->name
- ? git_path_submodule(refs->name, "%s", refname)
- : git_path("%s", refname);
+ ? git_pathdup_submodule(refs->name, "%s", refname)
+ : git_pathdup("%s", refname);
fd = open(path, O_RDONLY);
+ free(path);
if (fd < 0)
return resolve_gitlink_packed_ref(refs, refname, sha1);
return 0;
}
-static int remove_empty_directories(const char *file)
+static int remove_empty_directories(struct strbuf *path)
{
- /* we want to create a file but there is a directory there;
+ /*
+ * we want to create a file but there is a directory there;
* if that is an empty directory (or a directory that contains
* only empty directories), remove them.
*/
- struct strbuf path;
- int result, save_errno;
-
- strbuf_init(&path, 20);
- strbuf_addstr(&path, file);
-
- result = remove_dir_recursively(&path, REMOVE_DIR_EMPTY_ONLY);
- save_errno = errno;
-
- strbuf_release(&path);
- errno = save_errno;
-
- return result;
+ return remove_dir_recursively(path, REMOVE_DIR_EMPTY_ONLY);
}
/*
unsigned int flags, int *type_p,
struct strbuf *err)
{
- const char *ref_file;
+ struct strbuf ref_file = STRBUF_INIT;
+ struct strbuf orig_ref_file = STRBUF_INIT;
const char *orig_refname = refname;
struct ref_lock *lock;
int last_errno = 0;
refname = resolve_ref_unsafe(refname, resolve_flags,
lock->old_oid.hash, &type);
if (!refname && errno == EISDIR) {
- /* we are trying to lock foo but we used to
+ /*
+ * we are trying to lock foo but we used to
* have foo/bar which now does not exist;
* it is normal for the empty directory 'foo'
* to remain.
*/
- ref_file = git_path("%s", orig_refname);
- if (remove_empty_directories(ref_file)) {
+ strbuf_git_path(&orig_ref_file, "%s", orig_refname);
+ if (remove_empty_directories(&orig_ref_file)) {
last_errno = errno;
-
if (!verify_refname_available(orig_refname, extras, skip,
get_loose_refs(&ref_cache), err))
strbuf_addf(err, "there are still refs under '%s'",
orig_refname);
-
goto error_return;
}
refname = resolve_ref_unsafe(orig_refname, resolve_flags,
}
lock->ref_name = xstrdup(refname);
lock->orig_ref_name = xstrdup(orig_refname);
- ref_file = git_path("%s", refname);
+ strbuf_git_path(&ref_file, "%s", refname);
retry:
- switch (safe_create_leading_directories_const(ref_file)) {
+ switch (safe_create_leading_directories_const(ref_file.buf)) {
case SCLD_OK:
break; /* success */
case SCLD_VANISHED:
/* fall through */
default:
last_errno = errno;
- strbuf_addf(err, "unable to create directory for %s", ref_file);
+ strbuf_addf(err, "unable to create directory for %s",
+ ref_file.buf);
goto error_return;
}
- if (hold_lock_file_for_update(lock->lk, ref_file, lflags) < 0) {
+ if (hold_lock_file_for_update(lock->lk, ref_file.buf, lflags) < 0) {
last_errno = errno;
if (errno == ENOENT && --attempts_remaining > 0)
/*
*/
goto retry;
else {
- unable_to_lock_message(ref_file, errno, err);
+ unable_to_lock_message(ref_file.buf, errno, err);
goto error_return;
}
}
last_errno = errno;
goto error_return;
}
- return lock;
+ goto out;
error_return:
unlock_ref(lock);
+ lock = NULL;
+
+ out:
+ strbuf_release(&ref_file);
+ strbuf_release(&orig_ref_file);
errno = last_errno;
- return NULL;
+ return lock;
}
/*
static int rename_tmp_log(const char *newrefname)
{
int attempts_remaining = 4;
+ struct strbuf path = STRBUF_INIT;
+ int ret = -1;
retry:
- switch (safe_create_leading_directories_const(git_path("logs/%s", newrefname))) {
+ strbuf_reset(&path);
+ strbuf_git_path(&path, "logs/%s", newrefname);
+ switch (safe_create_leading_directories_const(path.buf)) {
case SCLD_OK:
break; /* success */
case SCLD_VANISHED:
/* fall through */
default:
error("unable to create directory for %s", newrefname);
- return -1;
+ goto out;
}
- if (rename(git_path(TMP_RENAMED_LOG), git_path("logs/%s", newrefname))) {
+ if (rename(git_path(TMP_RENAMED_LOG), path.buf)) {
if ((errno==EISDIR || errno==ENOTDIR) && --attempts_remaining > 0) {
/*
* rename(a, b) when b is an existing
* directory ought to result in ISDIR, but
* Solaris 5.8 gives ENOTDIR. Sheesh.
*/
- if (remove_empty_directories(git_path("logs/%s", newrefname))) {
+ if (remove_empty_directories(&path)) {
error("Directory not empty: logs/%s", newrefname);
- return -1;
+ goto out;
}
goto retry;
} else if (errno == ENOENT && --attempts_remaining > 0) {
} else {
error("unable to move logfile "TMP_RENAMED_LOG" to logs/%s: %s",
newrefname, strerror(errno));
- return -1;
+ goto out;
}
}
- return 0;
+ ret = 0;
+out:
+ strbuf_release(&path);
+ return ret;
}
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)
{
if (!read_ref_full(newrefname, RESOLVE_REF_READING, sha1, NULL) &&
delete_ref(newrefname, sha1, REF_NODEREF)) {
if (errno==EISDIR) {
- if (remove_empty_directories(git_path("%s", newrefname))) {
+ struct strbuf path = STRBUF_INIT;
+ int result;
+
+ strbuf_git_path(&path, "%s", newrefname);
+ result = remove_empty_directories(&path);
+ strbuf_release(&path);
+
+ if (result) {
error("Directory not empty: %s", newrefname);
goto rollback;
}
}
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;
}
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:
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 *logfile, struct strbuf *err, int force_create)
{
int logfd, oflags = O_APPEND | O_WRONLY;
- char *logfile;
-
- strbuf_git_path(sb_logfile, "logs/%s", refname);
- 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 (safe_create_leading_directories(logfile) < 0) {
- int save_errno = errno;
- error("unable to create directory for %s", logfile);
- errno = save_errno;
+
+ strbuf_git_path(logfile, "logs/%s", refname);
+ if (force_create || should_autocreate_reflog(refname)) {
+ if (safe_create_leading_directories(logfile->buf) < 0) {
+ strbuf_addf(err, "unable to create directory for %s: "
+ "%s", logfile->buf, strerror(errno));
return -1;
}
oflags |= O_CREAT;
}
- logfd = open(logfile, oflags, 0666);
+ logfd = open(logfile->buf, oflags, 0666);
if (logfd < 0) {
if (!(oflags & O_CREAT) && (errno == ENOENT || errno == EISDIR))
return 0;
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->buf);
return -1;
}
- logfd = open(logfile, oflags, 0666);
+ logfd = open(logfile->buf, 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->buf, strerror(errno));
return -1;
}
}
- adjust_shared_perm(logfile);
+ adjust_shared_perm(logfile->buf);
close(logfd);
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)
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 *logfile, int flags,
+ struct strbuf *err)
{
int logfd, result, oflags = O_APPEND | O_WRONLY;
- char *log_file;
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, logfile, err, flags & REF_FORCE_CREATE_REFLOG);
+
if (result)
return result;
- log_file = sb_log_file->buf;
- /* make sure the rest of the function can't change "log_file" */
- sb_log_file = NULL;
- logfd = open(log_file, oflags);
+ logfd = open(logfile->buf, oflags);
if (logfd < 0)
return 0;
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", logfile->buf,
+ 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", logfile->buf,
+ 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;
}
/*
* 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;
* 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;
}
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;
}
int create_symref(const char *ref_target, const char *refs_heads_master,
const char *logmsg)
{
- const char *lockpath;
+ char *lockpath = NULL;
char ref[1000];
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);
error("refname too long: %s", refs_heads_master);
goto error_free_return;
}
- lockpath = mkpath("%s.lock", git_HEAD);
+ lockpath = mkpathdup("%s.lock", git_HEAD);
fd = open(lockpath, O_CREAT | O_EXCL | O_WRONLY, 0666);
if (fd < 0) {
error("Unable to open %s for writing", lockpath);
error_unlink_return:
unlink_or_warn(lockpath);
error_free_return:
+ free(lockpath);
free(git_HEAD);
return -1;
}
+ free(lockpath);
#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;
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;
* 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 {
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 {
int ref_is_hidden(const char *refname)
{
- struct string_list_item *item;
+ int i;
if (!hide_refs)
return 0;
- for_each_string_list_item(item, hide_refs) {
+ for (i = hide_refs->nr - 1; i >= 0; i--) {
+ const char *match = hide_refs->items[i].string;
+ int neg = 0;
int len;
- if (!starts_with(refname, item->string))
+
+ if (*match == '!') {
+ neg = 1;
+ match++;
+ }
+
+ if (!starts_with(refname, match))
continue;
- len = strlen(item->string);
+ len = strlen(match);
if (!refname[len] || refname[len] == '/')
- return 1;
+ return !neg;
}
return 0;
}