Merge branch 'rs/ref-transaction'
The API to update refs have been restructured to allow introducing a true transactional updates later. We would even allow storing refs in backends other than the traditional filesystem-based one. * rs/ref-transaction: (25 commits) ref_transaction_commit: bail out on failure to remove a ref lockfile: remove unable_to_lock_error refs.c: do not permit err == NULL remote rm/prune: print a message when writing packed-refs fails for-each-ref: skip and warn about broken ref names refs.c: allow listing and deleting badly named refs test: put tests for handling of bad ref names in one place packed-ref cache: forbid dot-components in refnames branch -d: simplify by using RESOLVE_REF_READING branch -d: avoid repeated symref resolution reflog test: test interaction with detached HEAD refs.c: change resolve_ref_unsafe reading argument to be a flags field refs.c: make write_ref_sha1 static fetch.c: change s_update_ref to use a ref transaction refs.c: ref_transaction_commit: distinguish name conflicts from other errors refs.c: pass a list of names to skip to is_refname_available refs.c: call lock_ref_sha1_basic directly from commit refs.c: refuse to lock badly named refs in lock_ref_sha1_basic rename_ref: don't ask read_ref_full where the ref came from refs.c: pass the ref log message to _create/delete/update instead of _commit ...
This commit is contained in:
commit
3c85452bb0
6
branch.c
6
branch.c
@ -170,7 +170,7 @@ int validate_new_branchname(const char *name, struct strbuf *ref,
|
|||||||
const char *head;
|
const char *head;
|
||||||
unsigned char sha1[20];
|
unsigned char sha1[20];
|
||||||
|
|
||||||
head = resolve_ref_unsafe("HEAD", sha1, 0, NULL);
|
head = resolve_ref_unsafe("HEAD", 0, sha1, NULL);
|
||||||
if (!is_bare_repository() && head && !strcmp(head, ref->buf))
|
if (!is_bare_repository() && head && !strcmp(head, ref->buf))
|
||||||
die(_("Cannot force update the current branch."));
|
die(_("Cannot force update the current branch."));
|
||||||
}
|
}
|
||||||
@ -285,8 +285,8 @@ void create_branch(const char *head,
|
|||||||
transaction = ref_transaction_begin(&err);
|
transaction = ref_transaction_begin(&err);
|
||||||
if (!transaction ||
|
if (!transaction ||
|
||||||
ref_transaction_update(transaction, ref.buf, sha1,
|
ref_transaction_update(transaction, ref.buf, sha1,
|
||||||
null_sha1, 0, !forcing, &err) ||
|
null_sha1, 0, !forcing, msg, &err) ||
|
||||||
ref_transaction_commit(transaction, msg, &err))
|
ref_transaction_commit(transaction, &err))
|
||||||
die("%s", err.buf);
|
die("%s", err.buf);
|
||||||
ref_transaction_free(transaction);
|
ref_transaction_free(transaction);
|
||||||
strbuf_release(&err);
|
strbuf_release(&err);
|
||||||
|
@ -2286,7 +2286,7 @@ static struct commit *fake_working_tree_commit(struct diff_options *opt,
|
|||||||
commit->date = now;
|
commit->date = now;
|
||||||
parent_tail = &commit->parents;
|
parent_tail = &commit->parents;
|
||||||
|
|
||||||
if (!resolve_ref_unsafe("HEAD", head_sha1, 1, NULL))
|
if (!resolve_ref_unsafe("HEAD", RESOLVE_REF_READING, head_sha1, NULL))
|
||||||
die("no such ref: HEAD");
|
die("no such ref: HEAD");
|
||||||
|
|
||||||
parent_tail = append_parent(parent_tail, head_sha1);
|
parent_tail = append_parent(parent_tail, head_sha1);
|
||||||
|
@ -130,7 +130,8 @@ static int branch_merged(int kind, const char *name,
|
|||||||
branch->merge[0] &&
|
branch->merge[0] &&
|
||||||
branch->merge[0]->dst &&
|
branch->merge[0]->dst &&
|
||||||
(reference_name = reference_name_to_free =
|
(reference_name = reference_name_to_free =
|
||||||
resolve_refdup(branch->merge[0]->dst, sha1, 1, NULL)) != NULL)
|
resolve_refdup(branch->merge[0]->dst, RESOLVE_REF_READING,
|
||||||
|
sha1, NULL)) != NULL)
|
||||||
reference_rev = lookup_commit_reference(sha1);
|
reference_rev = lookup_commit_reference(sha1);
|
||||||
}
|
}
|
||||||
if (!reference_rev)
|
if (!reference_rev)
|
||||||
@ -234,9 +235,12 @@ static int delete_branches(int argc, const char **argv, int force, int kinds,
|
|||||||
free(name);
|
free(name);
|
||||||
|
|
||||||
name = mkpathdup(fmt, bname.buf);
|
name = mkpathdup(fmt, bname.buf);
|
||||||
target = resolve_ref_unsafe(name, sha1, 0, &flags);
|
target = resolve_ref_unsafe(name,
|
||||||
if (!target ||
|
RESOLVE_REF_READING
|
||||||
(!(flags & REF_ISSYMREF) && is_null_sha1(sha1))) {
|
| RESOLVE_REF_NO_RECURSE
|
||||||
|
| RESOLVE_REF_ALLOW_BAD_NAME,
|
||||||
|
sha1, &flags);
|
||||||
|
if (!target) {
|
||||||
error(remote_branch
|
error(remote_branch
|
||||||
? _("remote branch '%s' not found.")
|
? _("remote branch '%s' not found.")
|
||||||
: _("branch '%s' not found."), bname.buf);
|
: _("branch '%s' not found."), bname.buf);
|
||||||
@ -244,7 +248,7 @@ static int delete_branches(int argc, const char **argv, int force, int kinds,
|
|||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!(flags & REF_ISSYMREF) &&
|
if (!(flags & (REF_ISSYMREF|REF_ISBROKEN)) &&
|
||||||
check_branch_commit(bname.buf, name, sha1, head_rev, kinds,
|
check_branch_commit(bname.buf, name, sha1, head_rev, kinds,
|
||||||
force)) {
|
force)) {
|
||||||
ret = 1;
|
ret = 1;
|
||||||
@ -264,8 +268,8 @@ static int delete_branches(int argc, const char **argv, int force, int kinds,
|
|||||||
? _("Deleted remote branch %s (was %s).\n")
|
? _("Deleted remote branch %s (was %s).\n")
|
||||||
: _("Deleted branch %s (was %s).\n"),
|
: _("Deleted branch %s (was %s).\n"),
|
||||||
bname.buf,
|
bname.buf,
|
||||||
(flags & REF_ISSYMREF)
|
(flags & REF_ISBROKEN) ? "broken"
|
||||||
? target
|
: (flags & REF_ISSYMREF) ? target
|
||||||
: find_unique_abbrev(sha1, DEFAULT_ABBREV));
|
: find_unique_abbrev(sha1, DEFAULT_ABBREV));
|
||||||
}
|
}
|
||||||
delete_branch_config(bname.buf);
|
delete_branch_config(bname.buf);
|
||||||
@ -298,7 +302,7 @@ static char *resolve_symref(const char *src, const char *prefix)
|
|||||||
int flag;
|
int flag;
|
||||||
const char *dst;
|
const char *dst;
|
||||||
|
|
||||||
dst = resolve_ref_unsafe(src, sha1, 0, &flag);
|
dst = resolve_ref_unsafe(src, 0, sha1, &flag);
|
||||||
if (!(dst && (flag & REF_ISSYMREF)))
|
if (!(dst && (flag & REF_ISSYMREF)))
|
||||||
return NULL;
|
return NULL;
|
||||||
if (prefix)
|
if (prefix)
|
||||||
@ -868,7 +872,7 @@ int cmd_branch(int argc, const char **argv, const char *prefix)
|
|||||||
|
|
||||||
track = git_branch_track;
|
track = git_branch_track;
|
||||||
|
|
||||||
head = resolve_refdup("HEAD", head_sha1, 0, NULL);
|
head = resolve_refdup("HEAD", 0, head_sha1, NULL);
|
||||||
if (!head)
|
if (!head)
|
||||||
die(_("Failed to resolve HEAD as a valid ref."));
|
die(_("Failed to resolve HEAD as a valid ref."));
|
||||||
if (!strcmp(head, "HEAD"))
|
if (!strcmp(head, "HEAD"))
|
||||||
|
@ -355,7 +355,7 @@ static int checkout_paths(const struct checkout_opts *opts,
|
|||||||
if (write_locked_index(&the_index, lock_file, COMMIT_LOCK))
|
if (write_locked_index(&the_index, lock_file, COMMIT_LOCK))
|
||||||
die(_("unable to write new index file"));
|
die(_("unable to write new index file"));
|
||||||
|
|
||||||
read_ref_full("HEAD", rev, 0, &flag);
|
read_ref_full("HEAD", 0, rev, &flag);
|
||||||
head = lookup_commit_reference_gently(rev, 1);
|
head = lookup_commit_reference_gently(rev, 1);
|
||||||
|
|
||||||
errs |= post_checkout_hook(head, head, 0);
|
errs |= post_checkout_hook(head, head, 0);
|
||||||
@ -775,7 +775,7 @@ static int switch_branches(const struct checkout_opts *opts,
|
|||||||
unsigned char rev[20];
|
unsigned char rev[20];
|
||||||
int flag, writeout_error = 0;
|
int flag, writeout_error = 0;
|
||||||
memset(&old, 0, sizeof(old));
|
memset(&old, 0, sizeof(old));
|
||||||
old.path = path_to_free = resolve_refdup("HEAD", rev, 0, &flag);
|
old.path = path_to_free = resolve_refdup("HEAD", 0, rev, &flag);
|
||||||
old.commit = lookup_commit_reference_gently(rev, 1);
|
old.commit = lookup_commit_reference_gently(rev, 1);
|
||||||
if (!(flag & REF_ISSYMREF))
|
if (!(flag & REF_ISSYMREF))
|
||||||
old.path = NULL;
|
old.path = NULL;
|
||||||
@ -1072,7 +1072,7 @@ static int checkout_branch(struct checkout_opts *opts,
|
|||||||
unsigned char rev[20];
|
unsigned char rev[20];
|
||||||
int flag;
|
int flag;
|
||||||
|
|
||||||
if (!read_ref_full("HEAD", rev, 0, &flag) &&
|
if (!read_ref_full("HEAD", 0, rev, &flag) &&
|
||||||
(flag & REF_ISSYMREF) && is_null_sha1(rev))
|
(flag & REF_ISSYMREF) && is_null_sha1(rev))
|
||||||
return switch_unborn_to_new_branch(opts);
|
return switch_unborn_to_new_branch(opts);
|
||||||
}
|
}
|
||||||
|
@ -623,7 +623,7 @@ static int checkout(void)
|
|||||||
if (option_no_checkout)
|
if (option_no_checkout)
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
head = resolve_refdup("HEAD", sha1, 1, NULL);
|
head = resolve_refdup("HEAD", RESOLVE_REF_READING, sha1, NULL);
|
||||||
if (!head) {
|
if (!head) {
|
||||||
warning(_("remote HEAD refers to nonexistent ref, "
|
warning(_("remote HEAD refers to nonexistent ref, "
|
||||||
"unable to checkout.\n"));
|
"unable to checkout.\n"));
|
||||||
|
@ -1513,7 +1513,7 @@ static void print_summary(const char *prefix, const unsigned char *sha1,
|
|||||||
rev.diffopt.break_opt = 0;
|
rev.diffopt.break_opt = 0;
|
||||||
diff_setup_done(&rev.diffopt);
|
diff_setup_done(&rev.diffopt);
|
||||||
|
|
||||||
head = resolve_ref_unsafe("HEAD", junk_sha1, 0, NULL);
|
head = resolve_ref_unsafe("HEAD", 0, junk_sha1, NULL);
|
||||||
if (!strcmp(head, "HEAD"))
|
if (!strcmp(head, "HEAD"))
|
||||||
head = _("detached HEAD");
|
head = _("detached HEAD");
|
||||||
else
|
else
|
||||||
@ -1809,8 +1809,8 @@ int cmd_commit(int argc, const char **argv, const char *prefix)
|
|||||||
ref_transaction_update(transaction, "HEAD", sha1,
|
ref_transaction_update(transaction, "HEAD", sha1,
|
||||||
current_head
|
current_head
|
||||||
? current_head->object.sha1 : NULL,
|
? current_head->object.sha1 : NULL,
|
||||||
0, !!current_head, &err) ||
|
0, !!current_head, sb.buf, &err) ||
|
||||||
ref_transaction_commit(transaction, sb.buf, &err)) {
|
ref_transaction_commit(transaction, &err)) {
|
||||||
rollback_index_files();
|
rollback_index_files();
|
||||||
die("%s", err.buf);
|
die("%s", err.buf);
|
||||||
}
|
}
|
||||||
|
@ -404,23 +404,37 @@ static int s_update_ref(const char *action,
|
|||||||
{
|
{
|
||||||
char msg[1024];
|
char msg[1024];
|
||||||
char *rla = getenv("GIT_REFLOG_ACTION");
|
char *rla = getenv("GIT_REFLOG_ACTION");
|
||||||
static struct ref_lock *lock;
|
struct ref_transaction *transaction;
|
||||||
|
struct strbuf err = STRBUF_INIT;
|
||||||
|
int ret, df_conflict = 0;
|
||||||
|
|
||||||
if (dry_run)
|
if (dry_run)
|
||||||
return 0;
|
return 0;
|
||||||
if (!rla)
|
if (!rla)
|
||||||
rla = default_rla.buf;
|
rla = default_rla.buf;
|
||||||
snprintf(msg, sizeof(msg), "%s: %s", rla, action);
|
snprintf(msg, sizeof(msg), "%s: %s", rla, action);
|
||||||
lock = lock_any_ref_for_update(ref->name,
|
|
||||||
check_old ? ref->old_sha1 : NULL,
|
transaction = ref_transaction_begin(&err);
|
||||||
0, NULL);
|
if (!transaction ||
|
||||||
if (!lock)
|
ref_transaction_update(transaction, ref->name, ref->new_sha1,
|
||||||
return errno == ENOTDIR ? STORE_REF_ERROR_DF_CONFLICT :
|
ref->old_sha1, 0, check_old, msg, &err))
|
||||||
STORE_REF_ERROR_OTHER;
|
goto fail;
|
||||||
if (write_ref_sha1(lock, ref->new_sha1, msg) < 0)
|
|
||||||
return errno == ENOTDIR ? STORE_REF_ERROR_DF_CONFLICT :
|
ret = ref_transaction_commit(transaction, &err);
|
||||||
STORE_REF_ERROR_OTHER;
|
if (ret) {
|
||||||
|
df_conflict = (ret == TRANSACTION_NAME_CONFLICT);
|
||||||
|
goto fail;
|
||||||
|
}
|
||||||
|
|
||||||
|
ref_transaction_free(transaction);
|
||||||
|
strbuf_release(&err);
|
||||||
return 0;
|
return 0;
|
||||||
|
fail:
|
||||||
|
ref_transaction_free(transaction);
|
||||||
|
error("%s", err.buf);
|
||||||
|
strbuf_release(&err);
|
||||||
|
return df_conflict ? STORE_REF_ERROR_DF_CONFLICT
|
||||||
|
: STORE_REF_ERROR_OTHER;
|
||||||
}
|
}
|
||||||
|
|
||||||
#define REFCOL_WIDTH 10
|
#define REFCOL_WIDTH 10
|
||||||
|
@ -602,7 +602,7 @@ int fmt_merge_msg(struct strbuf *in, struct strbuf *out,
|
|||||||
|
|
||||||
/* get current branch */
|
/* get current branch */
|
||||||
current_branch = current_branch_to_free =
|
current_branch = current_branch_to_free =
|
||||||
resolve_refdup("HEAD", head_sha1, 1, NULL);
|
resolve_refdup("HEAD", RESOLVE_REF_READING, head_sha1, NULL);
|
||||||
if (!current_branch)
|
if (!current_branch)
|
||||||
die("No current branch");
|
die("No current branch");
|
||||||
if (starts_with(current_branch, "refs/heads/"))
|
if (starts_with(current_branch, "refs/heads/"))
|
||||||
|
@ -635,7 +635,8 @@ static void populate_value(struct refinfo *ref)
|
|||||||
|
|
||||||
if (need_symref && (ref->flag & REF_ISSYMREF) && !ref->symref) {
|
if (need_symref && (ref->flag & REF_ISSYMREF) && !ref->symref) {
|
||||||
unsigned char unused1[20];
|
unsigned char unused1[20];
|
||||||
ref->symref = resolve_refdup(ref->refname, unused1, 1, NULL);
|
ref->symref = resolve_refdup(ref->refname, RESOLVE_REF_READING,
|
||||||
|
unused1, NULL);
|
||||||
if (!ref->symref)
|
if (!ref->symref)
|
||||||
ref->symref = "";
|
ref->symref = "";
|
||||||
}
|
}
|
||||||
@ -694,7 +695,8 @@ static void populate_value(struct refinfo *ref)
|
|||||||
const char *head;
|
const char *head;
|
||||||
unsigned char sha1[20];
|
unsigned char sha1[20];
|
||||||
|
|
||||||
head = resolve_ref_unsafe("HEAD", sha1, 1, NULL);
|
head = resolve_ref_unsafe("HEAD", RESOLVE_REF_READING,
|
||||||
|
sha1, NULL);
|
||||||
if (!strcmp(ref->refname, head))
|
if (!strcmp(ref->refname, head))
|
||||||
v->s = "*";
|
v->s = "*";
|
||||||
else
|
else
|
||||||
@ -838,6 +840,11 @@ static int grab_single_ref(const char *refname, const unsigned char *sha1, int f
|
|||||||
struct refinfo *ref;
|
struct refinfo *ref;
|
||||||
int cnt;
|
int cnt;
|
||||||
|
|
||||||
|
if (flag & REF_BAD_NAME) {
|
||||||
|
warning("ignoring ref with broken name %s", refname);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
if (*cb->grab_pattern) {
|
if (*cb->grab_pattern) {
|
||||||
const char **pattern;
|
const char **pattern;
|
||||||
int namelen = strlen(refname);
|
int namelen = strlen(refname);
|
||||||
|
@ -556,7 +556,7 @@ static int fsck_head_link(void)
|
|||||||
if (verbose)
|
if (verbose)
|
||||||
fprintf(stderr, "Checking HEAD link\n");
|
fprintf(stderr, "Checking HEAD link\n");
|
||||||
|
|
||||||
head_points_at = resolve_ref_unsafe("HEAD", head_sha1, 0, &flag);
|
head_points_at = resolve_ref_unsafe("HEAD", 0, head_sha1, &flag);
|
||||||
if (!head_points_at)
|
if (!head_points_at)
|
||||||
return error("Invalid HEAD");
|
return error("Invalid HEAD");
|
||||||
if (!strcmp(head_points_at, "HEAD"))
|
if (!strcmp(head_points_at, "HEAD"))
|
||||||
|
@ -1400,7 +1400,8 @@ int cmd_format_patch(int argc, const char **argv, const char *prefix)
|
|||||||
if (check_head) {
|
if (check_head) {
|
||||||
unsigned char sha1[20];
|
unsigned char sha1[20];
|
||||||
const char *ref, *v;
|
const char *ref, *v;
|
||||||
ref = resolve_ref_unsafe("HEAD", sha1, 1, NULL);
|
ref = resolve_ref_unsafe("HEAD", RESOLVE_REF_READING,
|
||||||
|
sha1, NULL);
|
||||||
if (ref && skip_prefix(ref, "refs/heads/", &v))
|
if (ref && skip_prefix(ref, "refs/heads/", &v))
|
||||||
branch_name = xstrdup(v);
|
branch_name = xstrdup(v);
|
||||||
else
|
else
|
||||||
|
@ -1101,7 +1101,7 @@ int cmd_merge(int argc, const char **argv, const char *prefix)
|
|||||||
* Check if we are _not_ on a detached HEAD, i.e. if there is a
|
* Check if we are _not_ on a detached HEAD, i.e. if there is a
|
||||||
* current branch.
|
* current branch.
|
||||||
*/
|
*/
|
||||||
branch = branch_to_free = resolve_refdup("HEAD", head_sha1, 0, &flag);
|
branch = branch_to_free = resolve_refdup("HEAD", 0, head_sha1, &flag);
|
||||||
if (branch && starts_with(branch, "refs/heads/"))
|
if (branch && starts_with(branch, "refs/heads/"))
|
||||||
branch += 11;
|
branch += 11;
|
||||||
if (!branch || is_null_sha1(head_sha1))
|
if (!branch || is_null_sha1(head_sha1))
|
||||||
|
@ -702,7 +702,7 @@ static int merge_commit(struct notes_merge_options *o)
|
|||||||
init_notes(t, "NOTES_MERGE_PARTIAL", combine_notes_overwrite, 0);
|
init_notes(t, "NOTES_MERGE_PARTIAL", combine_notes_overwrite, 0);
|
||||||
|
|
||||||
o->local_ref = local_ref_to_free =
|
o->local_ref = local_ref_to_free =
|
||||||
resolve_refdup("NOTES_MERGE_REF", sha1, 0, NULL);
|
resolve_refdup("NOTES_MERGE_REF", 0, sha1, NULL);
|
||||||
if (!o->local_ref)
|
if (!o->local_ref)
|
||||||
die("Failed to resolve NOTES_MERGE_REF");
|
die("Failed to resolve NOTES_MERGE_REF");
|
||||||
|
|
||||||
|
@ -842,8 +842,9 @@ static const char *update(struct command *cmd, struct shallow_info *si)
|
|||||||
transaction = ref_transaction_begin(&err);
|
transaction = ref_transaction_begin(&err);
|
||||||
if (!transaction ||
|
if (!transaction ||
|
||||||
ref_transaction_update(transaction, namespaced_name,
|
ref_transaction_update(transaction, namespaced_name,
|
||||||
new_sha1, old_sha1, 0, 1, &err) ||
|
new_sha1, old_sha1, 0, 1, "push",
|
||||||
ref_transaction_commit(transaction, "push", &err)) {
|
&err) ||
|
||||||
|
ref_transaction_commit(transaction, &err)) {
|
||||||
ref_transaction_free(transaction);
|
ref_transaction_free(transaction);
|
||||||
|
|
||||||
rp_error("%s", err.buf);
|
rp_error("%s", err.buf);
|
||||||
@ -908,7 +909,7 @@ static void check_aliased_update(struct command *cmd, struct string_list *list)
|
|||||||
int flag;
|
int flag;
|
||||||
|
|
||||||
strbuf_addf(&buf, "%s%s", get_git_namespace(), cmd->ref_name);
|
strbuf_addf(&buf, "%s%s", get_git_namespace(), cmd->ref_name);
|
||||||
dst_name = resolve_ref_unsafe(buf.buf, sha1, 0, &flag);
|
dst_name = resolve_ref_unsafe(buf.buf, 0, sha1, &flag);
|
||||||
strbuf_release(&buf);
|
strbuf_release(&buf);
|
||||||
|
|
||||||
if (!(flag & REF_ISSYMREF))
|
if (!(flag & REF_ISSYMREF))
|
||||||
@ -1069,7 +1070,7 @@ static void execute_commands(struct command *commands,
|
|||||||
check_aliased_updates(commands);
|
check_aliased_updates(commands);
|
||||||
|
|
||||||
free(head_name_to_free);
|
free(head_name_to_free);
|
||||||
head_name = head_name_to_free = resolve_refdup("HEAD", sha1, 0, NULL);
|
head_name = head_name_to_free = resolve_refdup("HEAD", 0, sha1, NULL);
|
||||||
|
|
||||||
checked_connectivity = 1;
|
checked_connectivity = 1;
|
||||||
for (cmd = commands; cmd; cmd = cmd->next) {
|
for (cmd = commands; cmd; cmd = cmd->next) {
|
||||||
|
@ -567,7 +567,8 @@ static int read_remote_branches(const char *refname,
|
|||||||
strbuf_addf(&buf, "refs/remotes/%s/", rename->old);
|
strbuf_addf(&buf, "refs/remotes/%s/", rename->old);
|
||||||
if (starts_with(refname, buf.buf)) {
|
if (starts_with(refname, buf.buf)) {
|
||||||
item = string_list_append(rename->remote_branches, xstrdup(refname));
|
item = string_list_append(rename->remote_branches, xstrdup(refname));
|
||||||
symref = resolve_ref_unsafe(refname, orig_sha1, 1, &flag);
|
symref = resolve_ref_unsafe(refname, RESOLVE_REF_READING,
|
||||||
|
orig_sha1, &flag);
|
||||||
if (flag & REF_ISSYMREF)
|
if (flag & REF_ISSYMREF)
|
||||||
item->util = xstrdup(symref);
|
item->util = xstrdup(symref);
|
||||||
else
|
else
|
||||||
@ -703,7 +704,7 @@ static int mv(int argc, const char **argv)
|
|||||||
int flag = 0;
|
int flag = 0;
|
||||||
unsigned char sha1[20];
|
unsigned char sha1[20];
|
||||||
|
|
||||||
read_ref_full(item->string, sha1, 1, &flag);
|
read_ref_full(item->string, RESOLVE_REF_READING, sha1, &flag);
|
||||||
if (!(flag & REF_ISSYMREF))
|
if (!(flag & REF_ISSYMREF))
|
||||||
continue;
|
continue;
|
||||||
if (delete_ref(item->string, NULL, REF_NODEREF))
|
if (delete_ref(item->string, NULL, REF_NODEREF))
|
||||||
@ -748,13 +749,16 @@ static int mv(int argc, const char **argv)
|
|||||||
|
|
||||||
static int remove_branches(struct string_list *branches)
|
static int remove_branches(struct string_list *branches)
|
||||||
{
|
{
|
||||||
|
struct strbuf err = STRBUF_INIT;
|
||||||
const char **branch_names;
|
const char **branch_names;
|
||||||
int i, result = 0;
|
int i, result = 0;
|
||||||
|
|
||||||
branch_names = xmalloc(branches->nr * sizeof(*branch_names));
|
branch_names = xmalloc(branches->nr * sizeof(*branch_names));
|
||||||
for (i = 0; i < branches->nr; i++)
|
for (i = 0; i < branches->nr; i++)
|
||||||
branch_names[i] = branches->items[i].string;
|
branch_names[i] = branches->items[i].string;
|
||||||
result |= repack_without_refs(branch_names, branches->nr, NULL);
|
if (repack_without_refs(branch_names, branches->nr, &err))
|
||||||
|
result |= error("%s", err.buf);
|
||||||
|
strbuf_release(&err);
|
||||||
free(branch_names);
|
free(branch_names);
|
||||||
|
|
||||||
for (i = 0; i < branches->nr; i++) {
|
for (i = 0; i < branches->nr; i++) {
|
||||||
@ -1331,9 +1335,13 @@ static int prune_remote(const char *remote, int dry_run)
|
|||||||
delete_refs = xmalloc(states.stale.nr * sizeof(*delete_refs));
|
delete_refs = xmalloc(states.stale.nr * sizeof(*delete_refs));
|
||||||
for (i = 0; i < states.stale.nr; i++)
|
for (i = 0; i < states.stale.nr; i++)
|
||||||
delete_refs[i] = states.stale.items[i].util;
|
delete_refs[i] = states.stale.items[i].util;
|
||||||
if (!dry_run)
|
if (!dry_run) {
|
||||||
result |= repack_without_refs(delete_refs,
|
struct strbuf err = STRBUF_INIT;
|
||||||
states.stale.nr, NULL);
|
if (repack_without_refs(delete_refs, states.stale.nr,
|
||||||
|
&err))
|
||||||
|
result |= error("%s", err.buf);
|
||||||
|
strbuf_release(&err);
|
||||||
|
}
|
||||||
free(delete_refs);
|
free(delete_refs);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -171,8 +171,9 @@ static int replace_object_sha1(const char *object_ref,
|
|||||||
|
|
||||||
transaction = ref_transaction_begin(&err);
|
transaction = ref_transaction_begin(&err);
|
||||||
if (!transaction ||
|
if (!transaction ||
|
||||||
ref_transaction_update(transaction, ref, repl, prev, 0, 1, &err) ||
|
ref_transaction_update(transaction, ref, repl, prev,
|
||||||
ref_transaction_commit(transaction, NULL, &err))
|
0, 1, NULL, &err) ||
|
||||||
|
ref_transaction_commit(transaction, &err))
|
||||||
die("%s", err.buf);
|
die("%s", err.buf);
|
||||||
|
|
||||||
ref_transaction_free(transaction);
|
ref_transaction_free(transaction);
|
||||||
|
@ -728,7 +728,9 @@ int cmd_show_branch(int ac, const char **av, const char *prefix)
|
|||||||
if (ac == 0) {
|
if (ac == 0) {
|
||||||
static const char *fake_av[2];
|
static const char *fake_av[2];
|
||||||
|
|
||||||
fake_av[0] = resolve_refdup("HEAD", sha1, 1, NULL);
|
fake_av[0] = resolve_refdup("HEAD",
|
||||||
|
RESOLVE_REF_READING,
|
||||||
|
sha1, NULL);
|
||||||
fake_av[1] = NULL;
|
fake_av[1] = NULL;
|
||||||
av = fake_av;
|
av = fake_av;
|
||||||
ac = 1;
|
ac = 1;
|
||||||
@ -789,7 +791,8 @@ int cmd_show_branch(int ac, const char **av, const char *prefix)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
head_p = resolve_ref_unsafe("HEAD", head_sha1, 1, NULL);
|
head_p = resolve_ref_unsafe("HEAD", RESOLVE_REF_READING,
|
||||||
|
head_sha1, NULL);
|
||||||
if (head_p) {
|
if (head_p) {
|
||||||
head_len = strlen(head_p);
|
head_len = strlen(head_p);
|
||||||
memcpy(head, head_p, head_len + 1);
|
memcpy(head, head_p, head_len + 1);
|
||||||
|
@ -13,7 +13,7 @@ static int check_symref(const char *HEAD, int quiet, int shorten, int print)
|
|||||||
{
|
{
|
||||||
unsigned char sha1[20];
|
unsigned char sha1[20];
|
||||||
int flag;
|
int flag;
|
||||||
const char *refname = resolve_ref_unsafe(HEAD, sha1, 0, &flag);
|
const char *refname = resolve_ref_unsafe(HEAD, 0, sha1, &flag);
|
||||||
|
|
||||||
if (!refname)
|
if (!refname)
|
||||||
die("No such ref: %s", HEAD);
|
die("No such ref: %s", HEAD);
|
||||||
|
@ -733,8 +733,8 @@ int cmd_tag(int argc, const char **argv, const char *prefix)
|
|||||||
transaction = ref_transaction_begin(&err);
|
transaction = ref_transaction_begin(&err);
|
||||||
if (!transaction ||
|
if (!transaction ||
|
||||||
ref_transaction_update(transaction, ref.buf, object, prev,
|
ref_transaction_update(transaction, ref.buf, object, prev,
|
||||||
0, 1, &err) ||
|
0, 1, NULL, &err) ||
|
||||||
ref_transaction_commit(transaction, NULL, &err))
|
ref_transaction_commit(transaction, &err))
|
||||||
die("%s", err.buf);
|
die("%s", err.buf);
|
||||||
ref_transaction_free(transaction);
|
ref_transaction_free(transaction);
|
||||||
if (force && !is_null_sha1(prev) && hashcmp(prev, object))
|
if (force && !is_null_sha1(prev) && hashcmp(prev, object))
|
||||||
|
@ -14,6 +14,7 @@ static const char * const git_update_ref_usage[] = {
|
|||||||
|
|
||||||
static char line_termination = '\n';
|
static char line_termination = '\n';
|
||||||
static int update_flags;
|
static int update_flags;
|
||||||
|
static const char *msg;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Parse one whitespace- or NUL-terminated, possibly C-quoted argument
|
* Parse one whitespace- or NUL-terminated, possibly C-quoted argument
|
||||||
@ -198,7 +199,7 @@ static const char *parse_cmd_update(struct ref_transaction *transaction,
|
|||||||
die("update %s: extra input: %s", refname, next);
|
die("update %s: extra input: %s", refname, next);
|
||||||
|
|
||||||
if (ref_transaction_update(transaction, refname, new_sha1, old_sha1,
|
if (ref_transaction_update(transaction, refname, new_sha1, old_sha1,
|
||||||
update_flags, have_old, &err))
|
update_flags, have_old, msg, &err))
|
||||||
die("%s", err.buf);
|
die("%s", err.buf);
|
||||||
|
|
||||||
update_flags = 0;
|
update_flags = 0;
|
||||||
@ -229,7 +230,7 @@ static const char *parse_cmd_create(struct ref_transaction *transaction,
|
|||||||
die("create %s: extra input: %s", refname, next);
|
die("create %s: extra input: %s", refname, next);
|
||||||
|
|
||||||
if (ref_transaction_create(transaction, refname, new_sha1,
|
if (ref_transaction_create(transaction, refname, new_sha1,
|
||||||
update_flags, &err))
|
update_flags, msg, &err))
|
||||||
die("%s", err.buf);
|
die("%s", err.buf);
|
||||||
|
|
||||||
update_flags = 0;
|
update_flags = 0;
|
||||||
@ -264,7 +265,7 @@ static const char *parse_cmd_delete(struct ref_transaction *transaction,
|
|||||||
die("delete %s: extra input: %s", refname, next);
|
die("delete %s: extra input: %s", refname, next);
|
||||||
|
|
||||||
if (ref_transaction_delete(transaction, refname, old_sha1,
|
if (ref_transaction_delete(transaction, refname, old_sha1,
|
||||||
update_flags, have_old, &err))
|
update_flags, have_old, msg, &err))
|
||||||
die("%s", err.buf);
|
die("%s", err.buf);
|
||||||
|
|
||||||
update_flags = 0;
|
update_flags = 0;
|
||||||
@ -300,7 +301,7 @@ static const char *parse_cmd_verify(struct ref_transaction *transaction,
|
|||||||
die("verify %s: extra input: %s", refname, next);
|
die("verify %s: extra input: %s", refname, next);
|
||||||
|
|
||||||
if (ref_transaction_update(transaction, refname, new_sha1, old_sha1,
|
if (ref_transaction_update(transaction, refname, new_sha1, old_sha1,
|
||||||
update_flags, have_old, &err))
|
update_flags, have_old, msg, &err))
|
||||||
die("%s", err.buf);
|
die("%s", err.buf);
|
||||||
|
|
||||||
update_flags = 0;
|
update_flags = 0;
|
||||||
@ -354,7 +355,7 @@ static void update_refs_stdin(struct ref_transaction *transaction)
|
|||||||
|
|
||||||
int cmd_update_ref(int argc, const char **argv, const char *prefix)
|
int cmd_update_ref(int argc, const char **argv, const char *prefix)
|
||||||
{
|
{
|
||||||
const char *refname, *oldval, *msg = NULL;
|
const char *refname, *oldval;
|
||||||
unsigned char sha1[20], oldsha1[20];
|
unsigned char sha1[20], oldsha1[20];
|
||||||
int delete = 0, no_deref = 0, read_stdin = 0, end_null = 0, flags = 0;
|
int delete = 0, no_deref = 0, read_stdin = 0, end_null = 0, flags = 0;
|
||||||
struct option options[] = {
|
struct option options[] = {
|
||||||
@ -385,7 +386,7 @@ int cmd_update_ref(int argc, const char **argv, const char *prefix)
|
|||||||
if (end_null)
|
if (end_null)
|
||||||
line_termination = '\0';
|
line_termination = '\0';
|
||||||
update_refs_stdin(transaction);
|
update_refs_stdin(transaction);
|
||||||
if (ref_transaction_commit(transaction, msg, &err))
|
if (ref_transaction_commit(transaction, &err))
|
||||||
die("%s", err.buf);
|
die("%s", err.buf);
|
||||||
ref_transaction_free(transaction);
|
ref_transaction_free(transaction);
|
||||||
strbuf_release(&err);
|
strbuf_release(&err);
|
||||||
|
2
bundle.c
2
bundle.c
@ -310,7 +310,7 @@ int create_bundle(struct bundle_header *header, const char *path,
|
|||||||
continue;
|
continue;
|
||||||
if (dwim_ref(e->name, strlen(e->name), sha1, &ref) != 1)
|
if (dwim_ref(e->name, strlen(e->name), sha1, &ref) != 1)
|
||||||
continue;
|
continue;
|
||||||
if (read_ref_full(e->name, sha1, 1, &flag))
|
if (read_ref_full(e->name, RESOLVE_REF_READING, sha1, &flag))
|
||||||
flag = 0;
|
flag = 0;
|
||||||
display_ref = (flag & REF_ISSYMREF) ? e->name : ref;
|
display_ref = (flag & REF_ISSYMREF) ? e->name : ref;
|
||||||
|
|
||||||
|
44
cache.h
44
cache.h
@ -950,8 +950,8 @@ extern int for_each_abbrev(const char *prefix, each_abbrev_fn, void *);
|
|||||||
extern int get_sha1_hex(const char *hex, unsigned char *sha1);
|
extern int get_sha1_hex(const char *hex, unsigned char *sha1);
|
||||||
|
|
||||||
extern char *sha1_to_hex(const unsigned char *sha1); /* static buffer result! */
|
extern char *sha1_to_hex(const unsigned char *sha1); /* static buffer result! */
|
||||||
extern int read_ref_full(const char *refname, unsigned char *sha1,
|
extern int read_ref_full(const char *refname, int resolve_flags,
|
||||||
int reading, int *flags);
|
unsigned char *sha1, int *flags);
|
||||||
extern int read_ref(const char *refname, unsigned char *sha1);
|
extern int read_ref(const char *refname, unsigned char *sha1);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@ -963,29 +963,49 @@ extern int read_ref(const char *refname, unsigned char *sha1);
|
|||||||
* or the input ref.
|
* or the input ref.
|
||||||
*
|
*
|
||||||
* If the reference cannot be resolved to an object, the behavior
|
* If the reference cannot be resolved to an object, the behavior
|
||||||
* depends on the "reading" argument:
|
* depends on the RESOLVE_REF_READING flag:
|
||||||
*
|
*
|
||||||
* - If reading is set, return NULL.
|
* - If RESOLVE_REF_READING is set, return NULL.
|
||||||
*
|
*
|
||||||
* - If reading is not set, clear sha1 and return the name of the last
|
* - If RESOLVE_REF_READING is not set, clear sha1 and return the name of
|
||||||
* reference name in the chain, which will either be a non-symbolic
|
* the last reference name in the chain, which will either be a non-symbolic
|
||||||
* reference or an undefined reference. If this is a prelude to
|
* reference or an undefined reference. If this is a prelude to
|
||||||
* "writing" to the ref, the return value is the name of the ref
|
* "writing" to the ref, the return value is the name of the ref
|
||||||
* that will actually be created or changed.
|
* that will actually be created or changed.
|
||||||
*
|
*
|
||||||
* If flag is non-NULL, set the value that it points to the
|
* If the RESOLVE_REF_NO_RECURSE flag is passed, only resolves one
|
||||||
|
* level of symbolic reference. The value stored in sha1 for a symbolic
|
||||||
|
* reference will always be null_sha1 in this case, and the return
|
||||||
|
* value is the reference that the symref refers to directly.
|
||||||
|
*
|
||||||
|
* If flags is non-NULL, set the value that it points to the
|
||||||
* combination of REF_ISPACKED (if the reference was found among the
|
* combination of REF_ISPACKED (if the reference was found among the
|
||||||
* packed references) and REF_ISSYMREF (if the initial reference was a
|
* packed references), REF_ISSYMREF (if the initial reference was a
|
||||||
* symbolic reference).
|
* symbolic reference), REF_BAD_NAME (if the reference name is ill
|
||||||
|
* formed --- see RESOLVE_REF_ALLOW_BAD_NAME below), and REF_ISBROKEN
|
||||||
|
* (if the ref is malformed or has a bad name). See refs.h for more detail
|
||||||
|
* on each flag.
|
||||||
*
|
*
|
||||||
* If ref is not a properly-formatted, normalized reference, return
|
* If ref is not a properly-formatted, normalized reference, return
|
||||||
* NULL. If more than MAXDEPTH recursive symbolic lookups are needed,
|
* NULL. If more than MAXDEPTH recursive symbolic lookups are needed,
|
||||||
* give up and return NULL.
|
* give up and return NULL.
|
||||||
*
|
*
|
||||||
* errno is set to something meaningful on error.
|
* RESOLVE_REF_ALLOW_BAD_NAME allows resolving refs even when their
|
||||||
|
* name is invalid according to git-check-ref-format(1). If the name
|
||||||
|
* is bad then the value stored in sha1 will be null_sha1 and the two
|
||||||
|
* flags REF_ISBROKEN and REF_BAD_NAME will be set.
|
||||||
|
*
|
||||||
|
* Even with RESOLVE_REF_ALLOW_BAD_NAME, names that escape the refs/
|
||||||
|
* directory and do not consist of all caps and underscores cannot be
|
||||||
|
* resolved. The function returns NULL for such ref names.
|
||||||
|
* Caps and underscores refers to the special refs, such as HEAD,
|
||||||
|
* FETCH_HEAD and friends, that all live outside of the refs/ directory.
|
||||||
*/
|
*/
|
||||||
extern const char *resolve_ref_unsafe(const char *ref, unsigned char *sha1, int reading, int *flag);
|
#define RESOLVE_REF_READING 0x01
|
||||||
extern char *resolve_refdup(const char *ref, unsigned char *sha1, int reading, int *flag);
|
#define RESOLVE_REF_NO_RECURSE 0x02
|
||||||
|
#define RESOLVE_REF_ALLOW_BAD_NAME 0x04
|
||||||
|
extern const char *resolve_ref_unsafe(const char *ref, int resolve_flags, unsigned char *sha1, int *flags);
|
||||||
|
extern char *resolve_refdup(const char *ref, int resolve_flags, unsigned char *sha1, int *flags);
|
||||||
|
|
||||||
extern int dwim_ref(const char *str, int len, unsigned char *sha1, char **ref);
|
extern int dwim_ref(const char *str, int len, unsigned char *sha1, char **ref);
|
||||||
extern int dwim_log(const char *str, int len, unsigned char *sha1, char **ref);
|
extern int dwim_log(const char *str, int len, unsigned char *sha1, char **ref);
|
||||||
|
@ -1716,8 +1716,8 @@ static int update_branch(struct branch *b)
|
|||||||
transaction = ref_transaction_begin(&err);
|
transaction = ref_transaction_begin(&err);
|
||||||
if (!transaction ||
|
if (!transaction ||
|
||||||
ref_transaction_update(transaction, b->name, b->sha1, old_sha1,
|
ref_transaction_update(transaction, b->name, b->sha1, old_sha1,
|
||||||
0, 1, &err) ||
|
0, 1, msg, &err) ||
|
||||||
ref_transaction_commit(transaction, msg, &err)) {
|
ref_transaction_commit(transaction, &err)) {
|
||||||
ref_transaction_free(transaction);
|
ref_transaction_free(transaction);
|
||||||
error("%s", err.buf);
|
error("%s", err.buf);
|
||||||
strbuf_release(&err);
|
strbuf_release(&err);
|
||||||
@ -1757,12 +1757,12 @@ static void dump_tags(void)
|
|||||||
strbuf_addf(&ref_name, "refs/tags/%s", t->name);
|
strbuf_addf(&ref_name, "refs/tags/%s", t->name);
|
||||||
|
|
||||||
if (ref_transaction_update(transaction, ref_name.buf, t->sha1,
|
if (ref_transaction_update(transaction, ref_name.buf, t->sha1,
|
||||||
NULL, 0, 0, &err)) {
|
NULL, 0, 0, msg, &err)) {
|
||||||
failure |= error("%s", err.buf);
|
failure |= error("%s", err.buf);
|
||||||
goto cleanup;
|
goto cleanup;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (ref_transaction_commit(transaction, msg, &err))
|
if (ref_transaction_commit(transaction, &err))
|
||||||
failure |= error("%s", err.buf);
|
failure |= error("%s", err.buf);
|
||||||
|
|
||||||
cleanup:
|
cleanup:
|
||||||
|
@ -326,6 +326,8 @@ static inline char *git_find_last_dir_sep(const char *path)
|
|||||||
|
|
||||||
#include "wildmatch.h"
|
#include "wildmatch.h"
|
||||||
|
|
||||||
|
struct strbuf;
|
||||||
|
|
||||||
/* General helper functions */
|
/* General helper functions */
|
||||||
extern void vreportf(const char *prefix, const char *err, va_list params);
|
extern void vreportf(const char *prefix, const char *err, va_list params);
|
||||||
extern void vwritef(int fd, const char *prefix, const char *err, va_list params);
|
extern void vwritef(int fd, const char *prefix, const char *err, va_list params);
|
||||||
@ -777,11 +779,21 @@ void git_qsort(void *base, size_t nmemb, size_t size,
|
|||||||
|
|
||||||
/*
|
/*
|
||||||
* Preserves errno, prints a message, but gives no warning for ENOENT.
|
* Preserves errno, prints a message, but gives no warning for ENOENT.
|
||||||
* Always returns the return value of unlink(2).
|
* Returns 0 on success, which includes trying to unlink an object that does
|
||||||
|
* not exist.
|
||||||
*/
|
*/
|
||||||
int unlink_or_warn(const char *path);
|
int unlink_or_warn(const char *path);
|
||||||
|
/*
|
||||||
|
* Tries to unlink file. Returns 0 if unlink succeeded
|
||||||
|
* or the file already didn't exist. Returns -1 and
|
||||||
|
* appends a message to err suitable for
|
||||||
|
* 'error("%s", err->buf)' on error.
|
||||||
|
*/
|
||||||
|
int unlink_or_msg(const char *file, struct strbuf *err);
|
||||||
/*
|
/*
|
||||||
* Likewise for rmdir(2).
|
* Preserves errno, prints a message, but gives no warning for ENOENT.
|
||||||
|
* Returns 0 on success, which includes trying to remove a directory that does
|
||||||
|
* not exist.
|
||||||
*/
|
*/
|
||||||
int rmdir_or_warn(const char *path);
|
int rmdir_or_warn(const char *path);
|
||||||
/*
|
/*
|
||||||
|
@ -412,7 +412,9 @@ static int show_head_ref(const char *refname, const unsigned char *sha1,
|
|||||||
|
|
||||||
if (flag & REF_ISSYMREF) {
|
if (flag & REF_ISSYMREF) {
|
||||||
unsigned char unused[20];
|
unsigned char unused[20];
|
||||||
const char *target = resolve_ref_unsafe(refname, unused, 1, NULL);
|
const char *target = resolve_ref_unsafe(refname,
|
||||||
|
RESOLVE_REF_READING,
|
||||||
|
unused, NULL);
|
||||||
const char *target_nons = strip_namespace(target);
|
const char *target_nons = strip_namespace(target);
|
||||||
|
|
||||||
strbuf_addf(buf, "ref: %s\n", target_nons);
|
strbuf_addf(buf, "ref: %s\n", target_nons);
|
||||||
|
10
lockfile.c
10
lockfile.c
@ -162,16 +162,6 @@ void unable_to_lock_message(const char *path, int err, struct strbuf *buf)
|
|||||||
absolute_path(path), strerror(err));
|
absolute_path(path), strerror(err));
|
||||||
}
|
}
|
||||||
|
|
||||||
int unable_to_lock_error(const char *path, int err)
|
|
||||||
{
|
|
||||||
struct strbuf buf = STRBUF_INIT;
|
|
||||||
|
|
||||||
unable_to_lock_message(path, err, &buf);
|
|
||||||
error("%s", buf.buf);
|
|
||||||
strbuf_release(&buf);
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
NORETURN void unable_to_lock_die(const char *path, int err)
|
NORETURN void unable_to_lock_die(const char *path, int err)
|
||||||
{
|
{
|
||||||
struct strbuf buf = STRBUF_INIT;
|
struct strbuf buf = STRBUF_INIT;
|
||||||
|
@ -71,7 +71,6 @@ struct lock_file {
|
|||||||
#define LOCK_DIE_ON_ERROR 1
|
#define LOCK_DIE_ON_ERROR 1
|
||||||
#define LOCK_NO_DEREF 2
|
#define LOCK_NO_DEREF 2
|
||||||
|
|
||||||
extern int unable_to_lock_error(const char *path, int err);
|
|
||||||
extern void unable_to_lock_message(const char *path, int err,
|
extern void unable_to_lock_message(const char *path, int err,
|
||||||
struct strbuf *buf);
|
struct strbuf *buf);
|
||||||
extern NORETURN void unable_to_lock_die(const char *path, int err);
|
extern NORETURN void unable_to_lock_die(const char *path, int err);
|
||||||
|
@ -549,7 +549,7 @@ int notes_merge(struct notes_merge_options *o,
|
|||||||
o->local_ref, o->remote_ref);
|
o->local_ref, o->remote_ref);
|
||||||
|
|
||||||
/* Dereference o->local_ref into local_sha1 */
|
/* Dereference o->local_ref into local_sha1 */
|
||||||
if (read_ref_full(o->local_ref, local_sha1, 0, NULL))
|
if (read_ref_full(o->local_ref, 0, local_sha1, NULL))
|
||||||
die("Failed to resolve local notes ref '%s'", o->local_ref);
|
die("Failed to resolve local notes ref '%s'", o->local_ref);
|
||||||
else if (!check_refname_format(o->local_ref, 0) &&
|
else if (!check_refname_format(o->local_ref, 0) &&
|
||||||
is_null_sha1(local_sha1))
|
is_null_sha1(local_sha1))
|
||||||
|
@ -48,7 +48,8 @@ static struct complete_reflogs *read_complete_reflog(const char *ref)
|
|||||||
unsigned char sha1[20];
|
unsigned char sha1[20];
|
||||||
const char *name;
|
const char *name;
|
||||||
void *name_to_free;
|
void *name_to_free;
|
||||||
name = name_to_free = resolve_refdup(ref, sha1, 1, NULL);
|
name = name_to_free = resolve_refdup(ref, RESOLVE_REF_READING,
|
||||||
|
sha1, NULL);
|
||||||
if (name) {
|
if (name) {
|
||||||
for_each_reflog_ent(name, read_one_reflog, reflogs);
|
for_each_reflog_ent(name, read_one_reflog, reflogs);
|
||||||
free(name_to_free);
|
free(name_to_free);
|
||||||
@ -174,7 +175,7 @@ int add_reflog_for_walk(struct reflog_walk_info *info,
|
|||||||
if (*branch == '\0') {
|
if (*branch == '\0') {
|
||||||
unsigned char sha1[20];
|
unsigned char sha1[20];
|
||||||
free(branch);
|
free(branch);
|
||||||
branch = resolve_refdup("HEAD", sha1, 0, NULL);
|
branch = resolve_refdup("HEAD", 0, sha1, NULL);
|
||||||
if (!branch)
|
if (!branch)
|
||||||
die ("No current branch");
|
die ("No current branch");
|
||||||
|
|
||||||
|
410
refs.c
410
refs.c
@ -70,16 +70,8 @@ static int check_refname_component(const char *refname, int flags)
|
|||||||
out:
|
out:
|
||||||
if (cp == refname)
|
if (cp == refname)
|
||||||
return 0; /* Component has zero length. */
|
return 0; /* Component has zero length. */
|
||||||
if (refname[0] == '.') {
|
if (refname[0] == '.')
|
||||||
if (!(flags & REFNAME_DOT_COMPONENT))
|
|
||||||
return -1; /* Component starts with '.'. */
|
return -1; /* Component starts with '.'. */
|
||||||
/*
|
|
||||||
* Even if leading dots are allowed, don't allow "."
|
|
||||||
* as a component (".." is prevented by a rule above).
|
|
||||||
*/
|
|
||||||
if (refname[1] == '\0')
|
|
||||||
return -1; /* Component equals ".". */
|
|
||||||
}
|
|
||||||
if (cp - refname >= LOCK_SUFFIX_LEN &&
|
if (cp - refname >= LOCK_SUFFIX_LEN &&
|
||||||
!memcmp(cp - LOCK_SUFFIX_LEN, LOCK_SUFFIX, LOCK_SUFFIX_LEN))
|
!memcmp(cp - LOCK_SUFFIX_LEN, LOCK_SUFFIX, LOCK_SUFFIX_LEN))
|
||||||
return -1; /* Refname ends with ".lock". */
|
return -1; /* Refname ends with ".lock". */
|
||||||
@ -195,8 +187,8 @@ struct ref_dir {
|
|||||||
|
|
||||||
/*
|
/*
|
||||||
* Bit values for ref_entry::flag. REF_ISSYMREF=0x01,
|
* Bit values for ref_entry::flag. REF_ISSYMREF=0x01,
|
||||||
* REF_ISPACKED=0x02, and REF_ISBROKEN=0x04 are public values; see
|
* REF_ISPACKED=0x02, REF_ISBROKEN=0x04 and REF_BAD_NAME=0x08 are
|
||||||
* refs.h.
|
* public values; see refs.h.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@ -204,16 +196,16 @@ struct ref_dir {
|
|||||||
* the correct peeled value for the reference, which might be
|
* the correct peeled value for the reference, which might be
|
||||||
* null_sha1 if the reference is not a tag or if it is broken.
|
* null_sha1 if the reference is not a tag or if it is broken.
|
||||||
*/
|
*/
|
||||||
#define REF_KNOWS_PEELED 0x08
|
#define REF_KNOWS_PEELED 0x10
|
||||||
|
|
||||||
/* ref_entry represents a directory of references */
|
/* ref_entry represents a directory of references */
|
||||||
#define REF_DIR 0x10
|
#define REF_DIR 0x20
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Entry has not yet been read from disk (used only for REF_DIR
|
* Entry has not yet been read from disk (used only for REF_DIR
|
||||||
* entries representing loose references)
|
* entries representing loose references)
|
||||||
*/
|
*/
|
||||||
#define REF_INCOMPLETE 0x20
|
#define REF_INCOMPLETE 0x40
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* A ref_entry represents either a reference or a "subdirectory" of
|
* A ref_entry represents either a reference or a "subdirectory" of
|
||||||
@ -282,6 +274,39 @@ static struct ref_dir *get_ref_dir(struct ref_entry *entry)
|
|||||||
return dir;
|
return dir;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Check if a refname is safe.
|
||||||
|
* For refs that start with "refs/" we consider it safe as long they do
|
||||||
|
* not try to resolve to outside of refs/.
|
||||||
|
*
|
||||||
|
* For all other refs we only consider them safe iff they only contain
|
||||||
|
* upper case characters and '_' (like "HEAD" AND "MERGE_HEAD", and not like
|
||||||
|
* "config").
|
||||||
|
*/
|
||||||
|
static int refname_is_safe(const char *refname)
|
||||||
|
{
|
||||||
|
if (starts_with(refname, "refs/")) {
|
||||||
|
char *buf;
|
||||||
|
int result;
|
||||||
|
|
||||||
|
buf = xmalloc(strlen(refname) + 1);
|
||||||
|
/*
|
||||||
|
* Does the refname try to escape refs/?
|
||||||
|
* For example: refs/foo/../bar is safe but refs/foo/../../bar
|
||||||
|
* is not.
|
||||||
|
*/
|
||||||
|
result = !normalize_path_copy(buf, refname + strlen("refs/"));
|
||||||
|
free(buf);
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
while (*refname) {
|
||||||
|
if (!isupper(*refname) && *refname != '_')
|
||||||
|
return 0;
|
||||||
|
refname++;
|
||||||
|
}
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
static struct ref_entry *create_ref_entry(const char *refname,
|
static struct ref_entry *create_ref_entry(const char *refname,
|
||||||
const unsigned char *sha1, int flag,
|
const unsigned char *sha1, int flag,
|
||||||
int check_name)
|
int check_name)
|
||||||
@ -290,8 +315,10 @@ static struct ref_entry *create_ref_entry(const char *refname,
|
|||||||
struct ref_entry *ref;
|
struct ref_entry *ref;
|
||||||
|
|
||||||
if (check_name &&
|
if (check_name &&
|
||||||
check_refname_format(refname, REFNAME_ALLOW_ONELEVEL|REFNAME_DOT_COMPONENT))
|
check_refname_format(refname, REFNAME_ALLOW_ONELEVEL))
|
||||||
die("Reference has invalid format: '%s'", refname);
|
die("Reference has invalid format: '%s'", refname);
|
||||||
|
if (!check_name && !refname_is_safe(refname))
|
||||||
|
die("Reference has invalid name: '%s'", refname);
|
||||||
len = strlen(refname) + 1;
|
len = strlen(refname) + 1;
|
||||||
ref = xmalloc(sizeof(struct ref_entry) + len);
|
ref = xmalloc(sizeof(struct ref_entry) + len);
|
||||||
hashcpy(ref->u.value.sha1, sha1);
|
hashcpy(ref->u.value.sha1, sha1);
|
||||||
@ -787,13 +814,13 @@ static void prime_ref_dir(struct ref_dir *dir)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static int entry_matches(struct ref_entry *entry, const char *refname)
|
static int entry_matches(struct ref_entry *entry, const struct string_list *list)
|
||||||
{
|
{
|
||||||
return refname && !strcmp(entry->name, refname);
|
return list && string_list_has_string(list, entry->name);
|
||||||
}
|
}
|
||||||
|
|
||||||
struct nonmatching_ref_data {
|
struct nonmatching_ref_data {
|
||||||
const char *skip;
|
const struct string_list *skip;
|
||||||
struct ref_entry *found;
|
struct ref_entry *found;
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -817,16 +844,19 @@ static void report_refname_conflict(struct ref_entry *entry,
|
|||||||
/*
|
/*
|
||||||
* Return true iff a reference named refname could be created without
|
* Return true iff a reference named refname could be created without
|
||||||
* conflicting with the name of an existing reference in dir. If
|
* conflicting with the name of an existing reference in dir. If
|
||||||
* oldrefname is non-NULL, ignore potential conflicts with oldrefname
|
* skip is non-NULL, ignore potential conflicts with refs in skip
|
||||||
* (e.g., because oldrefname is scheduled for deletion in the same
|
* (e.g., because they are scheduled for deletion in the same
|
||||||
* operation).
|
* operation).
|
||||||
*
|
*
|
||||||
* Two reference names conflict if one of them exactly matches the
|
* Two reference names conflict if one of them exactly matches the
|
||||||
* leading components of the other; e.g., "foo/bar" conflicts with
|
* leading components of the other; e.g., "foo/bar" conflicts with
|
||||||
* both "foo" and with "foo/bar/baz" but not with "foo/bar" or
|
* both "foo" and with "foo/bar/baz" but not with "foo/bar" or
|
||||||
* "foo/barbados".
|
* "foo/barbados".
|
||||||
|
*
|
||||||
|
* skip must be sorted.
|
||||||
*/
|
*/
|
||||||
static int is_refname_available(const char *refname, const char *oldrefname,
|
static int is_refname_available(const char *refname,
|
||||||
|
const struct string_list *skip,
|
||||||
struct ref_dir *dir)
|
struct ref_dir *dir)
|
||||||
{
|
{
|
||||||
const char *slash;
|
const char *slash;
|
||||||
@ -840,12 +870,12 @@ static int is_refname_available(const char *refname, const char *oldrefname,
|
|||||||
* looking for a conflict with a leaf entry.
|
* looking for a conflict with a leaf entry.
|
||||||
*
|
*
|
||||||
* If we find one, we still must make sure it is
|
* If we find one, we still must make sure it is
|
||||||
* not "oldrefname".
|
* not in "skip".
|
||||||
*/
|
*/
|
||||||
pos = search_ref_dir(dir, refname, slash - refname);
|
pos = search_ref_dir(dir, refname, slash - refname);
|
||||||
if (pos >= 0) {
|
if (pos >= 0) {
|
||||||
struct ref_entry *entry = dir->entries[pos];
|
struct ref_entry *entry = dir->entries[pos];
|
||||||
if (entry_matches(entry, oldrefname))
|
if (entry_matches(entry, skip))
|
||||||
return 1;
|
return 1;
|
||||||
report_refname_conflict(entry, refname);
|
report_refname_conflict(entry, refname);
|
||||||
return 0;
|
return 0;
|
||||||
@ -878,13 +908,13 @@ static int is_refname_available(const char *refname, const char *oldrefname,
|
|||||||
/*
|
/*
|
||||||
* We found a directory named "refname". It is a
|
* We found a directory named "refname". It is a
|
||||||
* problem iff it contains any ref that is not
|
* problem iff it contains any ref that is not
|
||||||
* "oldrefname".
|
* in "skip".
|
||||||
*/
|
*/
|
||||||
struct ref_entry *entry = dir->entries[pos];
|
struct ref_entry *entry = dir->entries[pos];
|
||||||
struct ref_dir *dir = get_ref_dir(entry);
|
struct ref_dir *dir = get_ref_dir(entry);
|
||||||
struct nonmatching_ref_data data;
|
struct nonmatching_ref_data data;
|
||||||
|
|
||||||
data.skip = oldrefname;
|
data.skip = skip;
|
||||||
sort_ref_dir(dir);
|
sort_ref_dir(dir);
|
||||||
if (!do_for_each_entry_in_dir(dir, 0, nonmatching_ref_fn, &data))
|
if (!do_for_each_entry_in_dir(dir, 0, nonmatching_ref_fn, &data))
|
||||||
return 1;
|
return 1;
|
||||||
@ -1116,7 +1146,13 @@ static void read_packed_refs(FILE *f, struct ref_dir *dir)
|
|||||||
|
|
||||||
refname = parse_ref_line(refline, sha1);
|
refname = parse_ref_line(refline, sha1);
|
||||||
if (refname) {
|
if (refname) {
|
||||||
last = create_ref_entry(refname, sha1, REF_ISPACKED, 1);
|
int flag = REF_ISPACKED;
|
||||||
|
|
||||||
|
if (check_refname_format(refname, REFNAME_ALLOW_ONELEVEL)) {
|
||||||
|
hashclr(sha1);
|
||||||
|
flag |= REF_BAD_NAME | REF_ISBROKEN;
|
||||||
|
}
|
||||||
|
last = create_ref_entry(refname, sha1, flag, 0);
|
||||||
if (peeled == PEELED_FULLY ||
|
if (peeled == PEELED_FULLY ||
|
||||||
(peeled == PEELED_TAGS && starts_with(refname, "refs/tags/")))
|
(peeled == PEELED_TAGS && starts_with(refname, "refs/tags/")))
|
||||||
last->flag |= REF_KNOWS_PEELED;
|
last->flag |= REF_KNOWS_PEELED;
|
||||||
@ -1248,12 +1284,19 @@ static void read_loose_refs(const char *dirname, struct ref_dir *dir)
|
|||||||
hashclr(sha1);
|
hashclr(sha1);
|
||||||
flag |= REF_ISBROKEN;
|
flag |= REF_ISBROKEN;
|
||||||
}
|
}
|
||||||
} else if (read_ref_full(refname.buf, sha1, 1, &flag)) {
|
} else if (read_ref_full(refname.buf,
|
||||||
|
RESOLVE_REF_READING,
|
||||||
|
sha1, &flag)) {
|
||||||
hashclr(sha1);
|
hashclr(sha1);
|
||||||
flag |= REF_ISBROKEN;
|
flag |= REF_ISBROKEN;
|
||||||
}
|
}
|
||||||
|
if (check_refname_format(refname.buf,
|
||||||
|
REFNAME_ALLOW_ONELEVEL)) {
|
||||||
|
hashclr(sha1);
|
||||||
|
flag |= REF_BAD_NAME | REF_ISBROKEN;
|
||||||
|
}
|
||||||
add_entry_to_dir(dir,
|
add_entry_to_dir(dir,
|
||||||
create_ref_entry(refname.buf, sha1, flag, 1));
|
create_ref_entry(refname.buf, sha1, flag, 0));
|
||||||
}
|
}
|
||||||
strbuf_setlen(&refname, dirnamelen);
|
strbuf_setlen(&refname, dirnamelen);
|
||||||
}
|
}
|
||||||
@ -1372,10 +1415,10 @@ static struct ref_entry *get_packed_ref(const char *refname)
|
|||||||
* A loose ref file doesn't exist; check for a packed ref. The
|
* A loose ref file doesn't exist; check for a packed ref. The
|
||||||
* options are forwarded from resolve_safe_unsafe().
|
* options are forwarded from resolve_safe_unsafe().
|
||||||
*/
|
*/
|
||||||
static const char *handle_missing_loose_ref(const char *refname,
|
static int resolve_missing_loose_ref(const char *refname,
|
||||||
|
int resolve_flags,
|
||||||
unsigned char *sha1,
|
unsigned char *sha1,
|
||||||
int reading,
|
int *flags)
|
||||||
int *flag)
|
|
||||||
{
|
{
|
||||||
struct ref_entry *entry;
|
struct ref_entry *entry;
|
||||||
|
|
||||||
@ -1386,35 +1429,51 @@ static const char *handle_missing_loose_ref(const char *refname,
|
|||||||
entry = get_packed_ref(refname);
|
entry = get_packed_ref(refname);
|
||||||
if (entry) {
|
if (entry) {
|
||||||
hashcpy(sha1, entry->u.value.sha1);
|
hashcpy(sha1, entry->u.value.sha1);
|
||||||
if (flag)
|
if (flags)
|
||||||
*flag |= REF_ISPACKED;
|
*flags |= REF_ISPACKED;
|
||||||
return refname;
|
return 0;
|
||||||
}
|
}
|
||||||
/* The reference is not a packed reference, either. */
|
/* The reference is not a packed reference, either. */
|
||||||
if (reading) {
|
if (resolve_flags & RESOLVE_REF_READING) {
|
||||||
return NULL;
|
errno = ENOENT;
|
||||||
|
return -1;
|
||||||
} else {
|
} else {
|
||||||
hashclr(sha1);
|
hashclr(sha1);
|
||||||
return refname;
|
return 0;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/* This function needs to return a meaningful errno on failure */
|
/* This function needs to return a meaningful errno on failure */
|
||||||
const char *resolve_ref_unsafe(const char *refname, unsigned char *sha1, int reading, int *flag)
|
const char *resolve_ref_unsafe(const char *refname, int resolve_flags, unsigned char *sha1, int *flags)
|
||||||
{
|
{
|
||||||
int depth = MAXDEPTH;
|
int depth = MAXDEPTH;
|
||||||
ssize_t len;
|
ssize_t len;
|
||||||
char buffer[256];
|
char buffer[256];
|
||||||
static char refname_buffer[256];
|
static char refname_buffer[256];
|
||||||
|
int bad_name = 0;
|
||||||
|
|
||||||
if (flag)
|
if (flags)
|
||||||
*flag = 0;
|
*flags = 0;
|
||||||
|
|
||||||
if (check_refname_format(refname, REFNAME_ALLOW_ONELEVEL)) {
|
if (check_refname_format(refname, REFNAME_ALLOW_ONELEVEL)) {
|
||||||
|
if (flags)
|
||||||
|
*flags |= REF_BAD_NAME;
|
||||||
|
|
||||||
|
if (!(resolve_flags & RESOLVE_REF_ALLOW_BAD_NAME) ||
|
||||||
|
!refname_is_safe(refname)) {
|
||||||
errno = EINVAL;
|
errno = EINVAL;
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
/*
|
||||||
|
* dwim_ref() uses REF_ISBROKEN to distinguish between
|
||||||
|
* missing refs and refs that were present but invalid,
|
||||||
|
* to complain about the latter to stderr.
|
||||||
|
*
|
||||||
|
* We don't know whether the ref exists, so don't set
|
||||||
|
* REF_ISBROKEN yet.
|
||||||
|
*/
|
||||||
|
bad_name = 1;
|
||||||
|
}
|
||||||
for (;;) {
|
for (;;) {
|
||||||
char path[PATH_MAX];
|
char path[PATH_MAX];
|
||||||
struct stat st;
|
struct stat st;
|
||||||
@ -1439,11 +1498,17 @@ const char *resolve_ref_unsafe(const char *refname, unsigned char *sha1, int rea
|
|||||||
*/
|
*/
|
||||||
stat_ref:
|
stat_ref:
|
||||||
if (lstat(path, &st) < 0) {
|
if (lstat(path, &st) < 0) {
|
||||||
if (errno == ENOENT)
|
if (errno != ENOENT)
|
||||||
return handle_missing_loose_ref(refname, sha1,
|
|
||||||
reading, flag);
|
|
||||||
else
|
|
||||||
return NULL;
|
return NULL;
|
||||||
|
if (resolve_missing_loose_ref(refname, resolve_flags,
|
||||||
|
sha1, flags))
|
||||||
|
return NULL;
|
||||||
|
if (bad_name) {
|
||||||
|
hashclr(sha1);
|
||||||
|
if (flags)
|
||||||
|
*flags |= REF_ISBROKEN;
|
||||||
|
}
|
||||||
|
return refname;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Follow "normalized" - ie "refs/.." symlinks by hand */
|
/* Follow "normalized" - ie "refs/.." symlinks by hand */
|
||||||
@ -1461,8 +1526,12 @@ const char *resolve_ref_unsafe(const char *refname, unsigned char *sha1, int rea
|
|||||||
!check_refname_format(buffer, 0)) {
|
!check_refname_format(buffer, 0)) {
|
||||||
strcpy(refname_buffer, buffer);
|
strcpy(refname_buffer, buffer);
|
||||||
refname = refname_buffer;
|
refname = refname_buffer;
|
||||||
if (flag)
|
if (flags)
|
||||||
*flag |= REF_ISSYMREF;
|
*flags |= REF_ISSYMREF;
|
||||||
|
if (resolve_flags & RESOLVE_REF_NO_RECURSE) {
|
||||||
|
hashclr(sha1);
|
||||||
|
return refname;
|
||||||
|
}
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -1507,31 +1576,45 @@ const char *resolve_ref_unsafe(const char *refname, unsigned char *sha1, int rea
|
|||||||
*/
|
*/
|
||||||
if (get_sha1_hex(buffer, sha1) ||
|
if (get_sha1_hex(buffer, sha1) ||
|
||||||
(buffer[40] != '\0' && !isspace(buffer[40]))) {
|
(buffer[40] != '\0' && !isspace(buffer[40]))) {
|
||||||
if (flag)
|
if (flags)
|
||||||
*flag |= REF_ISBROKEN;
|
*flags |= REF_ISBROKEN;
|
||||||
errno = EINVAL;
|
errno = EINVAL;
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
if (bad_name) {
|
||||||
|
hashclr(sha1);
|
||||||
|
if (flags)
|
||||||
|
*flags |= REF_ISBROKEN;
|
||||||
|
}
|
||||||
return refname;
|
return refname;
|
||||||
}
|
}
|
||||||
if (flag)
|
if (flags)
|
||||||
*flag |= REF_ISSYMREF;
|
*flags |= REF_ISSYMREF;
|
||||||
buf = buffer + 4;
|
buf = buffer + 4;
|
||||||
while (isspace(*buf))
|
while (isspace(*buf))
|
||||||
buf++;
|
buf++;
|
||||||
|
refname = strcpy(refname_buffer, buf);
|
||||||
|
if (resolve_flags & RESOLVE_REF_NO_RECURSE) {
|
||||||
|
hashclr(sha1);
|
||||||
|
return refname;
|
||||||
|
}
|
||||||
if (check_refname_format(buf, REFNAME_ALLOW_ONELEVEL)) {
|
if (check_refname_format(buf, REFNAME_ALLOW_ONELEVEL)) {
|
||||||
if (flag)
|
if (flags)
|
||||||
*flag |= REF_ISBROKEN;
|
*flags |= REF_ISBROKEN;
|
||||||
|
|
||||||
|
if (!(resolve_flags & RESOLVE_REF_ALLOW_BAD_NAME) ||
|
||||||
|
!refname_is_safe(buf)) {
|
||||||
errno = EINVAL;
|
errno = EINVAL;
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
refname = strcpy(refname_buffer, buf);
|
bad_name = 1;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
char *resolve_refdup(const char *ref, unsigned char *sha1, int reading, int *flag)
|
char *resolve_refdup(const char *ref, int resolve_flags, unsigned char *sha1, int *flags)
|
||||||
{
|
{
|
||||||
const char *ret = resolve_ref_unsafe(ref, sha1, reading, flag);
|
const char *ret = resolve_ref_unsafe(ref, resolve_flags, sha1, flags);
|
||||||
return ret ? xstrdup(ret) : NULL;
|
return ret ? xstrdup(ret) : NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1542,22 +1625,22 @@ struct ref_filter {
|
|||||||
void *cb_data;
|
void *cb_data;
|
||||||
};
|
};
|
||||||
|
|
||||||
int read_ref_full(const char *refname, unsigned char *sha1, int reading, int *flags)
|
int read_ref_full(const char *refname, int resolve_flags, unsigned char *sha1, int *flags)
|
||||||
{
|
{
|
||||||
if (resolve_ref_unsafe(refname, sha1, reading, flags))
|
if (resolve_ref_unsafe(refname, resolve_flags, sha1, flags))
|
||||||
return 0;
|
return 0;
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
int read_ref(const char *refname, unsigned char *sha1)
|
int read_ref(const char *refname, unsigned char *sha1)
|
||||||
{
|
{
|
||||||
return read_ref_full(refname, sha1, 1, NULL);
|
return read_ref_full(refname, RESOLVE_REF_READING, sha1, NULL);
|
||||||
}
|
}
|
||||||
|
|
||||||
int ref_exists(const char *refname)
|
int ref_exists(const char *refname)
|
||||||
{
|
{
|
||||||
unsigned char sha1[20];
|
unsigned char sha1[20];
|
||||||
return !!resolve_ref_unsafe(refname, sha1, 1, NULL);
|
return !!resolve_ref_unsafe(refname, RESOLVE_REF_READING, sha1, NULL);
|
||||||
}
|
}
|
||||||
|
|
||||||
static int filter_refs(const char *refname, const unsigned char *sha1, int flags,
|
static int filter_refs(const char *refname, const unsigned char *sha1, int flags,
|
||||||
@ -1670,7 +1753,7 @@ int peel_ref(const char *refname, unsigned char *sha1)
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (read_ref_full(refname, base, 1, &flag))
|
if (read_ref_full(refname, RESOLVE_REF_READING, base, &flag))
|
||||||
return -1;
|
return -1;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@ -1711,7 +1794,7 @@ static int warn_if_dangling_symref(const char *refname, const unsigned char *sha
|
|||||||
if (!(flags & REF_ISSYMREF))
|
if (!(flags & REF_ISSYMREF))
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
resolves_to = resolve_ref_unsafe(refname, junk, 0, NULL);
|
resolves_to = resolve_ref_unsafe(refname, 0, junk, NULL);
|
||||||
if (!resolves_to
|
if (!resolves_to
|
||||||
|| (d->refname
|
|| (d->refname
|
||||||
? strcmp(resolves_to, d->refname)
|
? strcmp(resolves_to, d->refname)
|
||||||
@ -1836,7 +1919,7 @@ static int do_head_ref(const char *submodule, each_ref_fn fn, void *cb_data)
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!read_ref_full("HEAD", sha1, 1, &flag))
|
if (!read_ref_full("HEAD", RESOLVE_REF_READING, sha1, &flag))
|
||||||
return fn("HEAD", sha1, flag, cb_data);
|
return fn("HEAD", sha1, flag, cb_data);
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
@ -1916,7 +1999,7 @@ int head_ref_namespaced(each_ref_fn fn, void *cb_data)
|
|||||||
int flag;
|
int flag;
|
||||||
|
|
||||||
strbuf_addf(&buf, "%sHEAD", get_git_namespace());
|
strbuf_addf(&buf, "%sHEAD", get_git_namespace());
|
||||||
if (!read_ref_full(buf.buf, sha1, 1, &flag))
|
if (!read_ref_full(buf.buf, RESOLVE_REF_READING, sha1, &flag))
|
||||||
ret = fn(buf.buf, sha1, flag, cb_data);
|
ret = fn(buf.buf, sha1, flag, cb_data);
|
||||||
strbuf_release(&buf);
|
strbuf_release(&buf);
|
||||||
|
|
||||||
@ -2011,7 +2094,9 @@ int refname_match(const char *abbrev_name, const char *full_name)
|
|||||||
static struct ref_lock *verify_lock(struct ref_lock *lock,
|
static struct ref_lock *verify_lock(struct ref_lock *lock,
|
||||||
const unsigned char *old_sha1, int mustexist)
|
const unsigned char *old_sha1, int mustexist)
|
||||||
{
|
{
|
||||||
if (read_ref_full(lock->ref_name, lock->old_sha1, mustexist, NULL)) {
|
if (read_ref_full(lock->ref_name,
|
||||||
|
mustexist ? RESOLVE_REF_READING : 0,
|
||||||
|
lock->old_sha1, NULL)) {
|
||||||
int save_errno = errno;
|
int save_errno = errno;
|
||||||
error("Can't verify ref %s", lock->ref_name);
|
error("Can't verify ref %s", lock->ref_name);
|
||||||
unlock_ref(lock);
|
unlock_ref(lock);
|
||||||
@ -2084,7 +2169,8 @@ int dwim_ref(const char *str, int len, unsigned char *sha1, char **ref)
|
|||||||
|
|
||||||
this_result = refs_found ? sha1_from_ref : sha1;
|
this_result = refs_found ? sha1_from_ref : sha1;
|
||||||
mksnpath(fullref, sizeof(fullref), *p, len, str);
|
mksnpath(fullref, sizeof(fullref), *p, len, str);
|
||||||
r = resolve_ref_unsafe(fullref, this_result, 1, &flag);
|
r = resolve_ref_unsafe(fullref, RESOLVE_REF_READING,
|
||||||
|
this_result, &flag);
|
||||||
if (r) {
|
if (r) {
|
||||||
if (!refs_found++)
|
if (!refs_found++)
|
||||||
*ref = xstrdup(r);
|
*ref = xstrdup(r);
|
||||||
@ -2113,7 +2199,8 @@ int dwim_log(const char *str, int len, unsigned char *sha1, char **log)
|
|||||||
const char *ref, *it;
|
const char *ref, *it;
|
||||||
|
|
||||||
mksnpath(path, sizeof(path), *p, len, str);
|
mksnpath(path, sizeof(path), *p, len, str);
|
||||||
ref = resolve_ref_unsafe(path, hash, 1, NULL);
|
ref = resolve_ref_unsafe(path, RESOLVE_REF_READING,
|
||||||
|
hash, NULL);
|
||||||
if (!ref)
|
if (!ref)
|
||||||
continue;
|
continue;
|
||||||
if (reflog_exists(path))
|
if (reflog_exists(path))
|
||||||
@ -2134,11 +2221,12 @@ int dwim_log(const char *str, int len, unsigned char *sha1, char **log)
|
|||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Locks a "refs/" ref returning the lock on success and NULL on failure.
|
* Locks a ref returning the lock on success and NULL on failure.
|
||||||
* On failure errno is set to something meaningful.
|
* On failure errno is set to something meaningful.
|
||||||
*/
|
*/
|
||||||
static struct ref_lock *lock_ref_sha1_basic(const char *refname,
|
static struct ref_lock *lock_ref_sha1_basic(const char *refname,
|
||||||
const unsigned char *old_sha1,
|
const unsigned char *old_sha1,
|
||||||
|
const struct string_list *skip,
|
||||||
int flags, int *type_p)
|
int flags, int *type_p)
|
||||||
{
|
{
|
||||||
char *ref_file;
|
char *ref_file;
|
||||||
@ -2147,13 +2235,23 @@ static struct ref_lock *lock_ref_sha1_basic(const char *refname,
|
|||||||
int last_errno = 0;
|
int last_errno = 0;
|
||||||
int type, lflags;
|
int type, lflags;
|
||||||
int mustexist = (old_sha1 && !is_null_sha1(old_sha1));
|
int mustexist = (old_sha1 && !is_null_sha1(old_sha1));
|
||||||
|
int resolve_flags = 0;
|
||||||
int missing = 0;
|
int missing = 0;
|
||||||
int attempts_remaining = 3;
|
int attempts_remaining = 3;
|
||||||
|
|
||||||
lock = xcalloc(1, sizeof(struct ref_lock));
|
lock = xcalloc(1, sizeof(struct ref_lock));
|
||||||
lock->lock_fd = -1;
|
lock->lock_fd = -1;
|
||||||
|
|
||||||
refname = resolve_ref_unsafe(refname, lock->old_sha1, mustexist, &type);
|
if (mustexist)
|
||||||
|
resolve_flags |= RESOLVE_REF_READING;
|
||||||
|
if (flags & REF_DELETING) {
|
||||||
|
resolve_flags |= RESOLVE_REF_ALLOW_BAD_NAME;
|
||||||
|
if (flags & REF_NODEREF)
|
||||||
|
resolve_flags |= RESOLVE_REF_NO_RECURSE;
|
||||||
|
}
|
||||||
|
|
||||||
|
refname = resolve_ref_unsafe(refname, resolve_flags,
|
||||||
|
lock->old_sha1, &type);
|
||||||
if (!refname && errno == EISDIR) {
|
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;
|
* have foo/bar which now does not exist;
|
||||||
@ -2166,7 +2264,8 @@ static struct ref_lock *lock_ref_sha1_basic(const char *refname,
|
|||||||
error("there are still refs under '%s'", orig_refname);
|
error("there are still refs under '%s'", orig_refname);
|
||||||
goto error_return;
|
goto error_return;
|
||||||
}
|
}
|
||||||
refname = resolve_ref_unsafe(orig_refname, lock->old_sha1, mustexist, &type);
|
refname = resolve_ref_unsafe(orig_refname, resolve_flags,
|
||||||
|
lock->old_sha1, &type);
|
||||||
}
|
}
|
||||||
if (type_p)
|
if (type_p)
|
||||||
*type_p = type;
|
*type_p = type;
|
||||||
@ -2183,7 +2282,7 @@ static struct ref_lock *lock_ref_sha1_basic(const char *refname,
|
|||||||
* name is a proper prefix of our refname.
|
* name is a proper prefix of our refname.
|
||||||
*/
|
*/
|
||||||
if (missing &&
|
if (missing &&
|
||||||
!is_refname_available(refname, NULL, get_packed_refs(&ref_cache))) {
|
!is_refname_available(refname, skip, get_packed_refs(&ref_cache))) {
|
||||||
last_errno = ENOTDIR;
|
last_errno = ENOTDIR;
|
||||||
goto error_return;
|
goto error_return;
|
||||||
}
|
}
|
||||||
@ -2241,9 +2340,7 @@ struct ref_lock *lock_any_ref_for_update(const char *refname,
|
|||||||
const unsigned char *old_sha1,
|
const unsigned char *old_sha1,
|
||||||
int flags, int *type_p)
|
int flags, int *type_p)
|
||||||
{
|
{
|
||||||
if (check_refname_format(refname, REFNAME_ALLOW_ONELEVEL))
|
return lock_ref_sha1_basic(refname, old_sha1, NULL, flags, type_p);
|
||||||
return NULL;
|
|
||||||
return lock_ref_sha1_basic(refname, old_sha1, flags, type_p);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@ -2445,8 +2542,8 @@ static void prune_ref(struct ref_to_prune *r)
|
|||||||
transaction = ref_transaction_begin(&err);
|
transaction = ref_transaction_begin(&err);
|
||||||
if (!transaction ||
|
if (!transaction ||
|
||||||
ref_transaction_delete(transaction, r->name, r->sha1,
|
ref_transaction_delete(transaction, r->name, r->sha1,
|
||||||
REF_ISPRUNING, 1, &err) ||
|
REF_ISPRUNING, 1, NULL, &err) ||
|
||||||
ref_transaction_commit(transaction, NULL, &err)) {
|
ref_transaction_commit(transaction, &err)) {
|
||||||
ref_transaction_free(transaction);
|
ref_transaction_free(transaction);
|
||||||
error("%s", err.buf);
|
error("%s", err.buf);
|
||||||
strbuf_release(&err);
|
strbuf_release(&err);
|
||||||
@ -2510,7 +2607,7 @@ static int curate_packed_ref_fn(struct ref_entry *entry, void *cb_data)
|
|||||||
unsigned char sha1[20];
|
unsigned char sha1[20];
|
||||||
int flags;
|
int flags;
|
||||||
|
|
||||||
if (read_ref_full(entry->name, sha1, 0, &flags))
|
if (read_ref_full(entry->name, 0, sha1, &flags))
|
||||||
/* We should at least have found the packed ref. */
|
/* We should at least have found the packed ref. */
|
||||||
die("Internal error");
|
die("Internal error");
|
||||||
if ((flags & REF_ISSYMREF) || !(flags & REF_ISPACKED)) {
|
if ((flags & REF_ISSYMREF) || !(flags & REF_ISPACKED)) {
|
||||||
@ -2549,6 +2646,8 @@ int repack_without_refs(const char **refnames, int n, struct strbuf *err)
|
|||||||
struct string_list_item *ref_to_delete;
|
struct string_list_item *ref_to_delete;
|
||||||
int i, ret, removed = 0;
|
int i, ret, removed = 0;
|
||||||
|
|
||||||
|
assert(err);
|
||||||
|
|
||||||
/* Look for a packed ref */
|
/* Look for a packed ref */
|
||||||
for (i = 0; i < n; i++)
|
for (i = 0; i < n; i++)
|
||||||
if (get_packed_ref(refnames[i]))
|
if (get_packed_ref(refnames[i]))
|
||||||
@ -2559,14 +2658,9 @@ int repack_without_refs(const char **refnames, int n, struct strbuf *err)
|
|||||||
return 0; /* no refname exists in packed refs */
|
return 0; /* no refname exists in packed refs */
|
||||||
|
|
||||||
if (lock_packed_refs(0)) {
|
if (lock_packed_refs(0)) {
|
||||||
if (err) {
|
unable_to_lock_message(git_path("packed-refs"), errno, err);
|
||||||
unable_to_lock_message(git_path("packed-refs"), errno,
|
|
||||||
err);
|
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
unable_to_lock_error(git_path("packed-refs"), errno);
|
|
||||||
return error("cannot delete '%s' from packed refs", refnames[i]);
|
|
||||||
}
|
|
||||||
packed = get_packed_refs(&ref_cache);
|
packed = get_packed_refs(&ref_cache);
|
||||||
|
|
||||||
/* Remove refnames from the cache */
|
/* Remove refnames from the cache */
|
||||||
@ -2591,23 +2685,25 @@ int repack_without_refs(const char **refnames, int n, struct strbuf *err)
|
|||||||
|
|
||||||
/* Write what remains */
|
/* Write what remains */
|
||||||
ret = commit_packed_refs();
|
ret = commit_packed_refs();
|
||||||
if (ret && err)
|
if (ret)
|
||||||
strbuf_addf(err, "unable to overwrite old ref-pack file: %s",
|
strbuf_addf(err, "unable to overwrite old ref-pack file: %s",
|
||||||
strerror(errno));
|
strerror(errno));
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int delete_ref_loose(struct ref_lock *lock, int flag)
|
static int delete_ref_loose(struct ref_lock *lock, int flag, struct strbuf *err)
|
||||||
{
|
{
|
||||||
|
assert(err);
|
||||||
|
|
||||||
if (!(flag & REF_ISPACKED) || flag & REF_ISSYMREF) {
|
if (!(flag & REF_ISPACKED) || flag & REF_ISSYMREF) {
|
||||||
/*
|
/*
|
||||||
* loose. The loose file name is the same as the
|
* loose. The loose file name is the same as the
|
||||||
* lockfile name, minus ".lock":
|
* lockfile name, minus ".lock":
|
||||||
*/
|
*/
|
||||||
char *loose_filename = get_locked_file_path(lock->lk);
|
char *loose_filename = get_locked_file_path(lock->lk);
|
||||||
int err = unlink_or_warn(loose_filename);
|
int res = unlink_or_msg(loose_filename, err);
|
||||||
free(loose_filename);
|
free(loose_filename);
|
||||||
if (err && errno != ENOENT)
|
if (res)
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
return 0;
|
return 0;
|
||||||
@ -2621,8 +2717,8 @@ int delete_ref(const char *refname, const unsigned char *sha1, int delopt)
|
|||||||
transaction = ref_transaction_begin(&err);
|
transaction = ref_transaction_begin(&err);
|
||||||
if (!transaction ||
|
if (!transaction ||
|
||||||
ref_transaction_delete(transaction, refname, sha1, delopt,
|
ref_transaction_delete(transaction, refname, sha1, delopt,
|
||||||
sha1 && !is_null_sha1(sha1), &err) ||
|
sha1 && !is_null_sha1(sha1), NULL, &err) ||
|
||||||
ref_transaction_commit(transaction, NULL, &err)) {
|
ref_transaction_commit(transaction, &err)) {
|
||||||
error("%s", err.buf);
|
error("%s", err.buf);
|
||||||
ref_transaction_free(transaction);
|
ref_transaction_free(transaction);
|
||||||
strbuf_release(&err);
|
strbuf_release(&err);
|
||||||
@ -2687,6 +2783,21 @@ static int rename_tmp_log(const char *newrefname)
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static int rename_ref_available(const char *oldname, const char *newname)
|
||||||
|
{
|
||||||
|
struct string_list skip = STRING_LIST_INIT_NODUP;
|
||||||
|
int ret;
|
||||||
|
|
||||||
|
string_list_insert(&skip, oldname);
|
||||||
|
ret = is_refname_available(newname, &skip, get_packed_refs(&ref_cache))
|
||||||
|
&& is_refname_available(newname, &skip, get_loose_refs(&ref_cache));
|
||||||
|
string_list_clear(&skip, 0);
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int write_ref_sha1(struct ref_lock *lock, const unsigned char *sha1,
|
||||||
|
const char *logmsg);
|
||||||
|
|
||||||
int rename_ref(const char *oldrefname, const char *newrefname, const char *logmsg)
|
int rename_ref(const char *oldrefname, const char *newrefname, const char *logmsg)
|
||||||
{
|
{
|
||||||
unsigned char sha1[20], orig_sha1[20];
|
unsigned char sha1[20], orig_sha1[20];
|
||||||
@ -2699,17 +2810,15 @@ int rename_ref(const char *oldrefname, const char *newrefname, const char *logms
|
|||||||
if (log && S_ISLNK(loginfo.st_mode))
|
if (log && S_ISLNK(loginfo.st_mode))
|
||||||
return error("reflog for %s is a symlink", oldrefname);
|
return error("reflog for %s is a symlink", oldrefname);
|
||||||
|
|
||||||
symref = resolve_ref_unsafe(oldrefname, orig_sha1, 1, &flag);
|
symref = resolve_ref_unsafe(oldrefname, RESOLVE_REF_READING,
|
||||||
|
orig_sha1, &flag);
|
||||||
if (flag & REF_ISSYMREF)
|
if (flag & REF_ISSYMREF)
|
||||||
return error("refname %s is a symbolic ref, renaming it is not supported",
|
return error("refname %s is a symbolic ref, renaming it is not supported",
|
||||||
oldrefname);
|
oldrefname);
|
||||||
if (!symref)
|
if (!symref)
|
||||||
return error("refname %s not found", oldrefname);
|
return error("refname %s not found", oldrefname);
|
||||||
|
|
||||||
if (!is_refname_available(newrefname, oldrefname, get_packed_refs(&ref_cache)))
|
if (!rename_ref_available(oldrefname, newrefname))
|
||||||
return 1;
|
|
||||||
|
|
||||||
if (!is_refname_available(newrefname, oldrefname, get_loose_refs(&ref_cache)))
|
|
||||||
return 1;
|
return 1;
|
||||||
|
|
||||||
if (log && rename(git_path("logs/%s", oldrefname), git_path(TMP_RENAMED_LOG)))
|
if (log && rename(git_path("logs/%s", oldrefname), git_path(TMP_RENAMED_LOG)))
|
||||||
@ -2721,7 +2830,7 @@ int rename_ref(const char *oldrefname, const char *newrefname, const char *logms
|
|||||||
goto rollback;
|
goto rollback;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!read_ref_full(newrefname, sha1, 1, &flag) &&
|
if (!read_ref_full(newrefname, RESOLVE_REF_READING, sha1, NULL) &&
|
||||||
delete_ref(newrefname, sha1, REF_NODEREF)) {
|
delete_ref(newrefname, sha1, REF_NODEREF)) {
|
||||||
if (errno==EISDIR) {
|
if (errno==EISDIR) {
|
||||||
if (remove_empty_directories(git_path("%s", newrefname))) {
|
if (remove_empty_directories(git_path("%s", newrefname))) {
|
||||||
@ -2739,7 +2848,7 @@ int rename_ref(const char *oldrefname, const char *newrefname, const char *logms
|
|||||||
|
|
||||||
logmoved = log;
|
logmoved = log;
|
||||||
|
|
||||||
lock = lock_ref_sha1_basic(newrefname, NULL, 0, NULL);
|
lock = lock_ref_sha1_basic(newrefname, NULL, NULL, 0, NULL);
|
||||||
if (!lock) {
|
if (!lock) {
|
||||||
error("unable to lock %s for update", newrefname);
|
error("unable to lock %s for update", newrefname);
|
||||||
goto rollback;
|
goto rollback;
|
||||||
@ -2754,7 +2863,7 @@ int rename_ref(const char *oldrefname, const char *newrefname, const char *logms
|
|||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
rollback:
|
rollback:
|
||||||
lock = lock_ref_sha1_basic(oldrefname, NULL, 0, NULL);
|
lock = lock_ref_sha1_basic(oldrefname, NULL, NULL, 0, NULL);
|
||||||
if (!lock) {
|
if (!lock) {
|
||||||
error("unable to lock %s for rollback", oldrefname);
|
error("unable to lock %s for rollback", oldrefname);
|
||||||
goto rollbacklog;
|
goto rollbacklog;
|
||||||
@ -2934,8 +3043,11 @@ int is_branch(const char *refname)
|
|||||||
return !strcmp(refname, "HEAD") || starts_with(refname, "refs/heads/");
|
return !strcmp(refname, "HEAD") || starts_with(refname, "refs/heads/");
|
||||||
}
|
}
|
||||||
|
|
||||||
/* This function must return a meaningful errno */
|
/*
|
||||||
int write_ref_sha1(struct ref_lock *lock,
|
* Write sha1 into the ref specified by the lock. Make sure that errno
|
||||||
|
* is sane on error.
|
||||||
|
*/
|
||||||
|
static int write_ref_sha1(struct ref_lock *lock,
|
||||||
const unsigned char *sha1, const char *logmsg)
|
const unsigned char *sha1, const char *logmsg)
|
||||||
{
|
{
|
||||||
static char term = '\n';
|
static char term = '\n';
|
||||||
@ -2996,7 +3108,8 @@ int write_ref_sha1(struct ref_lock *lock,
|
|||||||
unsigned char head_sha1[20];
|
unsigned char head_sha1[20];
|
||||||
int head_flag;
|
int head_flag;
|
||||||
const char *head_ref;
|
const char *head_ref;
|
||||||
head_ref = resolve_ref_unsafe("HEAD", head_sha1, 1, &head_flag);
|
head_ref = resolve_ref_unsafe("HEAD", RESOLVE_REF_READING,
|
||||||
|
head_sha1, &head_flag);
|
||||||
if (head_ref && (head_flag & REF_ISSYMREF) &&
|
if (head_ref && (head_flag & REF_ISSYMREF) &&
|
||||||
!strcmp(head_ref, lock->ref_name))
|
!strcmp(head_ref, lock->ref_name))
|
||||||
log_ref_write("HEAD", lock->old_sha1, sha1, logmsg);
|
log_ref_write("HEAD", lock->old_sha1, sha1, logmsg);
|
||||||
@ -3367,7 +3480,7 @@ static int do_for_each_reflog(struct strbuf *name, each_ref_fn fn, void *cb_data
|
|||||||
retval = do_for_each_reflog(name, fn, cb_data);
|
retval = do_for_each_reflog(name, fn, cb_data);
|
||||||
} else {
|
} else {
|
||||||
unsigned char sha1[20];
|
unsigned char sha1[20];
|
||||||
if (read_ref_full(name->buf, sha1, 0, NULL))
|
if (read_ref_full(name->buf, 0, sha1, NULL))
|
||||||
retval = error("bad ref for %s", name->buf);
|
retval = error("bad ref for %s", name->buf);
|
||||||
else
|
else
|
||||||
retval = fn(name->buf, sha1, 0, cb_data);
|
retval = fn(name->buf, sha1, 0, cb_data);
|
||||||
@ -3404,6 +3517,7 @@ struct ref_update {
|
|||||||
int have_old; /* 1 if old_sha1 is valid, 0 otherwise */
|
int have_old; /* 1 if old_sha1 is valid, 0 otherwise */
|
||||||
struct ref_lock *lock;
|
struct ref_lock *lock;
|
||||||
int type;
|
int type;
|
||||||
|
char *msg;
|
||||||
const char refname[FLEX_ARRAY];
|
const char refname[FLEX_ARRAY];
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -3436,6 +3550,8 @@ struct ref_transaction {
|
|||||||
|
|
||||||
struct ref_transaction *ref_transaction_begin(struct strbuf *err)
|
struct ref_transaction *ref_transaction_begin(struct strbuf *err)
|
||||||
{
|
{
|
||||||
|
assert(err);
|
||||||
|
|
||||||
return xcalloc(1, sizeof(struct ref_transaction));
|
return xcalloc(1, sizeof(struct ref_transaction));
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -3446,9 +3562,10 @@ void ref_transaction_free(struct ref_transaction *transaction)
|
|||||||
if (!transaction)
|
if (!transaction)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
for (i = 0; i < transaction->nr; i++)
|
for (i = 0; i < transaction->nr; i++) {
|
||||||
|
free(transaction->updates[i]->msg);
|
||||||
free(transaction->updates[i]);
|
free(transaction->updates[i]);
|
||||||
|
}
|
||||||
free(transaction->updates);
|
free(transaction->updates);
|
||||||
free(transaction);
|
free(transaction);
|
||||||
}
|
}
|
||||||
@ -3469,57 +3586,80 @@ int ref_transaction_update(struct ref_transaction *transaction,
|
|||||||
const char *refname,
|
const char *refname,
|
||||||
const unsigned char *new_sha1,
|
const unsigned char *new_sha1,
|
||||||
const unsigned char *old_sha1,
|
const unsigned char *old_sha1,
|
||||||
int flags, int have_old,
|
int flags, int have_old, const char *msg,
|
||||||
struct strbuf *err)
|
struct strbuf *err)
|
||||||
{
|
{
|
||||||
struct ref_update *update;
|
struct ref_update *update;
|
||||||
|
|
||||||
|
assert(err);
|
||||||
|
|
||||||
if (transaction->state != REF_TRANSACTION_OPEN)
|
if (transaction->state != REF_TRANSACTION_OPEN)
|
||||||
die("BUG: update called for transaction that is not open");
|
die("BUG: update called for transaction that is not open");
|
||||||
|
|
||||||
if (have_old && !old_sha1)
|
if (have_old && !old_sha1)
|
||||||
die("BUG: have_old is true but old_sha1 is NULL");
|
die("BUG: have_old is true but old_sha1 is NULL");
|
||||||
|
|
||||||
|
if (!is_null_sha1(new_sha1) &&
|
||||||
|
check_refname_format(refname, REFNAME_ALLOW_ONELEVEL)) {
|
||||||
|
strbuf_addf(err, "refusing to update ref with bad name %s",
|
||||||
|
refname);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
update = add_update(transaction, refname);
|
update = add_update(transaction, refname);
|
||||||
hashcpy(update->new_sha1, new_sha1);
|
hashcpy(update->new_sha1, new_sha1);
|
||||||
update->flags = flags;
|
update->flags = flags;
|
||||||
update->have_old = have_old;
|
update->have_old = have_old;
|
||||||
if (have_old)
|
if (have_old)
|
||||||
hashcpy(update->old_sha1, old_sha1);
|
hashcpy(update->old_sha1, old_sha1);
|
||||||
|
if (msg)
|
||||||
|
update->msg = xstrdup(msg);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
int ref_transaction_create(struct ref_transaction *transaction,
|
int ref_transaction_create(struct ref_transaction *transaction,
|
||||||
const char *refname,
|
const char *refname,
|
||||||
const unsigned char *new_sha1,
|
const unsigned char *new_sha1,
|
||||||
int flags,
|
int flags, const char *msg,
|
||||||
struct strbuf *err)
|
struct strbuf *err)
|
||||||
{
|
{
|
||||||
struct ref_update *update;
|
struct ref_update *update;
|
||||||
|
|
||||||
|
assert(err);
|
||||||
|
|
||||||
if (transaction->state != REF_TRANSACTION_OPEN)
|
if (transaction->state != REF_TRANSACTION_OPEN)
|
||||||
die("BUG: create called for transaction that is not open");
|
die("BUG: create called for transaction that is not open");
|
||||||
|
|
||||||
if (!new_sha1 || is_null_sha1(new_sha1))
|
if (!new_sha1 || is_null_sha1(new_sha1))
|
||||||
die("BUG: create ref with null new_sha1");
|
die("BUG: create ref with null new_sha1");
|
||||||
|
|
||||||
|
if (check_refname_format(refname, REFNAME_ALLOW_ONELEVEL)) {
|
||||||
|
strbuf_addf(err, "refusing to create ref with bad name %s",
|
||||||
|
refname);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
update = add_update(transaction, refname);
|
update = add_update(transaction, refname);
|
||||||
|
|
||||||
hashcpy(update->new_sha1, new_sha1);
|
hashcpy(update->new_sha1, new_sha1);
|
||||||
hashclr(update->old_sha1);
|
hashclr(update->old_sha1);
|
||||||
update->flags = flags;
|
update->flags = flags;
|
||||||
update->have_old = 1;
|
update->have_old = 1;
|
||||||
|
if (msg)
|
||||||
|
update->msg = xstrdup(msg);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
int ref_transaction_delete(struct ref_transaction *transaction,
|
int ref_transaction_delete(struct ref_transaction *transaction,
|
||||||
const char *refname,
|
const char *refname,
|
||||||
const unsigned char *old_sha1,
|
const unsigned char *old_sha1,
|
||||||
int flags, int have_old,
|
int flags, int have_old, const char *msg,
|
||||||
struct strbuf *err)
|
struct strbuf *err)
|
||||||
{
|
{
|
||||||
struct ref_update *update;
|
struct ref_update *update;
|
||||||
|
|
||||||
|
assert(err);
|
||||||
|
|
||||||
if (transaction->state != REF_TRANSACTION_OPEN)
|
if (transaction->state != REF_TRANSACTION_OPEN)
|
||||||
die("BUG: delete called for transaction that is not open");
|
die("BUG: delete called for transaction that is not open");
|
||||||
|
|
||||||
@ -3533,6 +3673,8 @@ int ref_transaction_delete(struct ref_transaction *transaction,
|
|||||||
assert(!is_null_sha1(old_sha1));
|
assert(!is_null_sha1(old_sha1));
|
||||||
hashcpy(update->old_sha1, old_sha1);
|
hashcpy(update->old_sha1, old_sha1);
|
||||||
}
|
}
|
||||||
|
if (msg)
|
||||||
|
update->msg = xstrdup(msg);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -3546,8 +3688,8 @@ int update_ref(const char *action, const char *refname,
|
|||||||
t = ref_transaction_begin(&err);
|
t = ref_transaction_begin(&err);
|
||||||
if (!t ||
|
if (!t ||
|
||||||
ref_transaction_update(t, refname, sha1, oldval, flags,
|
ref_transaction_update(t, refname, sha1, oldval, flags,
|
||||||
!!oldval, &err) ||
|
!!oldval, action, &err) ||
|
||||||
ref_transaction_commit(t, action, &err)) {
|
ref_transaction_commit(t, &err)) {
|
||||||
const char *str = "update_ref failed for ref '%s': %s";
|
const char *str = "update_ref failed for ref '%s': %s";
|
||||||
|
|
||||||
ref_transaction_free(t);
|
ref_transaction_free(t);
|
||||||
@ -3580,26 +3722,29 @@ static int ref_update_reject_duplicates(struct ref_update **updates, int n,
|
|||||||
struct strbuf *err)
|
struct strbuf *err)
|
||||||
{
|
{
|
||||||
int i;
|
int i;
|
||||||
|
|
||||||
|
assert(err);
|
||||||
|
|
||||||
for (i = 1; i < n; i++)
|
for (i = 1; i < n; i++)
|
||||||
if (!strcmp(updates[i - 1]->refname, updates[i]->refname)) {
|
if (!strcmp(updates[i - 1]->refname, updates[i]->refname)) {
|
||||||
const char *str =
|
strbuf_addf(err,
|
||||||
"Multiple updates for ref '%s' not allowed.";
|
"Multiple updates for ref '%s' not allowed.",
|
||||||
if (err)
|
updates[i]->refname);
|
||||||
strbuf_addf(err, str, updates[i]->refname);
|
|
||||||
|
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
int ref_transaction_commit(struct ref_transaction *transaction,
|
int ref_transaction_commit(struct ref_transaction *transaction,
|
||||||
const char *msg, struct strbuf *err)
|
struct strbuf *err)
|
||||||
{
|
{
|
||||||
int ret = 0, delnum = 0, i;
|
int ret = 0, delnum = 0, i;
|
||||||
const char **delnames;
|
const char **delnames;
|
||||||
int n = transaction->nr;
|
int n = transaction->nr;
|
||||||
struct ref_update **updates = transaction->updates;
|
struct ref_update **updates = transaction->updates;
|
||||||
|
|
||||||
|
assert(err);
|
||||||
|
|
||||||
if (transaction->state != REF_TRANSACTION_OPEN)
|
if (transaction->state != REF_TRANSACTION_OPEN)
|
||||||
die("BUG: commit called for transaction that is not open");
|
die("BUG: commit called for transaction that is not open");
|
||||||
|
|
||||||
@ -3613,25 +3758,31 @@ int ref_transaction_commit(struct ref_transaction *transaction,
|
|||||||
|
|
||||||
/* Copy, sort, and reject duplicate refs */
|
/* Copy, sort, and reject duplicate refs */
|
||||||
qsort(updates, n, sizeof(*updates), ref_update_compare);
|
qsort(updates, n, sizeof(*updates), ref_update_compare);
|
||||||
ret = ref_update_reject_duplicates(updates, n, err);
|
if (ref_update_reject_duplicates(updates, n, err)) {
|
||||||
if (ret)
|
ret = TRANSACTION_GENERIC_ERROR;
|
||||||
goto cleanup;
|
goto cleanup;
|
||||||
|
}
|
||||||
|
|
||||||
/* Acquire all locks while verifying old values */
|
/* Acquire all locks while verifying old values */
|
||||||
for (i = 0; i < n; i++) {
|
for (i = 0; i < n; i++) {
|
||||||
struct ref_update *update = updates[i];
|
struct ref_update *update = updates[i];
|
||||||
|
int flags = update->flags;
|
||||||
|
|
||||||
update->lock = lock_any_ref_for_update(update->refname,
|
if (is_null_sha1(update->new_sha1))
|
||||||
|
flags |= REF_DELETING;
|
||||||
|
update->lock = lock_ref_sha1_basic(update->refname,
|
||||||
(update->have_old ?
|
(update->have_old ?
|
||||||
update->old_sha1 :
|
update->old_sha1 :
|
||||||
NULL),
|
NULL),
|
||||||
update->flags,
|
NULL,
|
||||||
|
flags,
|
||||||
&update->type);
|
&update->type);
|
||||||
if (!update->lock) {
|
if (!update->lock) {
|
||||||
if (err)
|
ret = (errno == ENOTDIR)
|
||||||
|
? TRANSACTION_NAME_CONFLICT
|
||||||
|
: TRANSACTION_GENERIC_ERROR;
|
||||||
strbuf_addf(err, "Cannot lock the ref '%s'.",
|
strbuf_addf(err, "Cannot lock the ref '%s'.",
|
||||||
update->refname);
|
update->refname);
|
||||||
ret = 1;
|
|
||||||
goto cleanup;
|
goto cleanup;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -3641,15 +3792,15 @@ int ref_transaction_commit(struct ref_transaction *transaction,
|
|||||||
struct ref_update *update = updates[i];
|
struct ref_update *update = updates[i];
|
||||||
|
|
||||||
if (!is_null_sha1(update->new_sha1)) {
|
if (!is_null_sha1(update->new_sha1)) {
|
||||||
ret = write_ref_sha1(update->lock, update->new_sha1,
|
if (write_ref_sha1(update->lock, update->new_sha1,
|
||||||
msg);
|
update->msg)) {
|
||||||
update->lock = NULL; /* freed by write_ref_sha1 */
|
update->lock = NULL; /* freed by write_ref_sha1 */
|
||||||
if (ret) {
|
|
||||||
if (err)
|
|
||||||
strbuf_addf(err, "Cannot update the ref '%s'.",
|
strbuf_addf(err, "Cannot update the ref '%s'.",
|
||||||
update->refname);
|
update->refname);
|
||||||
|
ret = TRANSACTION_GENERIC_ERROR;
|
||||||
goto cleanup;
|
goto cleanup;
|
||||||
}
|
}
|
||||||
|
update->lock = NULL; /* freed by write_ref_sha1 */
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -3658,13 +3809,20 @@ int ref_transaction_commit(struct ref_transaction *transaction,
|
|||||||
struct ref_update *update = updates[i];
|
struct ref_update *update = updates[i];
|
||||||
|
|
||||||
if (update->lock) {
|
if (update->lock) {
|
||||||
ret |= delete_ref_loose(update->lock, update->type);
|
if (delete_ref_loose(update->lock, update->type, err)) {
|
||||||
|
ret = TRANSACTION_GENERIC_ERROR;
|
||||||
|
goto cleanup;
|
||||||
|
}
|
||||||
|
|
||||||
if (!(update->flags & REF_ISPRUNING))
|
if (!(update->flags & REF_ISPRUNING))
|
||||||
delnames[delnum++] = update->lock->ref_name;
|
delnames[delnum++] = update->lock->ref_name;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
ret |= repack_without_refs(delnames, delnum, err);
|
if (repack_without_refs(delnames, delnum, err)) {
|
||||||
|
ret = TRANSACTION_GENERIC_ERROR;
|
||||||
|
goto cleanup;
|
||||||
|
}
|
||||||
for (i = 0; i < delnum; i++)
|
for (i = 0; i < delnum; i++)
|
||||||
unlink_or_warn(git_path("logs/%s", delnames[i]));
|
unlink_or_warn(git_path("logs/%s", delnames[i]));
|
||||||
clear_loose_ref_cache(&ref_cache);
|
clear_loose_ref_cache(&ref_cache);
|
||||||
|
44
refs.h
44
refs.h
@ -56,11 +56,19 @@ struct ref_transaction;
|
|||||||
|
|
||||||
/*
|
/*
|
||||||
* Reference cannot be resolved to an object name: dangling symbolic
|
* Reference cannot be resolved to an object name: dangling symbolic
|
||||||
* reference (directly or indirectly), corrupt reference file, or
|
* reference (directly or indirectly), corrupt reference file,
|
||||||
* symbolic reference refers to ill-formatted reference name.
|
* reference exists but name is bad, or symbolic reference refers to
|
||||||
|
* ill-formatted reference name.
|
||||||
*/
|
*/
|
||||||
#define REF_ISBROKEN 0x04
|
#define REF_ISBROKEN 0x04
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Reference name is not well formed.
|
||||||
|
*
|
||||||
|
* See git-check-ref-format(1) for the definition of well formed ref names.
|
||||||
|
*/
|
||||||
|
#define REF_BAD_NAME 0x08
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* The signature for the callback function for the for_each_*()
|
* The signature for the callback function for the for_each_*()
|
||||||
* functions below. The memory pointed to by the refname and sha1
|
* functions below. The memory pointed to by the refname and sha1
|
||||||
@ -177,10 +185,12 @@ extern int peel_ref(const char *refname, unsigned char *sha1);
|
|||||||
* ref_transaction_create(), etc.
|
* ref_transaction_create(), etc.
|
||||||
* REF_NODEREF: act on the ref directly, instead of dereferencing
|
* REF_NODEREF: act on the ref directly, instead of dereferencing
|
||||||
* symbolic references.
|
* symbolic references.
|
||||||
|
* REF_DELETING: tolerate broken refs
|
||||||
*
|
*
|
||||||
* Flags >= 0x100 are reserved for internal use.
|
* Flags >= 0x100 are reserved for internal use.
|
||||||
*/
|
*/
|
||||||
#define REF_NODEREF 0x01
|
#define REF_NODEREF 0x01
|
||||||
|
#define REF_DELETING 0x02
|
||||||
/*
|
/*
|
||||||
* This function sets errno to something meaningful on failure.
|
* This function sets errno to something meaningful on failure.
|
||||||
*/
|
*/
|
||||||
@ -197,9 +207,6 @@ extern int commit_ref(struct ref_lock *lock);
|
|||||||
/** Release any lock taken but not written. **/
|
/** Release any lock taken but not written. **/
|
||||||
extern void unlock_ref(struct ref_lock *lock);
|
extern void unlock_ref(struct ref_lock *lock);
|
||||||
|
|
||||||
/** Writes sha1 into the ref specified by the lock. **/
|
|
||||||
extern int write_ref_sha1(struct ref_lock *lock, const unsigned char *sha1, const char *msg);
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Setup reflog before using. Set errno to something meaningful on failure.
|
* Setup reflog before using. Set errno to something meaningful on failure.
|
||||||
*/
|
*/
|
||||||
@ -230,7 +237,6 @@ extern int for_each_reflog(each_ref_fn, void *);
|
|||||||
|
|
||||||
#define REFNAME_ALLOW_ONELEVEL 1
|
#define REFNAME_ALLOW_ONELEVEL 1
|
||||||
#define REFNAME_REFSPEC_PATTERN 2
|
#define REFNAME_REFSPEC_PATTERN 2
|
||||||
#define REFNAME_DOT_COMPONENT 4
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Return 0 iff refname has the correct format for a refname according
|
* Return 0 iff refname has the correct format for a refname according
|
||||||
@ -238,10 +244,7 @@ extern int for_each_reflog(each_ref_fn, void *);
|
|||||||
* If REFNAME_ALLOW_ONELEVEL is set in flags, then accept one-level
|
* If REFNAME_ALLOW_ONELEVEL is set in flags, then accept one-level
|
||||||
* reference names. If REFNAME_REFSPEC_PATTERN is set in flags, then
|
* reference names. If REFNAME_REFSPEC_PATTERN is set in flags, then
|
||||||
* allow a "*" wildcard character in place of one of the name
|
* allow a "*" wildcard character in place of one of the name
|
||||||
* components. No leading or repeated slashes are accepted. If
|
* components. No leading or repeated slashes are accepted.
|
||||||
* REFNAME_DOT_COMPONENT is set in flags, then allow refname
|
|
||||||
* components to start with "." (but not a whole component equal to
|
|
||||||
* "." or "..").
|
|
||||||
*/
|
*/
|
||||||
extern int check_refname_format(const char *refname, int flags);
|
extern int check_refname_format(const char *refname, int flags);
|
||||||
|
|
||||||
@ -274,8 +277,8 @@ struct ref_transaction *ref_transaction_begin(struct strbuf *err);
|
|||||||
* The following functions add a reference check or update to a
|
* The following functions add a reference check or update to a
|
||||||
* ref_transaction. In all of them, refname is the name of the
|
* ref_transaction. In all of them, refname is the name of the
|
||||||
* reference to be affected. The functions make internal copies of
|
* reference to be affected. The functions make internal copies of
|
||||||
* refname, so the caller retains ownership of the parameter. flags
|
* refname and msg, so the caller retains ownership of these parameters.
|
||||||
* can be REF_NODEREF; it is passed to update_ref_lock().
|
* flags can be REF_NODEREF; it is passed to update_ref_lock().
|
||||||
*/
|
*/
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@ -292,7 +295,7 @@ int ref_transaction_update(struct ref_transaction *transaction,
|
|||||||
const char *refname,
|
const char *refname,
|
||||||
const unsigned char *new_sha1,
|
const unsigned char *new_sha1,
|
||||||
const unsigned char *old_sha1,
|
const unsigned char *old_sha1,
|
||||||
int flags, int have_old,
|
int flags, int have_old, const char *msg,
|
||||||
struct strbuf *err);
|
struct strbuf *err);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@ -307,7 +310,7 @@ int ref_transaction_update(struct ref_transaction *transaction,
|
|||||||
int ref_transaction_create(struct ref_transaction *transaction,
|
int ref_transaction_create(struct ref_transaction *transaction,
|
||||||
const char *refname,
|
const char *refname,
|
||||||
const unsigned char *new_sha1,
|
const unsigned char *new_sha1,
|
||||||
int flags,
|
int flags, const char *msg,
|
||||||
struct strbuf *err);
|
struct strbuf *err);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@ -321,16 +324,21 @@ int ref_transaction_create(struct ref_transaction *transaction,
|
|||||||
int ref_transaction_delete(struct ref_transaction *transaction,
|
int ref_transaction_delete(struct ref_transaction *transaction,
|
||||||
const char *refname,
|
const char *refname,
|
||||||
const unsigned char *old_sha1,
|
const unsigned char *old_sha1,
|
||||||
int flags, int have_old,
|
int flags, int have_old, const char *msg,
|
||||||
struct strbuf *err);
|
struct strbuf *err);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Commit all of the changes that have been queued in transaction, as
|
* Commit all of the changes that have been queued in transaction, as
|
||||||
* atomically as possible. Return a nonzero value if there is a
|
* atomically as possible.
|
||||||
* problem.
|
*
|
||||||
|
* Returns 0 for success, or one of the below error codes for errors.
|
||||||
*/
|
*/
|
||||||
|
/* Naming conflict (for example, the ref names A and A/B conflict). */
|
||||||
|
#define TRANSACTION_NAME_CONFLICT -1
|
||||||
|
/* All other errors. */
|
||||||
|
#define TRANSACTION_GENERIC_ERROR -2
|
||||||
int ref_transaction_commit(struct ref_transaction *transaction,
|
int ref_transaction_commit(struct ref_transaction *transaction,
|
||||||
const char *msg, struct strbuf *err);
|
struct strbuf *err);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Free an existing transaction and all associated data.
|
* Free an existing transaction and all associated data.
|
||||||
|
11
remote.c
11
remote.c
@ -508,7 +508,7 @@ static void read_config(void)
|
|||||||
return;
|
return;
|
||||||
default_remote_name = "origin";
|
default_remote_name = "origin";
|
||||||
current_branch = NULL;
|
current_branch = NULL;
|
||||||
head_ref = resolve_ref_unsafe("HEAD", sha1, 0, &flag);
|
head_ref = resolve_ref_unsafe("HEAD", 0, sha1, &flag);
|
||||||
if (head_ref && (flag & REF_ISSYMREF) &&
|
if (head_ref && (flag & REF_ISSYMREF) &&
|
||||||
skip_prefix(head_ref, "refs/heads/", &head_ref)) {
|
skip_prefix(head_ref, "refs/heads/", &head_ref)) {
|
||||||
current_branch = make_branch(head_ref, 0);
|
current_branch = make_branch(head_ref, 0);
|
||||||
@ -1138,7 +1138,8 @@ static char *guess_ref(const char *name, struct ref *peer)
|
|||||||
struct strbuf buf = STRBUF_INIT;
|
struct strbuf buf = STRBUF_INIT;
|
||||||
unsigned char sha1[20];
|
unsigned char sha1[20];
|
||||||
|
|
||||||
const char *r = resolve_ref_unsafe(peer->name, sha1, 1, NULL);
|
const char *r = resolve_ref_unsafe(peer->name, RESOLVE_REF_READING,
|
||||||
|
sha1, NULL);
|
||||||
if (!r)
|
if (!r)
|
||||||
return NULL;
|
return NULL;
|
||||||
|
|
||||||
@ -1199,7 +1200,9 @@ static int match_explicit(struct ref *src, struct ref *dst,
|
|||||||
unsigned char sha1[20];
|
unsigned char sha1[20];
|
||||||
int flag;
|
int flag;
|
||||||
|
|
||||||
dst_value = resolve_ref_unsafe(matched_src->name, sha1, 1, &flag);
|
dst_value = resolve_ref_unsafe(matched_src->name,
|
||||||
|
RESOLVE_REF_READING,
|
||||||
|
sha1, &flag);
|
||||||
if (!dst_value ||
|
if (!dst_value ||
|
||||||
((flag & REF_ISSYMREF) &&
|
((flag & REF_ISSYMREF) &&
|
||||||
!starts_with(dst_value, "refs/heads/")))
|
!starts_with(dst_value, "refs/heads/")))
|
||||||
@ -1673,7 +1676,7 @@ static int ignore_symref_update(const char *refname)
|
|||||||
unsigned char sha1[20];
|
unsigned char sha1[20];
|
||||||
int flag;
|
int flag;
|
||||||
|
|
||||||
if (!resolve_ref_unsafe(refname, sha1, 0, &flag))
|
if (!resolve_ref_unsafe(refname, 0, sha1, &flag))
|
||||||
return 0; /* non-existing refs are OK */
|
return 0; /* non-existing refs are OK */
|
||||||
return (flag & REF_ISSYMREF);
|
return (flag & REF_ISSYMREF);
|
||||||
}
|
}
|
||||||
|
@ -252,8 +252,8 @@ static int fast_forward_to(const unsigned char *to, const unsigned char *from,
|
|||||||
if (!transaction ||
|
if (!transaction ||
|
||||||
ref_transaction_update(transaction, "HEAD",
|
ref_transaction_update(transaction, "HEAD",
|
||||||
to, unborn ? null_sha1 : from,
|
to, unborn ? null_sha1 : from,
|
||||||
0, 1, &err) ||
|
0, 1, sb.buf, &err) ||
|
||||||
ref_transaction_commit(transaction, sb.buf, &err)) {
|
ref_transaction_commit(transaction, &err)) {
|
||||||
ref_transaction_free(transaction);
|
ref_transaction_free(transaction);
|
||||||
error("%s", err.buf);
|
error("%s", err.buf);
|
||||||
strbuf_release(&sb);
|
strbuf_release(&sb);
|
||||||
@ -331,7 +331,7 @@ static int is_index_unchanged(void)
|
|||||||
unsigned char head_sha1[20];
|
unsigned char head_sha1[20];
|
||||||
struct commit *head_commit;
|
struct commit *head_commit;
|
||||||
|
|
||||||
if (!resolve_ref_unsafe("HEAD", head_sha1, 1, NULL))
|
if (!resolve_ref_unsafe("HEAD", RESOLVE_REF_READING, head_sha1, NULL))
|
||||||
return error(_("Could not resolve HEAD commit\n"));
|
return error(_("Could not resolve HEAD commit\n"));
|
||||||
|
|
||||||
head_commit = lookup_commit(head_sha1);
|
head_commit = lookup_commit(head_sha1);
|
||||||
@ -871,7 +871,7 @@ static int rollback_single_pick(void)
|
|||||||
if (!file_exists(git_path("CHERRY_PICK_HEAD")) &&
|
if (!file_exists(git_path("CHERRY_PICK_HEAD")) &&
|
||||||
!file_exists(git_path("REVERT_HEAD")))
|
!file_exists(git_path("REVERT_HEAD")))
|
||||||
return error(_("no cherry-pick or revert in progress"));
|
return error(_("no cherry-pick or revert in progress"));
|
||||||
if (read_ref_full("HEAD", head_sha1, 0, NULL))
|
if (read_ref_full("HEAD", 0, head_sha1, NULL))
|
||||||
return error(_("cannot resolve HEAD"));
|
return error(_("cannot resolve HEAD"));
|
||||||
if (is_null_sha1(head_sha1))
|
if (is_null_sha1(head_sha1))
|
||||||
return error(_("cannot abort from a branch yet to be born"));
|
return error(_("cannot abort from a branch yet to be born"));
|
||||||
|
@ -110,6 +110,32 @@ test_expect_success "delete symref without dereference when the referred ref is
|
|||||||
cp -f .git/HEAD.orig .git/HEAD
|
cp -f .git/HEAD.orig .git/HEAD
|
||||||
git update-ref -d $m
|
git update-ref -d $m
|
||||||
|
|
||||||
|
test_expect_success 'update-ref -d is not confused by self-reference' '
|
||||||
|
git symbolic-ref refs/heads/self refs/heads/self &&
|
||||||
|
test_when_finished "rm -f .git/refs/heads/self" &&
|
||||||
|
test_path_is_file .git/refs/heads/self &&
|
||||||
|
test_must_fail git update-ref -d refs/heads/self &&
|
||||||
|
test_path_is_file .git/refs/heads/self
|
||||||
|
'
|
||||||
|
|
||||||
|
test_expect_success 'update-ref --no-deref -d can delete self-reference' '
|
||||||
|
git symbolic-ref refs/heads/self refs/heads/self &&
|
||||||
|
test_when_finished "rm -f .git/refs/heads/self" &&
|
||||||
|
test_path_is_file .git/refs/heads/self &&
|
||||||
|
git update-ref --no-deref -d refs/heads/self &&
|
||||||
|
test_path_is_missing .git/refs/heads/self
|
||||||
|
'
|
||||||
|
|
||||||
|
test_expect_success 'update-ref --no-deref -d can delete reference to bad ref' '
|
||||||
|
>.git/refs/heads/bad &&
|
||||||
|
test_when_finished "rm -f .git/refs/heads/bad" &&
|
||||||
|
git symbolic-ref refs/heads/ref-to-bad refs/heads/bad &&
|
||||||
|
test_when_finished "rm -f .git/refs/heads/ref-to-bad" &&
|
||||||
|
test_path_is_file .git/refs/heads/ref-to-bad &&
|
||||||
|
git update-ref --no-deref -d refs/heads/ref-to-bad &&
|
||||||
|
test_path_is_missing .git/refs/heads/ref-to-bad
|
||||||
|
'
|
||||||
|
|
||||||
test_expect_success '(not) create HEAD with old sha1' "
|
test_expect_success '(not) create HEAD with old sha1' "
|
||||||
test_must_fail git update-ref HEAD $A $B
|
test_must_fail git update-ref HEAD $A $B
|
||||||
"
|
"
|
||||||
@ -374,12 +400,6 @@ test_expect_success 'stdin fails create with no ref' '
|
|||||||
grep "fatal: create: missing <ref>" err
|
grep "fatal: create: missing <ref>" err
|
||||||
'
|
'
|
||||||
|
|
||||||
test_expect_success 'stdin fails create with bad ref name' '
|
|
||||||
echo "create ~a $m" >stdin &&
|
|
||||||
test_must_fail git update-ref --stdin <stdin 2>err &&
|
|
||||||
grep "fatal: invalid ref format: ~a" err
|
|
||||||
'
|
|
||||||
|
|
||||||
test_expect_success 'stdin fails create with no new value' '
|
test_expect_success 'stdin fails create with no new value' '
|
||||||
echo "create $a" >stdin &&
|
echo "create $a" >stdin &&
|
||||||
test_must_fail git update-ref --stdin <stdin 2>err &&
|
test_must_fail git update-ref --stdin <stdin 2>err &&
|
||||||
@ -398,12 +418,6 @@ test_expect_success 'stdin fails update with no ref' '
|
|||||||
grep "fatal: update: missing <ref>" err
|
grep "fatal: update: missing <ref>" err
|
||||||
'
|
'
|
||||||
|
|
||||||
test_expect_success 'stdin fails update with bad ref name' '
|
|
||||||
echo "update ~a $m" >stdin &&
|
|
||||||
test_must_fail git update-ref --stdin <stdin 2>err &&
|
|
||||||
grep "fatal: invalid ref format: ~a" err
|
|
||||||
'
|
|
||||||
|
|
||||||
test_expect_success 'stdin fails update with no new value' '
|
test_expect_success 'stdin fails update with no new value' '
|
||||||
echo "update $a" >stdin &&
|
echo "update $a" >stdin &&
|
||||||
test_must_fail git update-ref --stdin <stdin 2>err &&
|
test_must_fail git update-ref --stdin <stdin 2>err &&
|
||||||
@ -422,12 +436,6 @@ test_expect_success 'stdin fails delete with no ref' '
|
|||||||
grep "fatal: delete: missing <ref>" err
|
grep "fatal: delete: missing <ref>" err
|
||||||
'
|
'
|
||||||
|
|
||||||
test_expect_success 'stdin fails delete with bad ref name' '
|
|
||||||
echo "delete ~a $m" >stdin &&
|
|
||||||
test_must_fail git update-ref --stdin <stdin 2>err &&
|
|
||||||
grep "fatal: invalid ref format: ~a" err
|
|
||||||
'
|
|
||||||
|
|
||||||
test_expect_success 'stdin fails delete with too many arguments' '
|
test_expect_success 'stdin fails delete with too many arguments' '
|
||||||
echo "delete $a $m $m" >stdin &&
|
echo "delete $a $m $m" >stdin &&
|
||||||
test_must_fail git update-ref --stdin <stdin 2>err &&
|
test_must_fail git update-ref --stdin <stdin 2>err &&
|
||||||
@ -700,12 +708,6 @@ test_expect_success 'stdin -z fails create with no ref' '
|
|||||||
grep "fatal: create: missing <ref>" err
|
grep "fatal: create: missing <ref>" err
|
||||||
'
|
'
|
||||||
|
|
||||||
test_expect_success 'stdin -z fails create with bad ref name' '
|
|
||||||
printf $F "create ~a " "$m" >stdin &&
|
|
||||||
test_must_fail git update-ref -z --stdin <stdin 2>err &&
|
|
||||||
grep "fatal: invalid ref format: ~a " err
|
|
||||||
'
|
|
||||||
|
|
||||||
test_expect_success 'stdin -z fails create with no new value' '
|
test_expect_success 'stdin -z fails create with no new value' '
|
||||||
printf $F "create $a" >stdin &&
|
printf $F "create $a" >stdin &&
|
||||||
test_must_fail git update-ref -z --stdin <stdin 2>err &&
|
test_must_fail git update-ref -z --stdin <stdin 2>err &&
|
||||||
@ -730,12 +732,6 @@ test_expect_success 'stdin -z fails update with too few args' '
|
|||||||
grep "fatal: update $a: unexpected end of input when reading <oldvalue>" err
|
grep "fatal: update $a: unexpected end of input when reading <oldvalue>" err
|
||||||
'
|
'
|
||||||
|
|
||||||
test_expect_success 'stdin -z fails update with bad ref name' '
|
|
||||||
printf $F "update ~a" "$m" "" >stdin &&
|
|
||||||
test_must_fail git update-ref -z --stdin <stdin 2>err &&
|
|
||||||
grep "fatal: invalid ref format: ~a" err
|
|
||||||
'
|
|
||||||
|
|
||||||
test_expect_success 'stdin -z emits warning with empty new value' '
|
test_expect_success 'stdin -z emits warning with empty new value' '
|
||||||
git update-ref $a $m &&
|
git update-ref $a $m &&
|
||||||
printf $F "update $a" "" "" >stdin &&
|
printf $F "update $a" "" "" >stdin &&
|
||||||
@ -768,12 +764,6 @@ test_expect_success 'stdin -z fails delete with no ref' '
|
|||||||
grep "fatal: delete: missing <ref>" err
|
grep "fatal: delete: missing <ref>" err
|
||||||
'
|
'
|
||||||
|
|
||||||
test_expect_success 'stdin -z fails delete with bad ref name' '
|
|
||||||
printf $F "delete ~a" "$m" >stdin &&
|
|
||||||
test_must_fail git update-ref -z --stdin <stdin 2>err &&
|
|
||||||
grep "fatal: invalid ref format: ~a" err
|
|
||||||
'
|
|
||||||
|
|
||||||
test_expect_success 'stdin -z fails delete with no old value' '
|
test_expect_success 'stdin -z fails delete with no old value' '
|
||||||
printf $F "delete $a" >stdin &&
|
printf $F "delete $a" >stdin &&
|
||||||
test_must_fail git update-ref -z --stdin <stdin 2>err &&
|
test_must_fail git update-ref -z --stdin <stdin 2>err &&
|
||||||
|
70
t/t1413-reflog-detach.sh
Executable file
70
t/t1413-reflog-detach.sh
Executable file
@ -0,0 +1,70 @@
|
|||||||
|
#!/bin/sh
|
||||||
|
|
||||||
|
test_description='Test reflog interaction with detached HEAD'
|
||||||
|
. ./test-lib.sh
|
||||||
|
|
||||||
|
reset_state () {
|
||||||
|
git checkout master &&
|
||||||
|
cp saved_reflog .git/logs/HEAD
|
||||||
|
}
|
||||||
|
|
||||||
|
test_expect_success setup '
|
||||||
|
test_tick &&
|
||||||
|
git commit --allow-empty -m initial &&
|
||||||
|
git branch side &&
|
||||||
|
test_tick &&
|
||||||
|
git commit --allow-empty -m second &&
|
||||||
|
cat .git/logs/HEAD >saved_reflog
|
||||||
|
'
|
||||||
|
|
||||||
|
test_expect_success baseline '
|
||||||
|
reset_state &&
|
||||||
|
git rev-parse master master^ >expect &&
|
||||||
|
git log -g --format=%H >actual &&
|
||||||
|
test_cmp expect actual
|
||||||
|
'
|
||||||
|
|
||||||
|
test_expect_success 'switch to branch' '
|
||||||
|
reset_state &&
|
||||||
|
git rev-parse side master master^ >expect &&
|
||||||
|
git checkout side &&
|
||||||
|
git log -g --format=%H >actual &&
|
||||||
|
test_cmp expect actual
|
||||||
|
'
|
||||||
|
|
||||||
|
test_expect_success 'detach to other' '
|
||||||
|
reset_state &&
|
||||||
|
git rev-parse master side master master^ >expect &&
|
||||||
|
git checkout side &&
|
||||||
|
git checkout master^0 &&
|
||||||
|
git log -g --format=%H >actual &&
|
||||||
|
test_cmp expect actual
|
||||||
|
'
|
||||||
|
|
||||||
|
test_expect_success 'detach to self' '
|
||||||
|
reset_state &&
|
||||||
|
git rev-parse master master master^ >expect &&
|
||||||
|
git checkout master^0 &&
|
||||||
|
git log -g --format=%H >actual &&
|
||||||
|
test_cmp expect actual
|
||||||
|
'
|
||||||
|
|
||||||
|
test_expect_success 'attach to self' '
|
||||||
|
reset_state &&
|
||||||
|
git rev-parse master master master master^ >expect &&
|
||||||
|
git checkout master^0 &&
|
||||||
|
git checkout master &&
|
||||||
|
git log -g --format=%H >actual &&
|
||||||
|
test_cmp expect actual
|
||||||
|
'
|
||||||
|
|
||||||
|
test_expect_success 'attach to other' '
|
||||||
|
reset_state &&
|
||||||
|
git rev-parse side master master master^ >expect &&
|
||||||
|
git checkout master^0 &&
|
||||||
|
git checkout side &&
|
||||||
|
git log -g --format=%H >actual &&
|
||||||
|
test_cmp expect actual
|
||||||
|
'
|
||||||
|
|
||||||
|
test_done
|
207
t/t1430-bad-ref-name.sh
Executable file
207
t/t1430-bad-ref-name.sh
Executable file
@ -0,0 +1,207 @@
|
|||||||
|
#!/bin/sh
|
||||||
|
|
||||||
|
test_description='Test handling of ref names that check-ref-format rejects'
|
||||||
|
. ./test-lib.sh
|
||||||
|
|
||||||
|
test_expect_success setup '
|
||||||
|
test_commit one &&
|
||||||
|
test_commit two
|
||||||
|
'
|
||||||
|
|
||||||
|
test_expect_success 'fast-import: fail on invalid branch name ".badbranchname"' '
|
||||||
|
test_when_finished "rm -f .git/objects/pack_* .git/objects/index_*" &&
|
||||||
|
cat >input <<-INPUT_END &&
|
||||||
|
commit .badbranchname
|
||||||
|
committer $GIT_COMMITTER_NAME <$GIT_COMMITTER_EMAIL> $GIT_COMMITTER_DATE
|
||||||
|
data <<COMMIT
|
||||||
|
corrupt
|
||||||
|
COMMIT
|
||||||
|
|
||||||
|
from refs/heads/master
|
||||||
|
|
||||||
|
INPUT_END
|
||||||
|
test_must_fail git fast-import <input
|
||||||
|
'
|
||||||
|
|
||||||
|
test_expect_success 'fast-import: fail on invalid branch name "bad[branch]name"' '
|
||||||
|
test_when_finished "rm -f .git/objects/pack_* .git/objects/index_*" &&
|
||||||
|
cat >input <<-INPUT_END &&
|
||||||
|
commit bad[branch]name
|
||||||
|
committer $GIT_COMMITTER_NAME <$GIT_COMMITTER_EMAIL> $GIT_COMMITTER_DATE
|
||||||
|
data <<COMMIT
|
||||||
|
corrupt
|
||||||
|
COMMIT
|
||||||
|
|
||||||
|
from refs/heads/master
|
||||||
|
|
||||||
|
INPUT_END
|
||||||
|
test_must_fail git fast-import <input
|
||||||
|
'
|
||||||
|
|
||||||
|
test_expect_success 'git branch shows badly named ref' '
|
||||||
|
cp .git/refs/heads/master .git/refs/heads/broken...ref &&
|
||||||
|
test_when_finished "rm -f .git/refs/heads/broken...ref" &&
|
||||||
|
git branch >output &&
|
||||||
|
grep -e "broken\.\.\.ref" output
|
||||||
|
'
|
||||||
|
|
||||||
|
test_expect_success 'branch -d can delete badly named ref' '
|
||||||
|
cp .git/refs/heads/master .git/refs/heads/broken...ref &&
|
||||||
|
test_when_finished "rm -f .git/refs/heads/broken...ref" &&
|
||||||
|
git branch -d broken...ref &&
|
||||||
|
git branch >output &&
|
||||||
|
! grep -e "broken\.\.\.ref" output
|
||||||
|
'
|
||||||
|
|
||||||
|
test_expect_success 'branch -D can delete badly named ref' '
|
||||||
|
cp .git/refs/heads/master .git/refs/heads/broken...ref &&
|
||||||
|
test_when_finished "rm -f .git/refs/heads/broken...ref" &&
|
||||||
|
git branch -D broken...ref &&
|
||||||
|
git branch >output &&
|
||||||
|
! grep -e "broken\.\.\.ref" output
|
||||||
|
'
|
||||||
|
|
||||||
|
test_expect_success 'branch -D cannot delete non-ref in .git dir' '
|
||||||
|
echo precious >.git/my-private-file &&
|
||||||
|
echo precious >expect &&
|
||||||
|
test_must_fail git branch -D ../../my-private-file &&
|
||||||
|
test_cmp expect .git/my-private-file
|
||||||
|
'
|
||||||
|
|
||||||
|
test_expect_success 'branch -D cannot delete absolute path' '
|
||||||
|
git branch -f extra &&
|
||||||
|
test_must_fail git branch -D "$(pwd)/.git/refs/heads/extra" &&
|
||||||
|
test_cmp_rev HEAD extra
|
||||||
|
'
|
||||||
|
|
||||||
|
test_expect_success 'git branch cannot create a badly named ref' '
|
||||||
|
test_when_finished "rm -f .git/refs/heads/broken...ref" &&
|
||||||
|
test_must_fail git branch broken...ref &&
|
||||||
|
git branch >output &&
|
||||||
|
! grep -e "broken\.\.\.ref" output
|
||||||
|
'
|
||||||
|
|
||||||
|
test_expect_success 'branch -m cannot rename to a bad ref name' '
|
||||||
|
test_when_finished "rm -f .git/refs/heads/broken...ref" &&
|
||||||
|
test_might_fail git branch -D goodref &&
|
||||||
|
git branch goodref &&
|
||||||
|
test_must_fail git branch -m goodref broken...ref &&
|
||||||
|
test_cmp_rev master goodref &&
|
||||||
|
git branch >output &&
|
||||||
|
! grep -e "broken\.\.\.ref" output
|
||||||
|
'
|
||||||
|
|
||||||
|
test_expect_failure 'branch -m can rename from a bad ref name' '
|
||||||
|
cp .git/refs/heads/master .git/refs/heads/broken...ref &&
|
||||||
|
test_when_finished "rm -f .git/refs/heads/broken...ref" &&
|
||||||
|
git branch -m broken...ref renamed &&
|
||||||
|
test_cmp_rev master renamed &&
|
||||||
|
git branch >output &&
|
||||||
|
! grep -e "broken\.\.\.ref" output
|
||||||
|
'
|
||||||
|
|
||||||
|
test_expect_success 'push cannot create a badly named ref' '
|
||||||
|
test_when_finished "rm -f .git/refs/heads/broken...ref" &&
|
||||||
|
test_must_fail git push "file://$(pwd)" HEAD:refs/heads/broken...ref &&
|
||||||
|
git branch >output &&
|
||||||
|
! grep -e "broken\.\.\.ref" output
|
||||||
|
'
|
||||||
|
|
||||||
|
test_expect_failure 'push --mirror can delete badly named ref' '
|
||||||
|
top=$(pwd) &&
|
||||||
|
git init src &&
|
||||||
|
git init dest &&
|
||||||
|
|
||||||
|
(
|
||||||
|
cd src &&
|
||||||
|
test_commit one
|
||||||
|
) &&
|
||||||
|
(
|
||||||
|
cd dest &&
|
||||||
|
test_commit two &&
|
||||||
|
git checkout --detach &&
|
||||||
|
cp .git/refs/heads/master .git/refs/heads/broken...ref
|
||||||
|
) &&
|
||||||
|
git -C src push --mirror "file://$top/dest" &&
|
||||||
|
git -C dest branch >output &&
|
||||||
|
! grep -e "broken\.\.\.ref" output
|
||||||
|
'
|
||||||
|
|
||||||
|
test_expect_success 'rev-parse skips symref pointing to broken name' '
|
||||||
|
test_when_finished "rm -f .git/refs/heads/broken...ref" &&
|
||||||
|
git branch shadow one &&
|
||||||
|
cp .git/refs/heads/master .git/refs/heads/broken...ref &&
|
||||||
|
git symbolic-ref refs/tags/shadow refs/heads/broken...ref &&
|
||||||
|
|
||||||
|
git rev-parse --verify one >expect &&
|
||||||
|
git rev-parse --verify shadow >actual 2>err &&
|
||||||
|
test_cmp expect actual &&
|
||||||
|
test_i18ngrep "ignoring.*refs/tags/shadow" err
|
||||||
|
'
|
||||||
|
|
||||||
|
test_expect_success 'update-ref --no-deref -d can delete reference to broken name' '
|
||||||
|
git symbolic-ref refs/heads/badname refs/heads/broken...ref &&
|
||||||
|
test_when_finished "rm -f .git/refs/heads/badname" &&
|
||||||
|
test_path_is_file .git/refs/heads/badname &&
|
||||||
|
git update-ref --no-deref -d refs/heads/badname &&
|
||||||
|
test_path_is_missing .git/refs/heads/badname
|
||||||
|
'
|
||||||
|
|
||||||
|
test_expect_success 'update-ref -d can delete broken name' '
|
||||||
|
cp .git/refs/heads/master .git/refs/heads/broken...ref &&
|
||||||
|
test_when_finished "rm -f .git/refs/heads/broken...ref" &&
|
||||||
|
git update-ref -d refs/heads/broken...ref &&
|
||||||
|
git branch >output &&
|
||||||
|
! grep -e "broken\.\.\.ref" output
|
||||||
|
'
|
||||||
|
|
||||||
|
test_expect_success 'update-ref -d cannot delete non-ref in .git dir' '
|
||||||
|
echo precious >.git/my-private-file &&
|
||||||
|
echo precious >expect &&
|
||||||
|
test_must_fail git update-ref -d my-private-file &&
|
||||||
|
test_cmp expect .git/my-private-file
|
||||||
|
'
|
||||||
|
|
||||||
|
test_expect_success 'update-ref -d cannot delete absolute path' '
|
||||||
|
git branch -f extra &&
|
||||||
|
test_must_fail git update-ref -d "$(pwd)/.git/refs/heads/extra" &&
|
||||||
|
test_cmp_rev HEAD extra
|
||||||
|
'
|
||||||
|
|
||||||
|
test_expect_success 'update-ref --stdin fails create with bad ref name' '
|
||||||
|
echo "create ~a refs/heads/master" >stdin &&
|
||||||
|
test_must_fail git update-ref --stdin <stdin 2>err &&
|
||||||
|
grep "fatal: invalid ref format: ~a" err
|
||||||
|
'
|
||||||
|
|
||||||
|
test_expect_success 'update-ref --stdin fails update with bad ref name' '
|
||||||
|
echo "update ~a refs/heads/master" >stdin &&
|
||||||
|
test_must_fail git update-ref --stdin <stdin 2>err &&
|
||||||
|
grep "fatal: invalid ref format: ~a" err
|
||||||
|
'
|
||||||
|
|
||||||
|
test_expect_success 'update-ref --stdin fails delete with bad ref name' '
|
||||||
|
echo "delete ~a refs/heads/master" >stdin &&
|
||||||
|
test_must_fail git update-ref --stdin <stdin 2>err &&
|
||||||
|
grep "fatal: invalid ref format: ~a" err
|
||||||
|
'
|
||||||
|
|
||||||
|
test_expect_success 'update-ref --stdin -z fails create with bad ref name' '
|
||||||
|
printf "%s\0" "create ~a " refs/heads/master >stdin &&
|
||||||
|
test_must_fail git update-ref -z --stdin <stdin 2>err &&
|
||||||
|
grep "fatal: invalid ref format: ~a " err
|
||||||
|
'
|
||||||
|
|
||||||
|
test_expect_success 'update-ref --stdin -z fails update with bad ref name' '
|
||||||
|
printf "%s\0" "update ~a" refs/heads/master "" >stdin &&
|
||||||
|
test_must_fail git update-ref -z --stdin <stdin 2>err &&
|
||||||
|
grep "fatal: invalid ref format: ~a" err
|
||||||
|
'
|
||||||
|
|
||||||
|
test_expect_success 'update-ref --stdin -z fails delete with bad ref name' '
|
||||||
|
printf "%s\0" "delete ~a" refs/heads/master >stdin &&
|
||||||
|
test_must_fail git update-ref -z --stdin <stdin 2>err &&
|
||||||
|
grep "fatal: invalid ref format: ~a" err
|
||||||
|
'
|
||||||
|
|
||||||
|
test_done
|
@ -285,6 +285,15 @@ test_expect_success 'deleting a dangling symref' '
|
|||||||
test_i18ncmp expect actual
|
test_i18ncmp expect actual
|
||||||
'
|
'
|
||||||
|
|
||||||
|
test_expect_success 'deleting a self-referential symref' '
|
||||||
|
git symbolic-ref refs/heads/self-reference refs/heads/self-reference &&
|
||||||
|
test_path_is_file .git/refs/heads/self-reference &&
|
||||||
|
echo "Deleted branch self-reference (was refs/heads/self-reference)." >expect &&
|
||||||
|
git branch -d self-reference >actual &&
|
||||||
|
test_path_is_missing .git/refs/heads/self-reference &&
|
||||||
|
test_i18ncmp expect actual
|
||||||
|
'
|
||||||
|
|
||||||
test_expect_success 'renaming a symref is not allowed' '
|
test_expect_success 'renaming a symref is not allowed' '
|
||||||
git symbolic-ref refs/heads/master2 refs/heads/master &&
|
git symbolic-ref refs/heads/master2 refs/heads/master &&
|
||||||
test_must_fail git branch -m master2 master3 &&
|
test_must_fail git branch -m master2 master3 &&
|
||||||
|
@ -350,10 +350,11 @@ test_expect_success 'git mv moves a submodule with a .git directory and .gitmodu
|
|||||||
'
|
'
|
||||||
|
|
||||||
test_expect_success 'git mv moves a submodule with gitfile' '
|
test_expect_success 'git mv moves a submodule with gitfile' '
|
||||||
rm -rf mod/sub &&
|
rm -rf mod &&
|
||||||
git reset --hard &&
|
git reset --hard &&
|
||||||
git submodule update &&
|
git submodule update &&
|
||||||
entry="$(git ls-files --stage sub | cut -f 1)" &&
|
entry="$(git ls-files --stage sub | cut -f 1)" &&
|
||||||
|
mkdir mod &&
|
||||||
(
|
(
|
||||||
cd mod &&
|
cd mod &&
|
||||||
git mv ../sub/ .
|
git mv ../sub/ .
|
||||||
@ -372,11 +373,12 @@ test_expect_success 'git mv moves a submodule with gitfile' '
|
|||||||
'
|
'
|
||||||
|
|
||||||
test_expect_success 'mv does not complain when no .gitmodules file is found' '
|
test_expect_success 'mv does not complain when no .gitmodules file is found' '
|
||||||
rm -rf mod/sub &&
|
rm -rf mod &&
|
||||||
git reset --hard &&
|
git reset --hard &&
|
||||||
git submodule update &&
|
git submodule update &&
|
||||||
git rm .gitmodules &&
|
git rm .gitmodules &&
|
||||||
entry="$(git ls-files --stage sub | cut -f 1)" &&
|
entry="$(git ls-files --stage sub | cut -f 1)" &&
|
||||||
|
mkdir mod &&
|
||||||
git mv sub mod/sub 2>actual.err &&
|
git mv sub mod/sub 2>actual.err &&
|
||||||
! test -s actual.err &&
|
! test -s actual.err &&
|
||||||
! test -e sub &&
|
! test -e sub &&
|
||||||
@ -390,11 +392,12 @@ test_expect_success 'mv does not complain when no .gitmodules file is found' '
|
|||||||
'
|
'
|
||||||
|
|
||||||
test_expect_success 'mv will error out on a modified .gitmodules file unless staged' '
|
test_expect_success 'mv will error out on a modified .gitmodules file unless staged' '
|
||||||
rm -rf mod/sub &&
|
rm -rf mod &&
|
||||||
git reset --hard &&
|
git reset --hard &&
|
||||||
git submodule update &&
|
git submodule update &&
|
||||||
git config -f .gitmodules foo.bar true &&
|
git config -f .gitmodules foo.bar true &&
|
||||||
entry="$(git ls-files --stage sub | cut -f 1)" &&
|
entry="$(git ls-files --stage sub | cut -f 1)" &&
|
||||||
|
mkdir mod &&
|
||||||
test_must_fail git mv sub mod/sub 2>actual.err &&
|
test_must_fail git mv sub mod/sub 2>actual.err &&
|
||||||
test -s actual.err &&
|
test -s actual.err &&
|
||||||
test -e sub &&
|
test -e sub &&
|
||||||
@ -413,13 +416,14 @@ test_expect_success 'mv will error out on a modified .gitmodules file unless sta
|
|||||||
'
|
'
|
||||||
|
|
||||||
test_expect_success 'mv issues a warning when section is not found in .gitmodules' '
|
test_expect_success 'mv issues a warning when section is not found in .gitmodules' '
|
||||||
rm -rf mod/sub &&
|
rm -rf mod &&
|
||||||
git reset --hard &&
|
git reset --hard &&
|
||||||
git submodule update &&
|
git submodule update &&
|
||||||
git config -f .gitmodules --remove-section submodule.sub &&
|
git config -f .gitmodules --remove-section submodule.sub &&
|
||||||
git add .gitmodules &&
|
git add .gitmodules &&
|
||||||
entry="$(git ls-files --stage sub | cut -f 1)" &&
|
entry="$(git ls-files --stage sub | cut -f 1)" &&
|
||||||
echo "warning: Could not find section in .gitmodules where path=sub" >expect.err &&
|
echo "warning: Could not find section in .gitmodules where path=sub" >expect.err &&
|
||||||
|
mkdir mod &&
|
||||||
git mv sub mod/sub 2>actual.err &&
|
git mv sub mod/sub 2>actual.err &&
|
||||||
test_i18ncmp expect.err actual.err &&
|
test_i18ncmp expect.err actual.err &&
|
||||||
! test -e sub &&
|
! test -e sub &&
|
||||||
@ -433,9 +437,10 @@ test_expect_success 'mv issues a warning when section is not found in .gitmodule
|
|||||||
'
|
'
|
||||||
|
|
||||||
test_expect_success 'mv --dry-run does not touch the submodule or .gitmodules' '
|
test_expect_success 'mv --dry-run does not touch the submodule or .gitmodules' '
|
||||||
rm -rf mod/sub &&
|
rm -rf mod &&
|
||||||
git reset --hard &&
|
git reset --hard &&
|
||||||
git submodule update &&
|
git submodule update &&
|
||||||
|
mkdir mod &&
|
||||||
git mv -n sub mod/sub 2>actual.err &&
|
git mv -n sub mod/sub 2>actual.err &&
|
||||||
test -f sub/.git &&
|
test -f sub/.git &&
|
||||||
git diff-index --exit-code HEAD &&
|
git diff-index --exit-code HEAD &&
|
||||||
|
@ -346,36 +346,6 @@ test_expect_success 'B: fail on invalid blob sha1' '
|
|||||||
'
|
'
|
||||||
rm -f .git/objects/pack_* .git/objects/index_*
|
rm -f .git/objects/pack_* .git/objects/index_*
|
||||||
|
|
||||||
cat >input <<INPUT_END
|
|
||||||
commit .badbranchname
|
|
||||||
committer $GIT_COMMITTER_NAME <$GIT_COMMITTER_EMAIL> $GIT_COMMITTER_DATE
|
|
||||||
data <<COMMIT
|
|
||||||
corrupt
|
|
||||||
COMMIT
|
|
||||||
|
|
||||||
from refs/heads/master
|
|
||||||
|
|
||||||
INPUT_END
|
|
||||||
test_expect_success 'B: fail on invalid branch name ".badbranchname"' '
|
|
||||||
test_must_fail git fast-import <input
|
|
||||||
'
|
|
||||||
rm -f .git/objects/pack_* .git/objects/index_*
|
|
||||||
|
|
||||||
cat >input <<INPUT_END
|
|
||||||
commit bad[branch]name
|
|
||||||
committer $GIT_COMMITTER_NAME <$GIT_COMMITTER_EMAIL> $GIT_COMMITTER_DATE
|
|
||||||
data <<COMMIT
|
|
||||||
corrupt
|
|
||||||
COMMIT
|
|
||||||
|
|
||||||
from refs/heads/master
|
|
||||||
|
|
||||||
INPUT_END
|
|
||||||
test_expect_success 'B: fail on invalid branch name "bad[branch]name"' '
|
|
||||||
test_must_fail git fast-import <input
|
|
||||||
'
|
|
||||||
rm -f .git/objects/pack_* .git/objects/index_*
|
|
||||||
|
|
||||||
cat >input <<INPUT_END
|
cat >input <<INPUT_END
|
||||||
commit TEMP_TAG
|
commit TEMP_TAG
|
||||||
committer $GIT_COMMITTER_NAME <$GIT_COMMITTER_EMAIL> $GIT_COMMITTER_DATE
|
committer $GIT_COMMITTER_NAME <$GIT_COMMITTER_EMAIL> $GIT_COMMITTER_DATE
|
||||||
|
@ -897,7 +897,10 @@ static int push_refs_with_export(struct transport *transport,
|
|||||||
int flag;
|
int flag;
|
||||||
|
|
||||||
/* Follow symbolic refs (mainly for HEAD). */
|
/* Follow symbolic refs (mainly for HEAD). */
|
||||||
name = resolve_ref_unsafe(ref->peer_ref->name, sha1, 1, &flag);
|
name = resolve_ref_unsafe(
|
||||||
|
ref->peer_ref->name,
|
||||||
|
RESOLVE_REF_READING,
|
||||||
|
sha1, &flag);
|
||||||
if (!name || !(flag & REF_ISSYMREF))
|
if (!name || !(flag & REF_ISSYMREF))
|
||||||
name = ref->peer_ref->name;
|
name = ref->peer_ref->name;
|
||||||
|
|
||||||
|
@ -168,7 +168,8 @@ static void set_upstreams(struct transport *transport, struct ref *refs,
|
|||||||
/* Follow symbolic refs (mainly for HEAD). */
|
/* Follow symbolic refs (mainly for HEAD). */
|
||||||
localname = ref->peer_ref->name;
|
localname = ref->peer_ref->name;
|
||||||
remotename = ref->name;
|
remotename = ref->name;
|
||||||
tmp = resolve_ref_unsafe(localname, sha, 1, &flag);
|
tmp = resolve_ref_unsafe(localname, RESOLVE_REF_READING,
|
||||||
|
sha, &flag);
|
||||||
if (tmp && flag & REF_ISSYMREF &&
|
if (tmp && flag & REF_ISSYMREF &&
|
||||||
starts_with(tmp, "refs/heads/"))
|
starts_with(tmp, "refs/heads/"))
|
||||||
localname = tmp;
|
localname = tmp;
|
||||||
@ -743,7 +744,7 @@ void transport_print_push_status(const char *dest, struct ref *refs,
|
|||||||
unsigned char head_sha1[20];
|
unsigned char head_sha1[20];
|
||||||
char *head;
|
char *head;
|
||||||
|
|
||||||
head = resolve_refdup("HEAD", head_sha1, 1, NULL);
|
head = resolve_refdup("HEAD", RESOLVE_REF_READING, head_sha1, NULL);
|
||||||
|
|
||||||
if (verbose) {
|
if (verbose) {
|
||||||
for (ref = refs; ref; ref = ref->next)
|
for (ref = refs; ref; ref = ref->next)
|
||||||
|
@ -744,7 +744,7 @@ static int find_symref(const char *refname, const unsigned char *sha1, int flag,
|
|||||||
|
|
||||||
if ((flag & REF_ISSYMREF) == 0)
|
if ((flag & REF_ISSYMREF) == 0)
|
||||||
return 0;
|
return 0;
|
||||||
symref_target = resolve_ref_unsafe(refname, unused, 0, &flag);
|
symref_target = resolve_ref_unsafe(refname, 0, unused, &flag);
|
||||||
if (!symref_target || (flag & REF_ISSYMREF) == 0)
|
if (!symref_target || (flag & REF_ISSYMREF) == 0)
|
||||||
die("'%s' is a symref but it is not?", refname);
|
die("'%s' is a symref but it is not?", refname);
|
||||||
item = string_list_append(cb_data, refname);
|
item = string_list_append(cb_data, refname);
|
||||||
|
5
walker.c
5
walker.c
@ -300,14 +300,13 @@ int walker_fetch(struct walker *walker, int targets, char **target,
|
|||||||
strbuf_addf(&refname, "refs/%s", write_ref[i]);
|
strbuf_addf(&refname, "refs/%s", write_ref[i]);
|
||||||
if (ref_transaction_update(transaction, refname.buf,
|
if (ref_transaction_update(transaction, refname.buf,
|
||||||
&sha1[20 * i], NULL, 0, 0,
|
&sha1[20 * i], NULL, 0, 0,
|
||||||
|
msg ? msg : "fetch (unknown)",
|
||||||
&err)) {
|
&err)) {
|
||||||
error("%s", err.buf);
|
error("%s", err.buf);
|
||||||
goto done;
|
goto done;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (ref_transaction_commit(transaction,
|
if (ref_transaction_commit(transaction, &err)) {
|
||||||
msg ? msg : "fetch (unknown)",
|
|
||||||
&err)) {
|
|
||||||
error("%s", err.buf);
|
error("%s", err.buf);
|
||||||
goto done;
|
goto done;
|
||||||
}
|
}
|
||||||
|
26
wrapper.c
26
wrapper.c
@ -466,17 +466,29 @@ int xmkstemp_mode(char *template, int mode)
|
|||||||
|
|
||||||
static int warn_if_unremovable(const char *op, const char *file, int rc)
|
static int warn_if_unremovable(const char *op, const char *file, int rc)
|
||||||
{
|
{
|
||||||
if (rc < 0) {
|
int err;
|
||||||
int err = errno;
|
if (!rc || errno == ENOENT)
|
||||||
if (ENOENT != err) {
|
return 0;
|
||||||
warning("unable to %s %s: %s",
|
err = errno;
|
||||||
op, file, strerror(errno));
|
warning("unable to %s %s: %s", op, file, strerror(errno));
|
||||||
errno = err;
|
errno = err;
|
||||||
}
|
|
||||||
}
|
|
||||||
return rc;
|
return rc;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int unlink_or_msg(const char *file, struct strbuf *err)
|
||||||
|
{
|
||||||
|
int rc = unlink(file);
|
||||||
|
|
||||||
|
assert(err);
|
||||||
|
|
||||||
|
if (!rc || errno == ENOENT)
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
strbuf_addf(err, "unable to unlink %s: %s",
|
||||||
|
file, strerror(errno));
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
int unlink_or_warn(const char *file)
|
int unlink_or_warn(const char *file)
|
||||||
{
|
{
|
||||||
return warn_if_unremovable("unlink", file, unlink(file));
|
return warn_if_unremovable("unlink", file, unlink(file));
|
||||||
|
@ -128,7 +128,7 @@ void wt_status_prepare(struct wt_status *s)
|
|||||||
s->show_untracked_files = SHOW_NORMAL_UNTRACKED_FILES;
|
s->show_untracked_files = SHOW_NORMAL_UNTRACKED_FILES;
|
||||||
s->use_color = -1;
|
s->use_color = -1;
|
||||||
s->relative_paths = 1;
|
s->relative_paths = 1;
|
||||||
s->branch = resolve_refdup("HEAD", sha1, 0, NULL);
|
s->branch = resolve_refdup("HEAD", 0, sha1, NULL);
|
||||||
s->reference = "HEAD";
|
s->reference = "HEAD";
|
||||||
s->fp = stdout;
|
s->fp = stdout;
|
||||||
s->index_file = get_index_file();
|
s->index_file = get_index_file();
|
||||||
|
Loading…
Reference in New Issue
Block a user