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 existence
This commit is contained in:
Junio C Hamano 2020-08-17 17:02:42 -07:00
Родитель a00bda2b2f 55dd8b9108
Коммит 95c687bf85
4 изменённых файлов: 36 добавлений и 139 удалений

Просмотреть файл

@ -148,12 +148,13 @@ still see a subset of the modifications.
LOGGING UPDATES
---------------
If config parameter "core.logAllRefUpdates" is true and the ref is one under
"refs/heads/", "refs/remotes/", "refs/notes/", or the symbolic ref HEAD; or
the file "$GIT_DIR/logs/<ref>" exists then `git update-ref` will append
a line to the log file "$GIT_DIR/logs/<ref>" (dereferencing all
symbolic refs before creating the log name) describing the change
in ref value. Log lines are formatted as:
If config parameter "core.logAllRefUpdates" is true and the ref is one
under "refs/heads/", "refs/remotes/", "refs/notes/", or a pseudoref
like HEAD or ORIG_HEAD; or the file "$GIT_DIR/logs/<ref>" exists then
`git update-ref` will append a line to the log file
"$GIT_DIR/logs/<ref>" (dereferencing all symbolic refs before creating
the log name) describing the change in ref value. Log lines are
formatted as:
oldsha1 SP newsha1 SP committer LF

127
refs.c
Просмотреть файл

@ -708,10 +708,9 @@ int dwim_log(const char *str, int len, struct object_id *oid, char **log)
static int is_per_worktree_ref(const char *refname)
{
return !strcmp(refname, "HEAD") ||
starts_with(refname, "refs/worktree/") ||
starts_with(refname, "refs/bisect/") ||
starts_with(refname, "refs/rewritten/");
return starts_with(refname, "refs/worktree/") ||
starts_with(refname, "refs/bisect/") ||
starts_with(refname, "refs/rewritten/");
}
static int is_pseudoref_syntax(const char *refname)
@ -771,102 +770,6 @@ long get_files_ref_lock_timeout_ms(void)
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,
const char *refname,
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 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);
if (!transaction ||
ref_transaction_delete(transaction, refname, old_oid,
@ -1210,18 +1108,13 @@ int refs_update_ref(struct ref_store *refs, const char *msg,
struct strbuf err = STRBUF_INIT;
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);
if (!t ||
ref_transaction_update(t, refname, new_oid, old_oid,
flags, msg, &err) ||
ref_transaction_commit(t, &err)) {
ret = 1;
ref_transaction_free(t);
}
t = ref_store_transaction_begin(refs, &err);
if (!t ||
ref_transaction_update(t, refname, new_oid, old_oid, flags, msg,
&err) ||
ref_transaction_commit(t, &err)) {
ret = 1;
ref_transaction_free(t);
}
if (ret) {
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
'
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 &&
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' '
@ -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_must_fail git update-ref PSEUDOREF $A $B 2>err &&
test_path_is_missing .git/PSEUDOREF &&
test_i18ngrep "could not read ref" err
test_must_fail git rev-parse PSEUDOREF &&
test_i18ngrep "unable to resolve reference" err
'
test_expect_success 'create pseudoref' '
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' '
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' '
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_must_fail git update-ref PSEUDOREF $D $E 2>err &&
test $C = $(cat .git/PSEUDOREF) &&
test_i18ngrep "unexpected object ID" err
test $C = $(git rev-parse PSEUDOREF) &&
test_i18ngrep "cannot lock ref.*expected" err
'
test_expect_success 'delete 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' '
git update-ref PSEUDOREF $A &&
test_must_fail git update-ref -d PSEUDOREF $B 2>err &&
test $A = $(cat .git/PSEUDOREF) &&
test_i18ngrep "unexpected object ID" err
test $A = $(git rev-parse PSEUDOREF) &&
test_i18ngrep "cannot lock ref.*expected" err
'
test_expect_success 'delete pseudoref with correct old value' '
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' '
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_when_finished git update-ref -d PSEUDOREF &&
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
'

Просмотреть файл

@ -31,7 +31,10 @@ test_expect_success 'create_symref(FOO, refs/heads/master)' '
test_expect_success 'delete_refs(FOO, refs/tags/new-tag)' '
git rev-parse FOO -- &&
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 refs/tags/new-tag --
'