mirror of
https://github.com/git-for-windows/git.git
synced 2026-06-10 22:15:04 -05:00
Merge branch 'kn/refs-generic-helpers' into next
Refactor service routines in the ref subsystem backends. * kn/refs-generic-helpers: refs: use peeled tag values in reference backends refs: add peeled object ID to the `ref_update` struct refs: move object parsing to the generic layer update-ref: handle rejections while adding updates update-ref: move `print_rejected_refs()` up refs: return `ref_transaction_error` from `ref_transaction_update()` refs: extract out reflog config to generic layer refs: introduce `ref_store_init_options` refs: remove unused typedef 'ref_transaction_commit_fn'
This commit is contained in:
@@ -1642,8 +1642,8 @@ static const char *update(struct command *cmd, struct shallow_info *si)
|
||||
ret = NULL; /* good */
|
||||
}
|
||||
strbuf_release(&err);
|
||||
}
|
||||
else {
|
||||
} else {
|
||||
enum ref_transaction_error tx_err;
|
||||
struct strbuf err = STRBUF_INIT;
|
||||
if (shallow_update && si->shallow_ref[cmd->index] &&
|
||||
update_shallow_ref(cmd, si)) {
|
||||
@@ -1651,14 +1651,18 @@ static const char *update(struct command *cmd, struct shallow_info *si)
|
||||
goto out;
|
||||
}
|
||||
|
||||
if (ref_transaction_update(transaction,
|
||||
namespaced_name,
|
||||
new_oid, old_oid,
|
||||
NULL, NULL,
|
||||
0, "push",
|
||||
&err)) {
|
||||
tx_err = ref_transaction_update(transaction,
|
||||
namespaced_name,
|
||||
new_oid, old_oid,
|
||||
NULL, NULL,
|
||||
0, "push",
|
||||
&err);
|
||||
if (tx_err) {
|
||||
rp_error("%s", err.buf);
|
||||
ret = "failed to update ref";
|
||||
if (tx_err == REF_TRANSACTION_ERROR_GENERIC)
|
||||
ret = "failed to update ref";
|
||||
else
|
||||
ret = ref_transaction_error_msg(tx_err);
|
||||
} else {
|
||||
ret = NULL; /* good */
|
||||
}
|
||||
|
||||
@@ -25,6 +25,15 @@ static unsigned int default_flags;
|
||||
static unsigned create_reflog_flag;
|
||||
static const char *msg;
|
||||
|
||||
struct command_options {
|
||||
/*
|
||||
* Individual updates are allowed to fail without causing
|
||||
* update-ref to exit. This is set when using the
|
||||
* '--batch-updates' flag.
|
||||
*/
|
||||
bool allow_update_failures;
|
||||
};
|
||||
|
||||
/*
|
||||
* Parse one whitespace- or NUL-terminated, possibly C-quoted argument
|
||||
* and append the result to arg. Return a pointer to the terminator.
|
||||
@@ -234,6 +243,53 @@ static int parse_next_oid(const char **next, const char *end,
|
||||
command, refname);
|
||||
}
|
||||
|
||||
static void print_rejected_refs(const char *refname,
|
||||
const struct object_id *old_oid,
|
||||
const struct object_id *new_oid,
|
||||
const char *old_target,
|
||||
const char *new_target,
|
||||
enum ref_transaction_error err,
|
||||
const char *details,
|
||||
void *cb_data UNUSED)
|
||||
{
|
||||
struct strbuf sb = STRBUF_INIT;
|
||||
|
||||
if (details && *details)
|
||||
error("%s", details);
|
||||
|
||||
strbuf_addf(&sb, "rejected %s %s %s %s\n", refname,
|
||||
new_oid ? oid_to_hex(new_oid) : new_target,
|
||||
old_oid ? oid_to_hex(old_oid) : old_target,
|
||||
ref_transaction_error_msg(err));
|
||||
|
||||
fwrite(sb.buf, sb.len, 1, stdout);
|
||||
strbuf_release(&sb);
|
||||
}
|
||||
|
||||
/*
|
||||
* Handle transaction errors. If we're using batches updates, we want to only
|
||||
* die for generic errors and print the remaining to the user.
|
||||
*/
|
||||
static void handle_ref_transaction_error(const char *refname,
|
||||
struct object_id *new_oid,
|
||||
struct object_id *old_oid,
|
||||
const char *new_target,
|
||||
const char *old_target,
|
||||
enum ref_transaction_error tx_err,
|
||||
struct strbuf *err,
|
||||
struct command_options *opts)
|
||||
{
|
||||
if (!tx_err)
|
||||
return;
|
||||
|
||||
if (tx_err != REF_TRANSACTION_ERROR_GENERIC && opts->allow_update_failures) {
|
||||
print_rejected_refs(refname, old_oid, new_oid, old_target,
|
||||
new_target, tx_err, err->buf, NULL);
|
||||
return;
|
||||
}
|
||||
|
||||
die("%s", err->buf);
|
||||
}
|
||||
|
||||
/*
|
||||
* The following five parse_cmd_*() functions parse the corresponding
|
||||
@@ -246,11 +302,13 @@ static int parse_next_oid(const char **next, const char *end,
|
||||
*/
|
||||
|
||||
static void parse_cmd_update(struct ref_transaction *transaction,
|
||||
const char *next, const char *end)
|
||||
const char *next, const char *end,
|
||||
struct command_options *opts)
|
||||
{
|
||||
struct strbuf err = STRBUF_INIT;
|
||||
char *refname;
|
||||
struct object_id new_oid, old_oid;
|
||||
enum ref_transaction_error tx_err;
|
||||
int have_old;
|
||||
|
||||
refname = parse_refname(&next);
|
||||
@@ -267,12 +325,14 @@ static void parse_cmd_update(struct ref_transaction *transaction,
|
||||
if (*next != line_termination)
|
||||
die("update %s: extra input: %s", refname, next);
|
||||
|
||||
if (ref_transaction_update(transaction, refname,
|
||||
&new_oid, have_old ? &old_oid : NULL,
|
||||
NULL, NULL,
|
||||
update_flags | create_reflog_flag,
|
||||
msg, &err))
|
||||
die("%s", err.buf);
|
||||
tx_err = ref_transaction_update(transaction, refname,
|
||||
&new_oid, have_old ? &old_oid : NULL,
|
||||
NULL, NULL,
|
||||
update_flags | create_reflog_flag,
|
||||
msg, &err);
|
||||
handle_ref_transaction_error(refname, &new_oid, have_old ? &old_oid : NULL,
|
||||
NULL, NULL, tx_err, &err, opts);
|
||||
|
||||
|
||||
update_flags = default_flags;
|
||||
free(refname);
|
||||
@@ -280,9 +340,11 @@ static void parse_cmd_update(struct ref_transaction *transaction,
|
||||
}
|
||||
|
||||
static void parse_cmd_symref_update(struct ref_transaction *transaction,
|
||||
const char *next, const char *end UNUSED)
|
||||
const char *next, const char *end UNUSED,
|
||||
struct command_options *opts)
|
||||
{
|
||||
char *refname, *new_target, *old_arg;
|
||||
enum ref_transaction_error tx_err;
|
||||
char *old_target = NULL;
|
||||
struct strbuf err = STRBUF_INIT;
|
||||
struct object_id old_oid;
|
||||
@@ -319,13 +381,15 @@ static void parse_cmd_symref_update(struct ref_transaction *transaction,
|
||||
if (*next != line_termination)
|
||||
die("symref-update %s: extra input: %s", refname, next);
|
||||
|
||||
if (ref_transaction_update(transaction, refname, NULL,
|
||||
have_old_oid ? &old_oid : NULL,
|
||||
new_target,
|
||||
have_old_oid ? NULL : old_target,
|
||||
update_flags | create_reflog_flag,
|
||||
msg, &err))
|
||||
die("%s", err.buf);
|
||||
tx_err = ref_transaction_update(transaction, refname, NULL,
|
||||
have_old_oid ? &old_oid : NULL,
|
||||
new_target,
|
||||
have_old_oid ? NULL : old_target,
|
||||
update_flags | create_reflog_flag,
|
||||
msg, &err);
|
||||
handle_ref_transaction_error(refname, NULL, have_old_oid ? &old_oid : NULL,
|
||||
new_target, have_old_oid ? NULL : old_target,
|
||||
tx_err, &err, opts);
|
||||
|
||||
update_flags = default_flags;
|
||||
free(refname);
|
||||
@@ -336,11 +400,13 @@ static void parse_cmd_symref_update(struct ref_transaction *transaction,
|
||||
}
|
||||
|
||||
static void parse_cmd_create(struct ref_transaction *transaction,
|
||||
const char *next, const char *end)
|
||||
const char *next, const char *end,
|
||||
struct command_options *opts)
|
||||
{
|
||||
struct strbuf err = STRBUF_INIT;
|
||||
char *refname;
|
||||
struct object_id new_oid;
|
||||
enum ref_transaction_error tx_err;
|
||||
|
||||
refname = parse_refname(&next);
|
||||
if (!refname)
|
||||
@@ -355,22 +421,24 @@ static void parse_cmd_create(struct ref_transaction *transaction,
|
||||
if (*next != line_termination)
|
||||
die("create %s: extra input: %s", refname, next);
|
||||
|
||||
if (ref_transaction_create(transaction, refname, &new_oid, NULL,
|
||||
update_flags | create_reflog_flag,
|
||||
msg, &err))
|
||||
die("%s", err.buf);
|
||||
tx_err = ref_transaction_create(transaction, refname, &new_oid, NULL,
|
||||
update_flags | create_reflog_flag,
|
||||
msg, &err);
|
||||
handle_ref_transaction_error(refname, &new_oid, NULL, NULL, NULL, tx_err,
|
||||
&err, opts);
|
||||
|
||||
update_flags = default_flags;
|
||||
free(refname);
|
||||
strbuf_release(&err);
|
||||
}
|
||||
|
||||
|
||||
static void parse_cmd_symref_create(struct ref_transaction *transaction,
|
||||
const char *next, const char *end UNUSED)
|
||||
const char *next, const char *end UNUSED,
|
||||
struct command_options *opts)
|
||||
{
|
||||
struct strbuf err = STRBUF_INIT;
|
||||
char *refname, *new_target;
|
||||
enum ref_transaction_error tx_err;
|
||||
|
||||
refname = parse_refname(&next);
|
||||
if (!refname)
|
||||
@@ -383,10 +451,11 @@ static void parse_cmd_symref_create(struct ref_transaction *transaction,
|
||||
if (*next != line_termination)
|
||||
die("symref-create %s: extra input: %s", refname, next);
|
||||
|
||||
if (ref_transaction_create(transaction, refname, NULL, new_target,
|
||||
update_flags | create_reflog_flag,
|
||||
msg, &err))
|
||||
die("%s", err.buf);
|
||||
tx_err = ref_transaction_create(transaction, refname, NULL, new_target,
|
||||
update_flags | create_reflog_flag,
|
||||
msg, &err);
|
||||
handle_ref_transaction_error(refname, NULL, NULL, new_target, NULL,
|
||||
tx_err, &err, opts);
|
||||
|
||||
update_flags = default_flags;
|
||||
free(refname);
|
||||
@@ -395,7 +464,8 @@ static void parse_cmd_symref_create(struct ref_transaction *transaction,
|
||||
}
|
||||
|
||||
static void parse_cmd_delete(struct ref_transaction *transaction,
|
||||
const char *next, const char *end)
|
||||
const char *next, const char *end,
|
||||
struct command_options *opts UNUSED)
|
||||
{
|
||||
struct strbuf err = STRBUF_INIT;
|
||||
char *refname;
|
||||
@@ -428,9 +498,9 @@ static void parse_cmd_delete(struct ref_transaction *transaction,
|
||||
strbuf_release(&err);
|
||||
}
|
||||
|
||||
|
||||
static void parse_cmd_symref_delete(struct ref_transaction *transaction,
|
||||
const char *next, const char *end UNUSED)
|
||||
const char *next, const char *end UNUSED,
|
||||
struct command_options *opts UNUSED)
|
||||
{
|
||||
struct strbuf err = STRBUF_INIT;
|
||||
char *refname, *old_target;
|
||||
@@ -457,9 +527,9 @@ static void parse_cmd_symref_delete(struct ref_transaction *transaction,
|
||||
strbuf_release(&err);
|
||||
}
|
||||
|
||||
|
||||
static void parse_cmd_verify(struct ref_transaction *transaction,
|
||||
const char *next, const char *end)
|
||||
const char *next, const char *end,
|
||||
struct command_options *opts UNUSED)
|
||||
{
|
||||
struct strbuf err = STRBUF_INIT;
|
||||
char *refname;
|
||||
@@ -486,7 +556,8 @@ static void parse_cmd_verify(struct ref_transaction *transaction,
|
||||
}
|
||||
|
||||
static void parse_cmd_symref_verify(struct ref_transaction *transaction,
|
||||
const char *next, const char *end UNUSED)
|
||||
const char *next, const char *end UNUSED,
|
||||
struct command_options *opts UNUSED)
|
||||
{
|
||||
struct strbuf err = STRBUF_INIT;
|
||||
struct object_id old_oid;
|
||||
@@ -528,7 +599,8 @@ static void report_ok(const char *command)
|
||||
}
|
||||
|
||||
static void parse_cmd_option(struct ref_transaction *transaction UNUSED,
|
||||
const char *next, const char *end UNUSED)
|
||||
const char *next, const char *end UNUSED,
|
||||
struct command_options *opts UNUSED)
|
||||
{
|
||||
const char *rest;
|
||||
if (skip_prefix(next, "no-deref", &rest) && *rest == line_termination)
|
||||
@@ -538,7 +610,8 @@ static void parse_cmd_option(struct ref_transaction *transaction UNUSED,
|
||||
}
|
||||
|
||||
static void parse_cmd_start(struct ref_transaction *transaction UNUSED,
|
||||
const char *next, const char *end UNUSED)
|
||||
const char *next, const char *end UNUSED,
|
||||
struct command_options *opts UNUSED)
|
||||
{
|
||||
if (*next != line_termination)
|
||||
die("start: extra input: %s", next);
|
||||
@@ -546,7 +619,8 @@ static void parse_cmd_start(struct ref_transaction *transaction UNUSED,
|
||||
}
|
||||
|
||||
static void parse_cmd_prepare(struct ref_transaction *transaction,
|
||||
const char *next, const char *end UNUSED)
|
||||
const char *next, const char *end UNUSED,
|
||||
struct command_options *opts UNUSED)
|
||||
{
|
||||
struct strbuf error = STRBUF_INIT;
|
||||
if (*next != line_termination)
|
||||
@@ -557,7 +631,8 @@ static void parse_cmd_prepare(struct ref_transaction *transaction,
|
||||
}
|
||||
|
||||
static void parse_cmd_abort(struct ref_transaction *transaction,
|
||||
const char *next, const char *end UNUSED)
|
||||
const char *next, const char *end UNUSED,
|
||||
struct command_options *opts UNUSED)
|
||||
{
|
||||
struct strbuf error = STRBUF_INIT;
|
||||
if (*next != line_termination)
|
||||
@@ -567,31 +642,9 @@ static void parse_cmd_abort(struct ref_transaction *transaction,
|
||||
report_ok("abort");
|
||||
}
|
||||
|
||||
static void print_rejected_refs(const char *refname,
|
||||
const struct object_id *old_oid,
|
||||
const struct object_id *new_oid,
|
||||
const char *old_target,
|
||||
const char *new_target,
|
||||
enum ref_transaction_error err,
|
||||
const char *details,
|
||||
void *cb_data UNUSED)
|
||||
{
|
||||
struct strbuf sb = STRBUF_INIT;
|
||||
|
||||
if (details && *details)
|
||||
error("%s", details);
|
||||
|
||||
strbuf_addf(&sb, "rejected %s %s %s %s\n", refname,
|
||||
new_oid ? oid_to_hex(new_oid) : new_target,
|
||||
old_oid ? oid_to_hex(old_oid) : old_target,
|
||||
ref_transaction_error_msg(err));
|
||||
|
||||
fwrite(sb.buf, sb.len, 1, stdout);
|
||||
strbuf_release(&sb);
|
||||
}
|
||||
|
||||
static void parse_cmd_commit(struct ref_transaction *transaction,
|
||||
const char *next, const char *end UNUSED)
|
||||
const char *next, const char *end UNUSED,
|
||||
struct command_options *opts UNUSED)
|
||||
{
|
||||
struct strbuf error = STRBUF_INIT;
|
||||
if (*next != line_termination)
|
||||
@@ -619,7 +672,8 @@ enum update_refs_state {
|
||||
|
||||
static const struct parse_cmd {
|
||||
const char *prefix;
|
||||
void (*fn)(struct ref_transaction *, const char *, const char *);
|
||||
void (*fn)(struct ref_transaction *, const char *, const char *,
|
||||
struct command_options *);
|
||||
unsigned args;
|
||||
enum update_refs_state state;
|
||||
} command[] = {
|
||||
@@ -645,6 +699,10 @@ static void update_refs_stdin(unsigned int flags)
|
||||
struct ref_transaction *transaction;
|
||||
int i, j;
|
||||
|
||||
struct command_options opts = {
|
||||
.allow_update_failures = flags & REF_TRANSACTION_ALLOW_FAILURE,
|
||||
};
|
||||
|
||||
transaction = ref_store_transaction_begin(get_main_ref_store(the_repository),
|
||||
flags, &err);
|
||||
if (!transaction)
|
||||
@@ -722,7 +780,7 @@ static void update_refs_stdin(unsigned int flags)
|
||||
}
|
||||
|
||||
cmd->fn(transaction, input.buf + strlen(cmd->prefix) + !!cmd->args,
|
||||
input.buf + input.len);
|
||||
input.buf + input.len, &opts);
|
||||
}
|
||||
|
||||
switch (state) {
|
||||
|
||||
60
refs.c
60
refs.c
@@ -1307,6 +1307,7 @@ struct ref_update *ref_transaction_add_update(
|
||||
const char *refname, unsigned int flags,
|
||||
const struct object_id *new_oid,
|
||||
const struct object_id *old_oid,
|
||||
const struct object_id *peeled,
|
||||
const char *new_target, const char *old_target,
|
||||
const char *committer_info,
|
||||
const char *msg)
|
||||
@@ -1339,6 +1340,8 @@ struct ref_update *ref_transaction_add_update(
|
||||
update->committer_info = xstrdup_or_null(committer_info);
|
||||
update->msg = normalize_reflog_message(msg);
|
||||
}
|
||||
if (flags & REF_HAVE_PEELED)
|
||||
oidcpy(&update->peeled, peeled);
|
||||
|
||||
/*
|
||||
* This list is generally used by the backends to avoid duplicates.
|
||||
@@ -1383,25 +1386,27 @@ static int transaction_refname_valid(const char *refname,
|
||||
return 1;
|
||||
}
|
||||
|
||||
int ref_transaction_update(struct ref_transaction *transaction,
|
||||
const char *refname,
|
||||
const struct object_id *new_oid,
|
||||
const struct object_id *old_oid,
|
||||
const char *new_target,
|
||||
const char *old_target,
|
||||
unsigned int flags, const char *msg,
|
||||
struct strbuf *err)
|
||||
enum ref_transaction_error ref_transaction_update(struct ref_transaction *transaction,
|
||||
const char *refname,
|
||||
const struct object_id *new_oid,
|
||||
const struct object_id *old_oid,
|
||||
const char *new_target,
|
||||
const char *old_target,
|
||||
unsigned int flags, const char *msg,
|
||||
struct strbuf *err)
|
||||
{
|
||||
struct object_id peeled;
|
||||
|
||||
assert(err);
|
||||
|
||||
if ((flags & REF_FORCE_CREATE_REFLOG) &&
|
||||
(flags & REF_SKIP_CREATE_REFLOG)) {
|
||||
strbuf_addstr(err, _("refusing to force and skip creation of reflog"));
|
||||
return -1;
|
||||
return REF_TRANSACTION_ERROR_GENERIC;
|
||||
}
|
||||
|
||||
if (!transaction_refname_valid(refname, new_oid, flags, err))
|
||||
return -1;
|
||||
return REF_TRANSACTION_ERROR_GENERIC;
|
||||
|
||||
if (flags & ~REF_TRANSACTION_UPDATE_ALLOWED_FLAGS)
|
||||
BUG("illegal flags 0x%x passed to ref_transaction_update()", flags);
|
||||
@@ -1416,8 +1421,32 @@ int ref_transaction_update(struct ref_transaction *transaction,
|
||||
flags |= (new_oid ? REF_HAVE_NEW : 0) | (old_oid ? REF_HAVE_OLD : 0);
|
||||
flags |= (new_target ? REF_HAVE_NEW : 0) | (old_target ? REF_HAVE_OLD : 0);
|
||||
|
||||
if ((flags & REF_HAVE_NEW) && !new_target && !is_null_oid(new_oid) &&
|
||||
!(flags & REF_SKIP_OID_VERIFICATION) && !(flags & REF_LOG_ONLY)) {
|
||||
struct object *o = parse_object(transaction->ref_store->repo, new_oid);
|
||||
|
||||
if (!o) {
|
||||
strbuf_addf(err,
|
||||
_("trying to write ref '%s' with nonexistent object %s"),
|
||||
refname, oid_to_hex(new_oid));
|
||||
return REF_TRANSACTION_ERROR_INVALID_NEW_VALUE;
|
||||
}
|
||||
|
||||
if (o->type != OBJ_COMMIT && is_branch(refname)) {
|
||||
strbuf_addf(err, _("trying to write non-commit object %s to branch '%s'"),
|
||||
oid_to_hex(new_oid), refname);
|
||||
return REF_TRANSACTION_ERROR_INVALID_NEW_VALUE;
|
||||
}
|
||||
|
||||
if (o->type == OBJ_TAG) {
|
||||
if (!peel_object(transaction->ref_store->repo, new_oid, &peeled,
|
||||
PEEL_OBJECT_VERIFY_TAGGED_OBJECT_TYPE))
|
||||
flags |= REF_HAVE_PEELED;
|
||||
}
|
||||
}
|
||||
|
||||
ref_transaction_add_update(transaction, refname, flags,
|
||||
new_oid, old_oid, new_target,
|
||||
new_oid, old_oid, &peeled, new_target,
|
||||
old_target, NULL, msg);
|
||||
|
||||
return 0;
|
||||
@@ -1444,7 +1473,7 @@ int ref_transaction_update_reflog(struct ref_transaction *transaction,
|
||||
return -1;
|
||||
|
||||
update = ref_transaction_add_update(transaction, refname, flags,
|
||||
new_oid, old_oid, NULL, NULL,
|
||||
new_oid, old_oid, NULL, NULL, NULL,
|
||||
committer_info, msg);
|
||||
update->index = index;
|
||||
|
||||
@@ -2295,6 +2324,10 @@ static struct ref_store *ref_store_init(struct repository *repo,
|
||||
{
|
||||
const struct ref_storage_be *be;
|
||||
struct ref_store *refs;
|
||||
struct ref_store_init_options opts = {
|
||||
.access_flags = flags,
|
||||
.log_all_ref_updates = repo_settings_get_log_all_ref_updates(repo),
|
||||
};
|
||||
|
||||
be = find_ref_storage_backend(format);
|
||||
if (!be)
|
||||
@@ -2304,7 +2337,8 @@ static struct ref_store *ref_store_init(struct repository *repo,
|
||||
* TODO Send in a 'struct worktree' instead of a 'gitdir', and
|
||||
* allow the backend to handle how it wants to deal with worktrees.
|
||||
*/
|
||||
refs = be->init(repo, repo->ref_storage_payload, gitdir, flags);
|
||||
refs = be->init(repo, repo->ref_storage_payload, gitdir, &opts);
|
||||
|
||||
return refs;
|
||||
}
|
||||
|
||||
|
||||
16
refs.h
16
refs.h
@@ -905,14 +905,14 @@ struct ref_transaction *ref_store_transaction_begin(struct ref_store *refs,
|
||||
* See the above comment "Reference transaction updates" for more
|
||||
* information.
|
||||
*/
|
||||
int ref_transaction_update(struct ref_transaction *transaction,
|
||||
const char *refname,
|
||||
const struct object_id *new_oid,
|
||||
const struct object_id *old_oid,
|
||||
const char *new_target,
|
||||
const char *old_target,
|
||||
unsigned int flags, const char *msg,
|
||||
struct strbuf *err);
|
||||
enum ref_transaction_error ref_transaction_update(struct ref_transaction *transaction,
|
||||
const char *refname,
|
||||
const struct object_id *new_oid,
|
||||
const struct object_id *old_oid,
|
||||
const char *new_target,
|
||||
const char *old_target,
|
||||
unsigned int flags, const char *msg,
|
||||
struct strbuf *err);
|
||||
|
||||
/*
|
||||
* Similar to `ref_transaction_update`, but this function is only for adding
|
||||
|
||||
@@ -19,7 +19,6 @@
|
||||
#include "../iterator.h"
|
||||
#include "../dir-iterator.h"
|
||||
#include "../lockfile.h"
|
||||
#include "../object.h"
|
||||
#include "../path.h"
|
||||
#include "../dir.h"
|
||||
#include "../chdir-notify.h"
|
||||
@@ -108,7 +107,7 @@ static void clear_loose_ref_cache(struct files_ref_store *refs)
|
||||
static struct ref_store *files_ref_store_init(struct repository *repo,
|
||||
const char *payload,
|
||||
const char *gitdir,
|
||||
unsigned int flags)
|
||||
const struct ref_store_init_options *opts)
|
||||
{
|
||||
struct files_ref_store *refs = xcalloc(1, sizeof(*refs));
|
||||
struct ref_store *ref_store = (struct ref_store *)refs;
|
||||
@@ -120,11 +119,13 @@ static struct ref_store *files_ref_store_init(struct repository *repo,
|
||||
&ref_common_dir);
|
||||
|
||||
base_ref_store_init(ref_store, repo, refdir.buf, &refs_be_files);
|
||||
refs->store_flags = flags;
|
||||
|
||||
refs->gitcommondir = strbuf_detach(&ref_common_dir, NULL);
|
||||
refs->packed_ref_store =
|
||||
packed_ref_store_init(repo, NULL, refs->gitcommondir, flags);
|
||||
refs->log_all_ref_updates = repo_settings_get_log_all_ref_updates(repo);
|
||||
packed_ref_store_init(repo, NULL, refs->gitcommondir, opts);
|
||||
refs->store_flags = opts->access_flags;
|
||||
refs->log_all_ref_updates = opts->log_all_ref_updates;
|
||||
|
||||
repo_config_get_bool(repo, "core.prefersymlinkrefs", &refs->prefer_symlink_refs);
|
||||
|
||||
chdir_notify_reparent("files-backend $GIT_DIR", &refs->base.gitdir);
|
||||
@@ -1331,7 +1332,8 @@ static void prune_ref(struct files_ref_store *refs, struct ref_to_prune *r)
|
||||
ref_transaction_add_update(
|
||||
transaction, r->name,
|
||||
REF_NO_DEREF | REF_HAVE_NEW | REF_HAVE_OLD | REF_IS_PRUNING,
|
||||
null_oid(the_hash_algo), &r->oid, NULL, NULL, NULL, NULL);
|
||||
null_oid(the_hash_algo), &r->oid, NULL, NULL, NULL,
|
||||
NULL, NULL);
|
||||
if (ref_transaction_commit(transaction, &err))
|
||||
goto cleanup;
|
||||
|
||||
@@ -1594,7 +1596,6 @@ static int rename_tmp_log(struct files_ref_store *refs, const char *newrefname)
|
||||
static enum ref_transaction_error write_ref_to_lockfile(struct files_ref_store *refs,
|
||||
struct ref_lock *lock,
|
||||
const struct object_id *oid,
|
||||
int skip_oid_verification,
|
||||
struct strbuf *err);
|
||||
static int commit_ref_update(struct files_ref_store *refs,
|
||||
struct ref_lock *lock,
|
||||
@@ -1742,7 +1743,7 @@ static int files_copy_or_rename_ref(struct ref_store *ref_store,
|
||||
}
|
||||
oidcpy(&lock->old_oid, &orig_oid);
|
||||
|
||||
if (write_ref_to_lockfile(refs, lock, &orig_oid, 0, &err) ||
|
||||
if (write_ref_to_lockfile(refs, lock, &orig_oid, &err) ||
|
||||
commit_ref_update(refs, lock, &orig_oid, logmsg, 0, &err)) {
|
||||
error("unable to write current sha1 into %s: %s", newrefname, err.buf);
|
||||
strbuf_release(&err);
|
||||
@@ -1760,7 +1761,7 @@ static int files_copy_or_rename_ref(struct ref_store *ref_store,
|
||||
goto rollbacklog;
|
||||
}
|
||||
|
||||
if (write_ref_to_lockfile(refs, lock, &orig_oid, 0, &err) ||
|
||||
if (write_ref_to_lockfile(refs, lock, &orig_oid, &err) ||
|
||||
commit_ref_update(refs, lock, &orig_oid, NULL, REF_SKIP_CREATE_REFLOG, &err)) {
|
||||
error("unable to write current sha1 into %s: %s", oldrefname, err.buf);
|
||||
strbuf_release(&err);
|
||||
@@ -2004,32 +2005,11 @@ static int files_log_ref_write(struct files_ref_store *refs,
|
||||
static enum ref_transaction_error write_ref_to_lockfile(struct files_ref_store *refs,
|
||||
struct ref_lock *lock,
|
||||
const struct object_id *oid,
|
||||
int skip_oid_verification,
|
||||
struct strbuf *err)
|
||||
{
|
||||
static char term = '\n';
|
||||
struct object *o;
|
||||
int fd;
|
||||
|
||||
if (!skip_oid_verification) {
|
||||
o = parse_object(refs->base.repo, oid);
|
||||
if (!o) {
|
||||
strbuf_addf(
|
||||
err,
|
||||
"trying to write ref '%s' with nonexistent object %s",
|
||||
lock->ref_name, oid_to_hex(oid));
|
||||
unlock_ref(lock);
|
||||
return REF_TRANSACTION_ERROR_INVALID_NEW_VALUE;
|
||||
}
|
||||
if (o->type != OBJ_COMMIT && is_branch(lock->ref_name)) {
|
||||
strbuf_addf(
|
||||
err,
|
||||
"trying to write non-commit object %s to branch '%s'",
|
||||
oid_to_hex(oid), lock->ref_name);
|
||||
unlock_ref(lock);
|
||||
return REF_TRANSACTION_ERROR_INVALID_NEW_VALUE;
|
||||
}
|
||||
}
|
||||
fd = get_lock_file_fd(&lock->lk);
|
||||
if (write_in_full(fd, oid_to_hex(oid), refs->base.repo->hash_algo->hexsz) < 0 ||
|
||||
write_in_full(fd, &term, 1) < 0 ||
|
||||
@@ -2496,7 +2476,7 @@ static enum ref_transaction_error split_head_update(struct ref_update *update,
|
||||
new_update = ref_transaction_add_update(
|
||||
transaction, "HEAD",
|
||||
update->flags | REF_LOG_ONLY | REF_NO_DEREF | REF_LOG_VIA_SPLIT,
|
||||
&update->new_oid, &update->old_oid,
|
||||
&update->new_oid, &update->old_oid, &update->peeled,
|
||||
NULL, NULL, update->committer_info, update->msg);
|
||||
new_update->parent_update = update;
|
||||
|
||||
@@ -2558,8 +2538,8 @@ static enum ref_transaction_error split_symref_update(struct ref_update *update,
|
||||
transaction, referent, new_flags,
|
||||
update->new_target ? NULL : &update->new_oid,
|
||||
update->old_target ? NULL : &update->old_oid,
|
||||
update->new_target, update->old_target, NULL,
|
||||
update->msg);
|
||||
&update->peeled, update->new_target, update->old_target,
|
||||
NULL, update->msg);
|
||||
|
||||
new_update->parent_update = update;
|
||||
|
||||
@@ -2833,7 +2813,6 @@ static enum ref_transaction_error lock_ref_for_update(struct files_ref_store *re
|
||||
} else {
|
||||
ret = write_ref_to_lockfile(
|
||||
refs, lock, &update->new_oid,
|
||||
update->flags & REF_SKIP_OID_VERIFICATION,
|
||||
err);
|
||||
if (ret) {
|
||||
char *write_err = strbuf_detach(err, NULL);
|
||||
@@ -3023,7 +3002,7 @@ static int files_transaction_prepare(struct ref_store *ref_store,
|
||||
ref_transaction_add_update(
|
||||
packed_transaction, update->refname,
|
||||
REF_HAVE_NEW | REF_NO_DEREF,
|
||||
&update->new_oid, NULL,
|
||||
&update->new_oid, NULL, NULL,
|
||||
NULL, NULL, NULL, NULL);
|
||||
}
|
||||
}
|
||||
@@ -3229,19 +3208,22 @@ static int files_transaction_finish_initial(struct files_ref_store *refs,
|
||||
if (update->flags & REF_LOG_ONLY)
|
||||
ref_transaction_add_update(loose_transaction, update->refname,
|
||||
update->flags, &update->new_oid,
|
||||
&update->old_oid, NULL, NULL,
|
||||
&update->old_oid, &update->peeled,
|
||||
NULL, NULL,
|
||||
update->committer_info, update->msg);
|
||||
else
|
||||
ref_transaction_add_update(loose_transaction, update->refname,
|
||||
update->flags & ~REF_HAVE_OLD,
|
||||
update->new_target ? NULL : &update->new_oid, NULL,
|
||||
update->new_target, NULL, update->committer_info,
|
||||
&update->peeled, update->new_target,
|
||||
NULL, update->committer_info,
|
||||
NULL);
|
||||
} else {
|
||||
ref_transaction_add_update(packed_transaction, update->refname,
|
||||
update->flags & ~REF_HAVE_OLD,
|
||||
&update->new_oid, &update->old_oid,
|
||||
NULL, NULL, update->committer_info, NULL);
|
||||
&update->peeled, NULL, NULL,
|
||||
update->committer_info, NULL);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -218,14 +218,14 @@ static size_t snapshot_hexsz(const struct snapshot *snapshot)
|
||||
struct ref_store *packed_ref_store_init(struct repository *repo,
|
||||
const char *payload UNUSED,
|
||||
const char *gitdir,
|
||||
unsigned int store_flags)
|
||||
const struct ref_store_init_options *opts)
|
||||
{
|
||||
struct packed_ref_store *refs = xcalloc(1, sizeof(*refs));
|
||||
struct ref_store *ref_store = (struct ref_store *)refs;
|
||||
struct strbuf sb = STRBUF_INIT;
|
||||
|
||||
base_ref_store_init(ref_store, repo, gitdir, &refs_be_packed);
|
||||
refs->store_flags = store_flags;
|
||||
refs->store_flags = opts->access_flags;
|
||||
|
||||
strbuf_addf(&sb, "%s/packed-refs", gitdir);
|
||||
refs->path = strbuf_detach(&sb, NULL);
|
||||
@@ -1531,13 +1531,11 @@ static enum ref_transaction_error write_with_updates(struct packed_ref_store *re
|
||||
*/
|
||||
i++;
|
||||
} else {
|
||||
struct object_id peeled;
|
||||
int peel_error = peel_object(refs->base.repo, &update->new_oid,
|
||||
&peeled, PEEL_OBJECT_VERIFY_TAGGED_OBJECT_TYPE);
|
||||
bool peeled = update->flags & REF_HAVE_PEELED;
|
||||
|
||||
if (write_packed_entry(out, update->refname,
|
||||
&update->new_oid,
|
||||
peel_error ? NULL : &peeled))
|
||||
peeled ? &update->peeled : NULL))
|
||||
goto write_error;
|
||||
|
||||
i++;
|
||||
|
||||
@@ -3,6 +3,7 @@
|
||||
|
||||
struct repository;
|
||||
struct ref_transaction;
|
||||
struct ref_store_init_options;
|
||||
|
||||
/*
|
||||
* Support for storing references in a `packed-refs` file.
|
||||
@@ -16,7 +17,7 @@ struct ref_transaction;
|
||||
struct ref_store *packed_ref_store_init(struct repository *repo,
|
||||
const char *payload,
|
||||
const char *gitdir,
|
||||
unsigned int store_flags);
|
||||
const struct ref_store_init_options *options);
|
||||
|
||||
/*
|
||||
* Lock the packed-refs file for writing. Flags is passed to
|
||||
|
||||
@@ -39,6 +39,13 @@ struct ref_transaction;
|
||||
*/
|
||||
#define REF_LOG_ONLY (1 << 7)
|
||||
|
||||
/*
|
||||
* The reference contains a peeled object ID. This is used when the
|
||||
* new_oid is pointing to a tag object and the reference backend
|
||||
* wants to also store the peeled value for optimized retrieval.
|
||||
*/
|
||||
#define REF_HAVE_PEELED (1 << 15)
|
||||
|
||||
/*
|
||||
* Return the length of time to retry acquiring a loose reference lock
|
||||
* before giving up, in milliseconds:
|
||||
@@ -92,6 +99,12 @@ struct ref_update {
|
||||
*/
|
||||
struct object_id old_oid;
|
||||
|
||||
/*
|
||||
* If the new_oid points to a tag object, set this to the peeled
|
||||
* object ID for optimized retrieval without needed to hit the odb.
|
||||
*/
|
||||
struct object_id peeled;
|
||||
|
||||
/*
|
||||
* If set, point the reference to this value. This can also be
|
||||
* used to convert regular references to become symbolic refs.
|
||||
@@ -169,6 +182,7 @@ struct ref_update *ref_transaction_add_update(
|
||||
const char *refname, unsigned int flags,
|
||||
const struct object_id *new_oid,
|
||||
const struct object_id *old_oid,
|
||||
const struct object_id *peeled,
|
||||
const char *new_target, const char *old_target,
|
||||
const char *committer_info,
|
||||
const char *msg);
|
||||
@@ -385,6 +399,21 @@ struct ref_store;
|
||||
REF_STORE_ODB | \
|
||||
REF_STORE_MAIN)
|
||||
|
||||
/*
|
||||
* Options for initializing the ref backend. All backend-agnostic information
|
||||
* which backends required will be held here.
|
||||
*/
|
||||
struct ref_store_init_options {
|
||||
/* The kind of operations that the ref_store is allowed to perform. */
|
||||
unsigned int access_flags;
|
||||
|
||||
/*
|
||||
* Denotes under what conditions reflogs should be created when updating
|
||||
* references.
|
||||
*/
|
||||
enum log_refs_config log_all_ref_updates;
|
||||
};
|
||||
|
||||
/*
|
||||
* Initialize the ref_store for the specified gitdir. These functions
|
||||
* should call base_ref_store_init() to initialize the shared part of
|
||||
@@ -393,7 +422,7 @@ struct ref_store;
|
||||
typedef struct ref_store *ref_store_init_fn(struct repository *repo,
|
||||
const char *payload,
|
||||
const char *gitdir,
|
||||
unsigned int flags);
|
||||
const struct ref_store_init_options *opts);
|
||||
/*
|
||||
* Release all memory and resources associated with the ref store.
|
||||
*/
|
||||
@@ -421,10 +450,6 @@ typedef int ref_transaction_abort_fn(struct ref_store *refs,
|
||||
struct ref_transaction *transaction,
|
||||
struct strbuf *err);
|
||||
|
||||
typedef int ref_transaction_commit_fn(struct ref_store *refs,
|
||||
struct ref_transaction *transaction,
|
||||
struct strbuf *err);
|
||||
|
||||
typedef int optimize_fn(struct ref_store *ref_store,
|
||||
struct refs_optimize_opts *opts);
|
||||
|
||||
|
||||
@@ -12,7 +12,6 @@
|
||||
#include "../hex.h"
|
||||
#include "../ident.h"
|
||||
#include "../iterator.h"
|
||||
#include "../object.h"
|
||||
#include "../parse.h"
|
||||
#include "../path.h"
|
||||
#include "../refs.h"
|
||||
@@ -369,7 +368,7 @@ static int reftable_be_config(const char *var, const char *value,
|
||||
static struct ref_store *reftable_be_init(struct repository *repo,
|
||||
const char *payload,
|
||||
const char *gitdir,
|
||||
unsigned int store_flags)
|
||||
const struct ref_store_init_options *opts)
|
||||
{
|
||||
struct reftable_ref_store *refs = xcalloc(1, sizeof(*refs));
|
||||
struct strbuf ref_common_dir = STRBUF_INIT;
|
||||
@@ -386,8 +385,8 @@ static struct ref_store *reftable_be_init(struct repository *repo,
|
||||
|
||||
base_ref_store_init(&refs->base, repo, refdir.buf, &refs_be_reftable);
|
||||
strmap_init(&refs->worktree_backends);
|
||||
refs->store_flags = store_flags;
|
||||
refs->log_all_ref_updates = repo_settings_get_log_all_ref_updates(repo);
|
||||
refs->log_all_ref_updates = opts->log_all_ref_updates;
|
||||
refs->store_flags = opts->access_flags;
|
||||
|
||||
switch (repo->hash_algo->format_id) {
|
||||
case GIT_SHA1_FORMAT_ID:
|
||||
@@ -1081,25 +1080,6 @@ static enum ref_transaction_error prepare_single_update(struct reftable_ref_stor
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Verify that the new object ID is valid. */
|
||||
if ((u->flags & REF_HAVE_NEW) && !is_null_oid(&u->new_oid) &&
|
||||
!(u->flags & REF_SKIP_OID_VERIFICATION) &&
|
||||
!(u->flags & REF_LOG_ONLY)) {
|
||||
struct object *o = parse_object(refs->base.repo, &u->new_oid);
|
||||
if (!o) {
|
||||
strbuf_addf(err,
|
||||
_("trying to write ref '%s' with nonexistent object %s"),
|
||||
u->refname, oid_to_hex(&u->new_oid));
|
||||
return REF_TRANSACTION_ERROR_INVALID_NEW_VALUE;
|
||||
}
|
||||
|
||||
if (o->type != OBJ_COMMIT && is_branch(u->refname)) {
|
||||
strbuf_addf(err, _("trying to write non-commit object %s to branch '%s'"),
|
||||
oid_to_hex(&u->new_oid), u->refname);
|
||||
return REF_TRANSACTION_ERROR_INVALID_NEW_VALUE;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* When we update the reference that HEAD points to we enqueue
|
||||
* a second log-only update for HEAD so that its reflog is
|
||||
@@ -1126,8 +1106,8 @@ static enum ref_transaction_error prepare_single_update(struct reftable_ref_stor
|
||||
ref_transaction_add_update(
|
||||
transaction, "HEAD",
|
||||
u->flags | REF_LOG_ONLY | REF_NO_DEREF,
|
||||
&u->new_oid, &u->old_oid, NULL, NULL, NULL,
|
||||
u->msg);
|
||||
&u->new_oid, &u->old_oid, &u->peeled, NULL, NULL,
|
||||
NULL, u->msg);
|
||||
}
|
||||
|
||||
ret = reftable_backend_read_ref(be, rewritten_ref,
|
||||
@@ -1213,7 +1193,7 @@ static enum ref_transaction_error prepare_single_update(struct reftable_ref_stor
|
||||
transaction, referent->buf, new_flags,
|
||||
u->new_target ? NULL : &u->new_oid,
|
||||
u->old_target ? NULL : &u->old_oid,
|
||||
u->new_target, u->old_target,
|
||||
&u->peeled, u->new_target, u->old_target,
|
||||
u->committer_info, u->msg);
|
||||
|
||||
new_update->parent_update = u;
|
||||
@@ -1603,17 +1583,13 @@ static int write_transaction_table(struct reftable_writer *writer, void *cb_data
|
||||
goto done;
|
||||
} else if (u->flags & REF_HAVE_NEW) {
|
||||
struct reftable_ref_record ref = {0};
|
||||
struct object_id peeled;
|
||||
int peel_error;
|
||||
|
||||
ref.refname = (char *)u->refname;
|
||||
ref.update_index = ts;
|
||||
|
||||
peel_error = peel_object(arg->refs->base.repo, &u->new_oid, &peeled,
|
||||
PEEL_OBJECT_VERIFY_TAGGED_OBJECT_TYPE);
|
||||
if (!peel_error) {
|
||||
if (u->flags & REF_HAVE_PEELED) {
|
||||
ref.value_type = REFTABLE_REF_VAL2;
|
||||
memcpy(ref.value.val2.target_value, peeled.hash, GIT_MAX_RAWSZ);
|
||||
memcpy(ref.value.val2.target_value, u->peeled.hash, GIT_MAX_RAWSZ);
|
||||
memcpy(ref.value.val2.value, u->new_oid.hash, GIT_MAX_RAWSZ);
|
||||
} else if (!is_null_oid(&u->new_oid)) {
|
||||
ref.value_type = REFTABLE_REF_VAL1;
|
||||
|
||||
@@ -1196,6 +1196,20 @@ test_expect_success 'stdin -z create ref fails with empty new value' '
|
||||
test_must_fail git rev-parse --verify -q $c
|
||||
'
|
||||
|
||||
test_expect_success 'stdin -z create ref fails with non commit object' '
|
||||
printf $F "create $c" "$(test_oid 001)" >stdin &&
|
||||
test_must_fail git update-ref -z --stdin <stdin 2>err &&
|
||||
grep "fatal: trying to write ref ${SQ}$c${SQ} with nonexistent object" err &&
|
||||
test_must_fail git rev-parse --verify -q $c
|
||||
'
|
||||
|
||||
test_expect_success 'stdin -z update ref fails with non commit object' '
|
||||
printf $F "update $b" "$(test_oid 001)" "" >stdin &&
|
||||
test_must_fail git update-ref -z --stdin <stdin 2>err &&
|
||||
grep "fatal: trying to write ref ${SQ}$b${SQ} with nonexistent object" err &&
|
||||
test_must_fail git rev-parse --verify -q $c
|
||||
'
|
||||
|
||||
test_expect_success 'stdin -z update ref works with right old value' '
|
||||
printf $F "update $b" "$m~1" "$m" >stdin &&
|
||||
git update-ref -z --stdin <stdin &&
|
||||
|
||||
Reference in New Issue
Block a user