Merge branch 'hn/reftable-prep-part-2'
Further preliminary change to refs API. * hn/reftable-prep-part-2: Make HEAD a PSEUDOREF rather than PER_WORKTREE. Modify pseudo refs through ref backend storage t1400: use git rev-parse for testing PSEUDOREF existencemaint
commit
95c687bf85
|
@ -148,12 +148,13 @@ still see a subset of the modifications.
|
||||||
|
|
||||||
LOGGING UPDATES
|
LOGGING UPDATES
|
||||||
---------------
|
---------------
|
||||||
If config parameter "core.logAllRefUpdates" is true and the ref is one under
|
If config parameter "core.logAllRefUpdates" is true and the ref is one
|
||||||
"refs/heads/", "refs/remotes/", "refs/notes/", or the symbolic ref HEAD; or
|
under "refs/heads/", "refs/remotes/", "refs/notes/", or a pseudoref
|
||||||
the file "$GIT_DIR/logs/<ref>" exists then `git update-ref` will append
|
like HEAD or ORIG_HEAD; or the file "$GIT_DIR/logs/<ref>" exists then
|
||||||
a line to the log file "$GIT_DIR/logs/<ref>" (dereferencing all
|
`git update-ref` will append a line to the log file
|
||||||
symbolic refs before creating the log name) describing the change
|
"$GIT_DIR/logs/<ref>" (dereferencing all symbolic refs before creating
|
||||||
in ref value. Log lines are formatted as:
|
the log name) describing the change in ref value. Log lines are
|
||||||
|
formatted as:
|
||||||
|
|
||||||
oldsha1 SP newsha1 SP committer LF
|
oldsha1 SP newsha1 SP committer LF
|
||||||
|
|
||||||
|
|
113
refs.c
113
refs.c
|
@ -708,8 +708,7 @@ int dwim_log(const char *str, int len, struct object_id *oid, char **log)
|
||||||
|
|
||||||
static int is_per_worktree_ref(const char *refname)
|
static int is_per_worktree_ref(const char *refname)
|
||||||
{
|
{
|
||||||
return !strcmp(refname, "HEAD") ||
|
return starts_with(refname, "refs/worktree/") ||
|
||||||
starts_with(refname, "refs/worktree/") ||
|
|
||||||
starts_with(refname, "refs/bisect/") ||
|
starts_with(refname, "refs/bisect/") ||
|
||||||
starts_with(refname, "refs/rewritten/");
|
starts_with(refname, "refs/rewritten/");
|
||||||
}
|
}
|
||||||
|
@ -771,102 +770,6 @@ long get_files_ref_lock_timeout_ms(void)
|
||||||
return timeout_ms;
|
return timeout_ms;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int write_pseudoref(const char *pseudoref, const struct object_id *oid,
|
|
||||||
const struct object_id *old_oid, struct strbuf *err)
|
|
||||||
{
|
|
||||||
const char *filename;
|
|
||||||
int fd;
|
|
||||||
struct lock_file lock = LOCK_INIT;
|
|
||||||
struct strbuf buf = STRBUF_INIT;
|
|
||||||
int ret = -1;
|
|
||||||
|
|
||||||
if (!oid)
|
|
||||||
return 0;
|
|
||||||
|
|
||||||
strbuf_addf(&buf, "%s\n", oid_to_hex(oid));
|
|
||||||
|
|
||||||
filename = git_path("%s", pseudoref);
|
|
||||||
fd = hold_lock_file_for_update_timeout(&lock, filename, 0,
|
|
||||||
get_files_ref_lock_timeout_ms());
|
|
||||||
if (fd < 0) {
|
|
||||||
strbuf_addf(err, _("could not open '%s' for writing: %s"),
|
|
||||||
filename, strerror(errno));
|
|
||||||
goto done;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (old_oid) {
|
|
||||||
struct object_id actual_old_oid;
|
|
||||||
|
|
||||||
if (read_ref(pseudoref, &actual_old_oid)) {
|
|
||||||
if (!is_null_oid(old_oid)) {
|
|
||||||
strbuf_addf(err, _("could not read ref '%s'"),
|
|
||||||
pseudoref);
|
|
||||||
rollback_lock_file(&lock);
|
|
||||||
goto done;
|
|
||||||
}
|
|
||||||
} else if (is_null_oid(old_oid)) {
|
|
||||||
strbuf_addf(err, _("ref '%s' already exists"),
|
|
||||||
pseudoref);
|
|
||||||
rollback_lock_file(&lock);
|
|
||||||
goto done;
|
|
||||||
} else if (!oideq(&actual_old_oid, old_oid)) {
|
|
||||||
strbuf_addf(err, _("unexpected object ID when writing '%s'"),
|
|
||||||
pseudoref);
|
|
||||||
rollback_lock_file(&lock);
|
|
||||||
goto done;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (write_in_full(fd, buf.buf, buf.len) < 0) {
|
|
||||||
strbuf_addf(err, _("could not write to '%s'"), filename);
|
|
||||||
rollback_lock_file(&lock);
|
|
||||||
goto done;
|
|
||||||
}
|
|
||||||
|
|
||||||
commit_lock_file(&lock);
|
|
||||||
ret = 0;
|
|
||||||
done:
|
|
||||||
strbuf_release(&buf);
|
|
||||||
return ret;
|
|
||||||
}
|
|
||||||
|
|
||||||
static int delete_pseudoref(const char *pseudoref, const struct object_id *old_oid)
|
|
||||||
{
|
|
||||||
const char *filename;
|
|
||||||
|
|
||||||
filename = git_path("%s", pseudoref);
|
|
||||||
|
|
||||||
if (old_oid && !is_null_oid(old_oid)) {
|
|
||||||
struct lock_file lock = LOCK_INIT;
|
|
||||||
int fd;
|
|
||||||
struct object_id actual_old_oid;
|
|
||||||
|
|
||||||
fd = hold_lock_file_for_update_timeout(
|
|
||||||
&lock, filename, 0,
|
|
||||||
get_files_ref_lock_timeout_ms());
|
|
||||||
if (fd < 0) {
|
|
||||||
error_errno(_("could not open '%s' for writing"),
|
|
||||||
filename);
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
if (read_ref(pseudoref, &actual_old_oid))
|
|
||||||
die(_("could not read ref '%s'"), pseudoref);
|
|
||||||
if (!oideq(&actual_old_oid, old_oid)) {
|
|
||||||
error(_("unexpected object ID when deleting '%s'"),
|
|
||||||
pseudoref);
|
|
||||||
rollback_lock_file(&lock);
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
unlink(filename);
|
|
||||||
rollback_lock_file(&lock);
|
|
||||||
} else {
|
|
||||||
unlink(filename);
|
|
||||||
}
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
int refs_delete_ref(struct ref_store *refs, const char *msg,
|
int refs_delete_ref(struct ref_store *refs, const char *msg,
|
||||||
const char *refname,
|
const char *refname,
|
||||||
const struct object_id *old_oid,
|
const struct object_id *old_oid,
|
||||||
|
@ -875,11 +778,6 @@ int refs_delete_ref(struct ref_store *refs, const char *msg,
|
||||||
struct ref_transaction *transaction;
|
struct ref_transaction *transaction;
|
||||||
struct strbuf err = STRBUF_INIT;
|
struct strbuf err = STRBUF_INIT;
|
||||||
|
|
||||||
if (ref_type(refname) == REF_TYPE_PSEUDOREF) {
|
|
||||||
assert(refs == get_main_ref_store(the_repository));
|
|
||||||
return delete_pseudoref(refname, old_oid);
|
|
||||||
}
|
|
||||||
|
|
||||||
transaction = ref_store_transaction_begin(refs, &err);
|
transaction = ref_store_transaction_begin(refs, &err);
|
||||||
if (!transaction ||
|
if (!transaction ||
|
||||||
ref_transaction_delete(transaction, refname, old_oid,
|
ref_transaction_delete(transaction, refname, old_oid,
|
||||||
|
@ -1210,19 +1108,14 @@ int refs_update_ref(struct ref_store *refs, const char *msg,
|
||||||
struct strbuf err = STRBUF_INIT;
|
struct strbuf err = STRBUF_INIT;
|
||||||
int ret = 0;
|
int ret = 0;
|
||||||
|
|
||||||
if (ref_type(refname) == REF_TYPE_PSEUDOREF) {
|
|
||||||
assert(refs == get_main_ref_store(the_repository));
|
|
||||||
ret = write_pseudoref(refname, new_oid, old_oid, &err);
|
|
||||||
} else {
|
|
||||||
t = ref_store_transaction_begin(refs, &err);
|
t = ref_store_transaction_begin(refs, &err);
|
||||||
if (!t ||
|
if (!t ||
|
||||||
ref_transaction_update(t, refname, new_oid, old_oid,
|
ref_transaction_update(t, refname, new_oid, old_oid, flags, msg,
|
||||||
flags, msg, &err) ||
|
&err) ||
|
||||||
ref_transaction_commit(t, &err)) {
|
ref_transaction_commit(t, &err)) {
|
||||||
ret = 1;
|
ret = 1;
|
||||||
ref_transaction_free(t);
|
ref_transaction_free(t);
|
||||||
}
|
}
|
||||||
}
|
|
||||||
if (ret) {
|
if (ret) {
|
||||||
const char *str = _("update_ref failed for ref '%s': %s");
|
const char *str = _("update_ref failed for ref '%s': %s");
|
||||||
|
|
||||||
|
|
|
@ -160,10 +160,10 @@ test_expect_success 'core.logAllRefUpdates=always creates reflog by default' '
|
||||||
git reflog exists $outside
|
git reflog exists $outside
|
||||||
'
|
'
|
||||||
|
|
||||||
test_expect_success 'core.logAllRefUpdates=always creates no reflog for ORIG_HEAD' '
|
test_expect_success 'core.logAllRefUpdates=always creates reflog for ORIG_HEAD' '
|
||||||
test_config core.logAllRefUpdates always &&
|
test_config core.logAllRefUpdates always &&
|
||||||
git update-ref ORIG_HEAD $A &&
|
git update-ref ORIG_HEAD $A &&
|
||||||
test_must_fail git reflog exists ORIG_HEAD
|
git reflog exists ORIG_HEAD
|
||||||
'
|
'
|
||||||
|
|
||||||
test_expect_success '--no-create-reflog overrides core.logAllRefUpdates=always' '
|
test_expect_success '--no-create-reflog overrides core.logAllRefUpdates=always' '
|
||||||
|
@ -475,57 +475,57 @@ test_expect_success 'git cat-file blob master@{2005-05-26 23:42}:F (expect OTHER
|
||||||
|
|
||||||
test_expect_success 'given old value for missing pseudoref, do not create' '
|
test_expect_success 'given old value for missing pseudoref, do not create' '
|
||||||
test_must_fail git update-ref PSEUDOREF $A $B 2>err &&
|
test_must_fail git update-ref PSEUDOREF $A $B 2>err &&
|
||||||
test_path_is_missing .git/PSEUDOREF &&
|
test_must_fail git rev-parse PSEUDOREF &&
|
||||||
test_i18ngrep "could not read ref" err
|
test_i18ngrep "unable to resolve reference" err
|
||||||
'
|
'
|
||||||
|
|
||||||
test_expect_success 'create pseudoref' '
|
test_expect_success 'create pseudoref' '
|
||||||
git update-ref PSEUDOREF $A &&
|
git update-ref PSEUDOREF $A &&
|
||||||
test $A = $(cat .git/PSEUDOREF)
|
test $A = $(git rev-parse PSEUDOREF)
|
||||||
'
|
'
|
||||||
|
|
||||||
test_expect_success 'overwrite pseudoref with no old value given' '
|
test_expect_success 'overwrite pseudoref with no old value given' '
|
||||||
git update-ref PSEUDOREF $B &&
|
git update-ref PSEUDOREF $B &&
|
||||||
test $B = $(cat .git/PSEUDOREF)
|
test $B = $(git rev-parse PSEUDOREF)
|
||||||
'
|
'
|
||||||
|
|
||||||
test_expect_success 'overwrite pseudoref with correct old value' '
|
test_expect_success 'overwrite pseudoref with correct old value' '
|
||||||
git update-ref PSEUDOREF $C $B &&
|
git update-ref PSEUDOREF $C $B &&
|
||||||
test $C = $(cat .git/PSEUDOREF)
|
test $C = $(git rev-parse PSEUDOREF)
|
||||||
'
|
'
|
||||||
|
|
||||||
test_expect_success 'do not overwrite pseudoref with wrong old value' '
|
test_expect_success 'do not overwrite pseudoref with wrong old value' '
|
||||||
test_must_fail git update-ref PSEUDOREF $D $E 2>err &&
|
test_must_fail git update-ref PSEUDOREF $D $E 2>err &&
|
||||||
test $C = $(cat .git/PSEUDOREF) &&
|
test $C = $(git rev-parse PSEUDOREF) &&
|
||||||
test_i18ngrep "unexpected object ID" err
|
test_i18ngrep "cannot lock ref.*expected" err
|
||||||
'
|
'
|
||||||
|
|
||||||
test_expect_success 'delete pseudoref' '
|
test_expect_success 'delete pseudoref' '
|
||||||
git update-ref -d PSEUDOREF &&
|
git update-ref -d PSEUDOREF &&
|
||||||
test_path_is_missing .git/PSEUDOREF
|
test_must_fail git rev-parse PSEUDOREF
|
||||||
'
|
'
|
||||||
|
|
||||||
test_expect_success 'do not delete pseudoref with wrong old value' '
|
test_expect_success 'do not delete pseudoref with wrong old value' '
|
||||||
git update-ref PSEUDOREF $A &&
|
git update-ref PSEUDOREF $A &&
|
||||||
test_must_fail git update-ref -d PSEUDOREF $B 2>err &&
|
test_must_fail git update-ref -d PSEUDOREF $B 2>err &&
|
||||||
test $A = $(cat .git/PSEUDOREF) &&
|
test $A = $(git rev-parse PSEUDOREF) &&
|
||||||
test_i18ngrep "unexpected object ID" err
|
test_i18ngrep "cannot lock ref.*expected" err
|
||||||
'
|
'
|
||||||
|
|
||||||
test_expect_success 'delete pseudoref with correct old value' '
|
test_expect_success 'delete pseudoref with correct old value' '
|
||||||
git update-ref -d PSEUDOREF $A &&
|
git update-ref -d PSEUDOREF $A &&
|
||||||
test_path_is_missing .git/PSEUDOREF
|
test_must_fail git rev-parse PSEUDOREF
|
||||||
'
|
'
|
||||||
|
|
||||||
test_expect_success 'create pseudoref with old OID zero' '
|
test_expect_success 'create pseudoref with old OID zero' '
|
||||||
git update-ref PSEUDOREF $A $Z &&
|
git update-ref PSEUDOREF $A $Z &&
|
||||||
test $A = $(cat .git/PSEUDOREF)
|
test $A = $(git rev-parse PSEUDOREF)
|
||||||
'
|
'
|
||||||
|
|
||||||
test_expect_success 'do not overwrite pseudoref with old OID zero' '
|
test_expect_success 'do not overwrite pseudoref with old OID zero' '
|
||||||
test_when_finished git update-ref -d PSEUDOREF &&
|
test_when_finished git update-ref -d PSEUDOREF &&
|
||||||
test_must_fail git update-ref PSEUDOREF $B $Z 2>err &&
|
test_must_fail git update-ref PSEUDOREF $B $Z 2>err &&
|
||||||
test $A = $(cat .git/PSEUDOREF) &&
|
test $A = $(git rev-parse PSEUDOREF) &&
|
||||||
test_i18ngrep "already exists" err
|
test_i18ngrep "already exists" err
|
||||||
'
|
'
|
||||||
|
|
||||||
|
|
|
@ -31,7 +31,10 @@ test_expect_success 'create_symref(FOO, refs/heads/master)' '
|
||||||
test_expect_success 'delete_refs(FOO, refs/tags/new-tag)' '
|
test_expect_success 'delete_refs(FOO, refs/tags/new-tag)' '
|
||||||
git rev-parse FOO -- &&
|
git rev-parse FOO -- &&
|
||||||
git rev-parse refs/tags/new-tag -- &&
|
git rev-parse refs/tags/new-tag -- &&
|
||||||
$RUN delete-refs 0 nothing FOO refs/tags/new-tag &&
|
m=$(git rev-parse master) &&
|
||||||
|
REF_NO_DEREF=1 &&
|
||||||
|
$RUN delete-refs $REF_NO_DEREF nothing FOO refs/tags/new-tag &&
|
||||||
|
test_must_fail git rev-parse --symbolic-full-name FOO &&
|
||||||
test_must_fail git rev-parse FOO -- &&
|
test_must_fail git rev-parse FOO -- &&
|
||||||
test_must_fail git rev-parse refs/tags/new-tag --
|
test_must_fail git rev-parse refs/tags/new-tag --
|
||||||
'
|
'
|
||||||
|
|
Loading…
Reference in New Issue