Reftable support git-core
Subsystems (2)
v20 cover Reftable support git-core
In reply to Han-Wen Nienhuys via GitGitGadgetThis adds the reftable library, and hooks it up as a ref backend.
This is still based on next, as there are conflicts basing on master.
Includes testing support, to test: make -C t/ GIT_TEST_REFTABLE=1
Summary 455 tests fail
v24
* rebase
* FETCH_HEAD special casing
Han-Wen Nienhuys (19):
refs: add \t to reflog in the files backend
Split off reading loose ref data in separate function
t1400: use git rev-parse for testing PSEUDOREF existence Modify pseudo refs through ref backend storage
Make HEAD a PSEUDOREF rather than PER_WORKTREE.
Make refs_ref_exists public
Treat CHERRY_PICK_HEAD as a pseudo ref
Treat REVERT_HEAD as a pseudo ref
Move REF_LOG_ONLY to refs-internal.h
Iteration over entire ref namespace is iterating over "refs/" Add .gitattributes for the reftable/ directory
Add reftable library
Add standalone build infrastructure for reftable Reftable support for git-core
Read FETCH_HEAD as loose ref
Hookup unittests for the reftable library.
Add GIT_DEBUG_REFS debugging mechanism
Add reftable testing infrastructure
Add "test-tool dump-reftable" command.
Johannes Schindelin (1):
vcxproj: adjust for the reftable changes
SZEDER Gábor (1):
git-prompt: prepare for reftable refs backend
Documentation/git-update-ref.txt | 13 +- .../technical/repository-version.txt | 7 + Makefile | 47 +- builtin/clone.c | 4 +- builtin/commit.c | 34 +- builtin/init-db.c | 55 +- builtin/merge.c | 2 +- builtin/worktree.c | 29 +- cache.h | 8 +- config.mak.uname | 2 +- contrib/buildsystems/Generators/Vcxproj.pm | 11 +- contrib/completion/git-prompt.sh | 7 +- path.c | 2 - path.h | 9 +- ref-filter.c | 7 +- refs.c | 171 +- refs.h | 6 + refs/debug.c | 387 +++++ refs/files-backend.c | 45 +- refs/refs-internal.h | 20 + refs/reftable-backend.c | 1415 +++++++++++++++++ reftable/.gitattributes | 1 + reftable/BUILD | 203 +++ reftable/LICENSE | 31 + reftable/README.md | 33 + reftable/VERSION | 1 + reftable/WORKSPACE | 14 + reftable/basics.c | 215 +++ reftable/basics.h | 53 + reftable/block.c | 432 +++++ reftable/block.h | 129 ++ reftable/block_test.c | 157 ++ reftable/compat.c | 98 ++ reftable/compat.h | 48 + reftable/constants.h | 21 + reftable/dump.c | 212 +++ reftable/file.c | 95 ++ reftable/iter.c | 242 +++ reftable/iter.h | 72 + reftable/merged.c | 317 ++++ reftable/merged.h | 43 + reftable/merged_test.c | 286 ++++ reftable/pq.c | 115 ++ reftable/pq.h | 34 + reftable/reader.c | 744 +++++++++ reftable/reader.h | 65 + reftable/record.c | 1126 +++++++++++++ reftable/record.h | 143 ++ reftable/record_test.c | 410 +++++ reftable/refname.c | 209 +++ reftable/refname.h | 38 + reftable/refname_test.c | 99 ++ reftable/reftable-tests.h | 22 + reftable/reftable.c | 154 ++ reftable/reftable.h | 585 +++++++ reftable/reftable_test.c | 632 ++++++++ reftable/stack.c | 1225 ++++++++++++++ reftable/stack.h | 50 + reftable/stack_test.c | 787 +++++++++ reftable/strbuf.c | 206 +++ reftable/strbuf.h | 88 + reftable/strbuf_test.c | 39 + reftable/system.h | 53 + reftable/test_framework.c | 69 + reftable/test_framework.h | 64 + reftable/tree.c | 63 + reftable/tree.h | 34 + reftable/tree_test.c | 62 + reftable/update.sh | 19 + reftable/writer.c | 663 ++++++++ reftable/writer.h | 60 + reftable/zlib-compat.c | 92 ++ reftable/zlib.BUILD | 36 + repository.c | 2 + repository.h | 3 + sequencer.c | 56 +- setup.c | 10 +- t/helper/test-reftable.c | 20 + t/helper/test-tool.c | 2 + t/helper/test-tool.h | 2 + t/t0031-reftable.sh | 185 +++ t/t0033-debug-refs.sh | 18 + t/t1400-update-ref.sh | 30 +- t/t1405-main-ref-store.sh | 5 +- t/t1409-avoid-packing-refs.sh | 6 + t/t1450-fsck.sh | 6 + t/t3210-pack-refs.sh | 6 + t/test-lib.sh | 5 + wt-status.c | 6 +- 89 files changed, 13076 insertions(+), 256 deletions(-) create mode 100644 refs/debug.c create mode 100644 refs/reftable-backend.c create mode 100644 reftable/.gitattributes create mode 100644 reftable/BUILD create mode 100644 reftable/LICENSE create mode 100644 reftable/README.md create mode 100644 reftable/VERSION create mode 100644 reftable/WORKSPACE create mode 100644 reftable/basics.c create mode 100644 reftable/basics.h create mode 100644 reftable/block.c create mode 100644 reftable/block.h create mode 100644 reftable/block_test.c create mode 100644 reftable/compat.c create mode 100644 reftable/compat.h create mode 100644 reftable/constants.h create mode 100644 reftable/dump.c create mode 100644 reftable/file.c create mode 100644 reftable/iter.c create mode 100644 reftable/iter.h create mode 100644 reftable/merged.c create mode 100644 reftable/merged.h create mode 100644 reftable/merged_test.c create mode 100644 reftable/pq.c create mode 100644 reftable/pq.h create mode 100644 reftable/reader.c create mode 100644 reftable/reader.h create mode 100644 reftable/record.c create mode 100644 reftable/record.h create mode 100644 reftable/record_test.c create mode 100644 reftable/refname.c create mode 100644 reftable/refname.h create mode 100644 reftable/refname_test.c create mode 100644 reftable/reftable-tests.h create mode 100644 reftable/reftable.c create mode 100644 reftable/reftable.h create mode 100644 reftable/reftable_test.c create mode 100644 reftable/stack.c create mode 100644 reftable/stack.h create mode 100644 reftable/stack_test.c create mode 100644 reftable/strbuf.c create mode 100644 reftable/strbuf.h create mode 100644 reftable/strbuf_test.c create mode 100644 reftable/system.h create mode 100644 reftable/test_framework.c create mode 100644 reftable/test_framework.h create mode 100644 reftable/tree.c create mode 100644 reftable/tree.h create mode 100644 reftable/tree_test.c create mode 100755 reftable/update.sh create mode 100644 reftable/writer.c create mode 100644 reftable/writer.h create mode 100644 reftable/zlib-compat.c create mode 100644 reftable/zlib.BUILD create mode 100644 t/helper/test-reftable.c create mode 100755 t/t0031-reftable.sh create mode 100755 t/t0033-debug-refs.sh
base-commit: e8ab941b671da6890181aea5b5755d1d9eea24ec
Published-As: https://github.com/gitgitgadget/git/releases/tag/pr-539%2Fhanwen%2Freftable-v20
Fetch-It-Via: git fetch https://github.com/gitgitgadget/git pr-539/hanwen/reftable-v20
Pull-Request: https://github.com/gitgitgadget/git/pull/539
Range-diff vs v19:
1: 596c316da4 < -: ---------- lib-t6000.sh: write tag using git-update-ref
2: 277da0cf7e < -: ---------- t3432: use git-reflog to inspect the reflog for HEAD
3: 125695ce92 < -: ---------- checkout: add '\n' to reflog message
-: ---------- > 1: 05ced51683 refs: add \t to reflog in the files backend
-: ---------- > 2: d0f0680c0e Split off reading loose ref data in separate function
-: ---------- > 3: 716cb30c1b t1400: use git rev-parse for testing PSEUDOREF existence
4: 5715681b3f ! 4: 400ffe531f Write pseudorefs through ref backends.
@@ Metadata
Author: Han-Wen Nienhuys <[email protected]>
## Commit message ##
- Write pseudorefs through ref backends.
+ Modify pseudo refs through ref backend storage
- Pseudorefs store transient data in in the repository. Examples are HEAD,
- CHERRY_PICK_HEAD, etc.
+ The previous behavior was introduced in commit 74ec19d4be
+ ("pseudorefs: create and use pseudoref update and delete functions",
+ Jul 31, 2015), with the justification "alternate ref backends still
+ need to store pseudorefs in GIT_DIR".
- These refs have always been read through the ref backends, but they were written
- in a one-off routine that wrote an object ID or symref directly into
- .git/<pseudo_ref_name>.
+ Refs such as REBASE_HEAD are read through the ref backend. This can
+ only work consistently if they are written through the ref backend as
+ well. Tooling that works directly on files under .git should be
+ updated to use git commands to read refs instead.
- This causes problems when introducing a new ref storage backend. To remedy this,
- extend the ref backend implementation with a write_pseudoref_fn and
- update_pseudoref_fn.
+ The following behaviors change:
+
+ * Updates to pseudorefs (eg. ORIG_HEAD) with
+ core.logAllRefUpdates=always will create reflogs for the pseudoref.
+
+ * non-HEAD pseudoref symrefs are also dereferenced on deletion. Update
+ t1405 accordingly.
Signed-off-by: Han-Wen Nienhuys <[email protected]>
- ## refs.c ##
-@@ refs.c: int ref_exists(const char *refname)
- return refs_ref_exists(get_main_ref_store(the_repository), refname);
- }
+ ## Documentation/git-update-ref.txt ##
+@@ Documentation/git-update-ref.txt: 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
-+int delete_pseudoref(const char *pseudoref, const struct object_id *old_oid)
-+{
-+ return refs_delete_pseudoref(get_main_ref_store(the_repository),
-+ pseudoref, old_oid);
-+}
-+
- static int filter_refs(const char *refname, const struct object_id *oid,
- int flags, void *data)
- {
+
+ ## refs.c ##
@@ refs.c: long get_files_ref_lock_timeout_ms(void)
return timeout_ms;
}
@@ refs.c: long get_files_ref_lock_timeout_ms(void)
-
- return 0;
-}
-
+-
int refs_delete_ref(struct ref_store *refs, const char *msg,
const char *refname,
+ const struct object_id *old_oid,
@@ refs.c: 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));
+- if (ref_type(refname) == REF_TYPE_PSEUDOREF) {
+- assert(refs == get_main_ref_store(the_repository));
- return delete_pseudoref(refname, old_oid);
-+ return refs_delete_pseudoref(refs, refname, old_oid);
- }
-
+- }
+-
transaction = ref_store_transaction_begin(refs, &err);
+ if (!transaction ||
+ ref_transaction_delete(transaction, refname, old_oid,
@@ refs.c: 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));
+- if (ref_type(refname) == REF_TYPE_PSEUDOREF) {
+- assert(refs == get_main_ref_store(the_repository));
- ret = write_pseudoref(refname, new_oid, old_oid, &err);
-+ ret = refs_write_pseudoref(refs, refname, new_oid, old_oid,
-+ &err);
- } else {
- t = ref_store_transaction_begin(refs, &err);
- if (!t ||
-@@ refs.c: int head_ref(each_ref_fn fn, void *cb_data)
- return refs_head_ref(get_main_ref_store(the_repository), fn, cb_data);
- }
-
-+int refs_write_pseudoref(struct ref_store *refs, const char *pseudoref,
-+ const struct object_id *oid,
-+ const struct object_id *old_oid, struct strbuf *err)
-+{
-+ return refs->be->write_pseudoref(refs, pseudoref, oid, old_oid, err);
-+}
-+
-+int refs_delete_pseudoref(struct ref_store *refs, const char *pseudoref,
-+ const struct object_id *old_oid)
-+{
-+ return refs->be->delete_pseudoref(refs, pseudoref, old_oid);
-+}
-+
- struct ref_iterator *refs_ref_iterator_begin(
- struct ref_store *refs,
- const char *prefix, int trim, int flags)
-
- ## refs.h ##
-@@ refs.h: int update_ref(const char *msg, const char *refname,
- const struct object_id *new_oid, const struct object_id *old_oid,
- unsigned int flags, enum action_on_err onerr);
-
-+/* Pseudorefs (eg. HEAD, CHERRY_PICK_HEAD) have a separate routines for updating
-+ and deletion as they cannot take part in normal transactional updates.
-+ Pseudorefs should only be written for the main repository.
-+*/
-+int refs_write_pseudoref(struct ref_store *refs, const char *pseudoref,
-+ const struct object_id *oid,
-+ const struct object_id *old_oid, struct strbuf *err);
-+int refs_delete_pseudoref(struct ref_store *refs, const char *pseudoref,
-+ const struct object_id *old_oid);
-+int delete_pseudoref(const char *pseudoref, const struct object_id *old_oid);
-+
- int parse_hide_refs_config(const char *var, const char *value, const char *);
-
- /*
-
- ## refs/files-backend.c ##
-@@ refs/files-backend.c: static int lock_raw_ref(struct files_ref_store *refs,
- return ret;
- }
-
-+static int files_write_pseudoref(struct ref_store *ref_store,
-+ const char *pseudoref,
-+ const struct object_id *oid,
-+ const struct object_id *old_oid,
-+ struct strbuf *err)
-+{
-+ struct files_ref_store *refs =
-+ files_downcast(ref_store, REF_STORE_READ, "write_pseudoref");
-+ int fd;
-+ struct lock_file lock = LOCK_INIT;
-+ struct strbuf filename = STRBUF_INIT;
-+ struct strbuf buf = STRBUF_INIT;
-+ int ret = -1;
-+
-+ if (!oid)
-+ return 0;
-+
-+ strbuf_addf(&filename, "%s/%s", refs->gitdir, pseudoref);
-+ fd = hold_lock_file_for_update_timeout(&lock, filename.buf, 0,
-+ get_files_ref_lock_timeout_ms());
-+ if (fd < 0) {
-+ strbuf_addf(err, _("could not open '%s' for writing: %s"),
-+ buf.buf, 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;
-+ }
-+ }
-+
-+ strbuf_addf(&buf, "%s\n", oid_to_hex(oid));
-+ if (write_in_full(fd, buf.buf, buf.len) < 0) {
-+ strbuf_addf(err, _("could not write to '%s'"), filename.buf);
-+ rollback_lock_file(&lock);
-+ goto done;
-+ }
-+
-+ commit_lock_file(&lock);
-+ ret = 0;
-+done:
-+ strbuf_release(&buf);
-+ strbuf_release(&filename);
-+ return ret;
-+}
-+
-+static int files_delete_pseudoref(struct ref_store *ref_store,
-+ const char *pseudoref,
-+ const struct object_id *old_oid)
-+{
-+ struct files_ref_store *refs =
-+ files_downcast(ref_store, REF_STORE_READ, "delete_pseudoref");
-+ struct strbuf filename = STRBUF_INIT;
-+ int ret = -1;
-+
-+ strbuf_addf(&filename, "%s/%s", refs->gitdir, 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.buf, 0,
-+ get_files_ref_lock_timeout_ms());
-+ if (fd < 0) {
-+ error_errno(_("could not open '%s' for writing"),
-+ filename.buf);
-+ goto done;
-+ }
-+ 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);
-+ goto done;
-+ }
-+
-+ unlink(filename.buf);
-+ rollback_lock_file(&lock);
-+ } else {
-+ unlink(filename.buf);
-+ }
-+ ret = 0;
-+done:
-+ strbuf_release(&filename);
-+ return ret;
-+}
-+
- struct files_ref_iterator {
- struct ref_iterator base;
-
-@@ refs/files-backend.c: struct ref_storage_be refs_be_files = {
- files_rename_ref,
- files_copy_ref,
-
-+ files_write_pseudoref,
-+ files_delete_pseudoref,
-+
- files_ref_iterator_begin,
- files_read_raw_ref,
-
-@@ refs/files-backend.c: struct ref_storage_be refs_be_files = {
- files_reflog_exists,
- files_create_reflog,
- files_delete_reflog,
-- files_reflog_expire
-+ files_reflog_expire,
- };
+- } 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");
- ## refs/packed-backend.c ##
-@@ refs/packed-backend.c: static int packed_copy_ref(struct ref_store *ref_store,
- BUG("packed reference store does not support copying references");
- }
-
-+static int packed_write_pseudoref(struct ref_store *ref_store,
-+ const char *pseudoref,
-+ const struct object_id *oid,
-+ const struct object_id *old_oid,
-+ struct strbuf *err)
-+{
-+ BUG("packed reference store does not support writing pseudo-references");
-+}
-+
-+static int packed_delete_pseudoref(struct ref_store *ref_store,
-+ const char *pseudoref,
-+ const struct object_id *old_oid)
-+{
-+ BUG("packed reference store does not support deleting pseudo-references");
-+}
-+
- static struct ref_iterator *packed_reflog_iterator_begin(struct ref_store *ref_store)
- {
- return empty_ref_iterator_begin();
-@@ refs/packed-backend.c: struct ref_storage_be refs_be_packed = {
- packed_rename_ref,
- packed_copy_ref,
-
-+ packed_write_pseudoref,
-+ packed_delete_pseudoref,
-+
- packed_ref_iterator_begin,
- packed_read_raw_ref,
-
-@@ refs/packed-backend.c: struct ref_storage_be refs_be_packed = {
- packed_reflog_exists,
- packed_create_reflog,
- packed_delete_reflog,
-- packed_reflog_expire
-+ packed_reflog_expire,
- };
+ ## t/t1400-update-ref.sh ##
+@@ t/t1400-update-ref.sh: 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' '
+@@ t/t1400-update-ref.sh: 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_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' '
+@@ t/t1400-update-ref.sh: test_expect_success 'overwrite pseudoref with correct 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 $C = $(git rev-parse PSEUDOREF) &&
+- test_i18ngrep "unexpected object ID" err
++ test_i18ngrep "cannot lock ref.*expected" err
+ '
+
+ test_expect_success 'delete pseudoref' '
+@@ t/t1400-update-ref.sh: 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 = $(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' '
- ## refs/refs-internal.h ##
-@@ refs/refs-internal.h: typedef int copy_ref_fn(struct ref_store *ref_store,
- const char *oldref, const char *newref,
- const char *logmsg);
-
-+typedef int write_pseudoref_fn(struct ref_store *ref_store,
-+ const char *pseudoref,
-+ const struct object_id *oid,
-+ const struct object_id *old_oid,
-+ struct strbuf *err);
-+
-+/*
-+ * Deletes a pseudoref. Deletion always succeeds (even if the pseudoref doesn't
-+ * exist.), except if old_oid is specified. If it is, it can fail due to lock
-+ * failure, failure reading the old OID, or an OID mismatch
-+ */
-+typedef int delete_pseudoref_fn(struct ref_store *ref_store,
-+ const char *pseudoref,
-+ const struct object_id *old_oid);
-+
- /*
- * Iterate over the references in `ref_store` whose names start with
- * `prefix`. `prefix` is matched as a literal string, without regard
-@@ refs/refs-internal.h: struct ref_storage_be {
- rename_ref_fn *rename_ref;
- copy_ref_fn *copy_ref;
-
-+ write_pseudoref_fn *write_pseudoref;
-+ delete_pseudoref_fn *delete_pseudoref;
-+
- ref_iterator_begin_fn *iterator_begin;
- read_raw_ref_fn *read_raw_ref;
-
+ ## t/t1405-main-ref-store.sh ##
+@@ t/t1405-main-ref-store.sh: 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 --
+ '
-: ---------- > 5: e9df96925b Make HEAD a PSEUDOREF rather than PER_WORKTREE.
5: c8cf2d2ce1 = 6: d33ea20fba Make refs_ref_exists public
6: e36b29de79 < -: ---------- Treat BISECT_HEAD as a pseudo ref
7: 1676df9851 ! 7: d12f6e905c Treat CHERRY_PICK_HEAD as a pseudo ref
@@ Metadata
## Commit message ##
Treat CHERRY_PICK_HEAD as a pseudo ref
- Check for existence and delete CHERRY_PICK_HEAD through pseudo ref functions.
+ Check for existence and delete CHERRY_PICK_HEAD through ref functions.
This will help cherry-pick work with alternate ref storage backends.
Signed-off-by: Han-Wen Nienhuys <[email protected]>
@@ sequencer.c: static void print_advice(struct repository *r, int show_hint,
* of the commit itself so remove CHERRY_PICK_HEAD
*/
- unlink(git_path_cherry_pick_head(r));
-+ refs_delete_pseudoref(get_main_ref_store(r), "CHERRY_PICK_HEAD",
-+ NULL);
++ refs_delete_ref(get_main_ref_store(r), "", "CHERRY_PICK_HEAD",
++ NULL, 0);
return;
}
@@ sequencer.c: static int do_commit(struct repository *r,
strbuf_release(&sb);
if (!res) {
- unlink(git_path_cherry_pick_head(r));
-+ refs_delete_pseudoref(get_main_ref_store(r),
-+ "CHERRY_PICK_HEAD", NULL);
++ refs_delete_ref(get_main_ref_store(r), "",
++ "CHERRY_PICK_HEAD", NULL, 0);
unlink(git_path_merge_msg(r));
if (!is_rebase_i(opts))
print_commit_summary(r, NULL, &oid,
@@ sequencer.c: static int do_pick_commit(struct repository *r,
} else if (allow == 2) {
drop_commit = 1;
- unlink(git_path_cherry_pick_head(r));
-+ refs_delete_pseudoref(get_main_ref_store(r), "CHERRY_PICK_HEAD",
-+ NULL);
++ refs_delete_ref(get_main_ref_store(r), "", "CHERRY_PICK_HEAD",
++ NULL, 0);
unlink(git_path_merge_msg(r));
fprintf(stderr,
_("dropping %s %s -- patch contents already upstream\n"),
@@ sequencer.c: void sequencer_post_commit_cleanup(struct repository *r, int verbos
- if (file_exists(git_path_cherry_pick_head(r))) {
- if (!unlink(git_path_cherry_pick_head(r)) && verbose)
+ if (refs_ref_exists(get_main_ref_store(r), "CHERRY_PICK_HEAD")) {
-+ if (!refs_delete_pseudoref(get_main_ref_store(r),
-+ "CHERRY_PICK_HEAD", NULL) &&
++ if (!refs_delete_ref(get_main_ref_store(r), "",
++ "CHERRY_PICK_HEAD", NULL, 0) &&
+ verbose)
warning(_("cancelling a cherry picking in progress"));
opts.action = REPLAY_PICK;
@@ sequencer.c: static int do_merge(struct repository *r,
strbuf_release(&ref_name);
- unlink(git_path_cherry_pick_head(r));
-+ refs_delete_pseudoref(get_main_ref_store(r), "CHERRY_PICK_HEAD",
-+ NULL);
++ refs_delete_ref(get_main_ref_store(r), "", "CHERRY_PICK_HEAD",
++ NULL, 0);
rollback_lock_file(&lock);
rollback_lock_file(&lock);
@@ sequencer.c: static int commit_staged_changes(struct repository *r,
- if (file_exists(cherry_pick_head) && unlink(cherry_pick_head))
+ if (refs_ref_exists(get_main_ref_store(r),
+ "CHERRY_PICK_HEAD") &&
-+ refs_delete_pseudoref(get_main_ref_store(r),
-+ "CHERRY_PICK_HEAD", NULL))
++ refs_delete_ref(get_main_ref_store(r), "",
++ "CHERRY_PICK_HEAD", NULL, 0))
return error(_("could not remove CHERRY_PICK_HEAD"));
if (!final_fixup)
return 0;
8: 0a5f97ea34 ! 8: 224f7bf224 Treat REVERT_HEAD as a pseudo ref
@@ sequencer.c: void sequencer_post_commit_cleanup(struct repository *r, int verbos
- if (file_exists(git_path_revert_head(r))) {
- if (!unlink(git_path_revert_head(r)) && verbose)
+ if (refs_ref_exists(get_main_ref_store(r), "REVERT_HEAD")) {
-+ if (!refs_delete_pseudoref(get_main_ref_store(r), "REVERT_HEAD",
-+ NULL) &&
++ if (!refs_delete_ref(get_main_ref_store(r), "", "REVERT_HEAD",
++ NULL, 0) &&
+ verbose)
warning(_("cancelling a revert in progress"));
opts.action = REPLAY_REVERT;
9: 9463ed9093 = 9: 4b601b545c Move REF_LOG_ONLY to refs-internal.h
10: a116aebe11 ! 10: ea8a78374f Iterate over the "refs/" namespace in for_each_[raw]ref @@ Metadata
Author: Han-Wen Nienhuys <[email protected]>
## Commit message ##
- Iterate over the "refs/" namespace in for_each_[raw]ref
+ Iteration over entire ref namespace is iterating over "refs/"
+
+ This changes behavior for in for_each_[raw]ref and
+ for_each_fullref_in_pattern.
This happens implicitly in the files/packed ref backend; making it explicit simplifies adding alternate ref storage backends, such as
@@ Commit message
+ ## ref-filter.c ##
+@@ ref-filter.c: static int for_each_fullref_in_pattern(struct ref_filter *filter,
+ {
+ struct string_list prefixes = STRING_LIST_INIT_DUP;
+ struct string_list_item *prefix;
++ const char *all = "refs/";
+ int ret;
+
+ if (!filter->match_as_path) {
+@@ ref-filter.c: static int for_each_fullref_in_pattern(struct ref_filter *filter,
+ * prefixes like "refs/heads/" etc. are stripped off,
+ * so we have to look at everything:
+ */
+- return for_each_fullref_in("", cb, cb_data, broken);
++ return for_each_fullref_in(all, cb, cb_data, broken);
+ }
+
+ if (filter->ignore_case) {
+@@ ref-filter.c: static int for_each_fullref_in_pattern(struct ref_filter *filter,
+ * so just return everything and let the caller
+ * sort it out.
+ */
+- return for_each_fullref_in("", cb, cb_data, broken);
++ return for_each_fullref_in(all, cb, cb_data, broken);
+ }
+
+ if (!filter->name_patterns[0]) {
+ /* no patterns; we have to look at everything */
+- return for_each_fullref_in("", cb, cb_data, broken);
++ return for_each_fullref_in(all, cb, cb_data, broken);
+ }
+
+ find_longest_prefixes(&prefixes, filter->name_patterns);
+
## refs.c ##
@@ refs.c: static int do_for_each_ref(struct ref_store *refs, const char *prefix,
11: e4545658ed = 11: 0606b2a1c8 Add .gitattributes for the reftable/ directory
12: 169f6c7f54 = 12: 12d98125c2 Add reftable library
13: d155240b16 = 13: 70ce4ce49d Add standalone build infrastructure for reftable
14: 073bff7279 ! 14: 7af3b2340e Reftable support for git-core
@@ builtin/init-db.c: int init_db(const char *git_dir, const char *real_git_dir,
git_config_set("receive.denyNonFastforwards", "true");
}
-+ git_config_set("extensions.refStorage", ref_storage_format);
++ if (!strcmp(ref_storage_format, "reftable"))
++ git_config_set("extensions.refStorage", ref_storage_format);
+
if (!(flags & INIT_DB_QUIET)) {
int len = strlen(git_dir);
@@ cache.h: int path_inside_repo(const char *prefix, const char *path);
void sanitize_stdfds(void);
int daemonize(void);
@@ cache.h: struct repository_format {
+ int is_bare;
int hash_algo;
- int has_extensions;
char *work_tree;
+ char *ref_storage;
struct string_list unknown_extensions;
+ struct string_list v1_only_extensions;
};
-
## refs.c ##
@@
@@ refs.c: struct ref_store *get_main_ref_store(struct repository *r)
- r->refs_private = ref_store_init(r->gitdir, REF_STORE_ALL_CAPS);
+ r->refs_private = ref_store_init(r->gitdir,
+ r->ref_storage_format ?
-+ r->ref_storage_format :
-+ default_ref_storage(),
++ r->ref_storage_format :
++ default_ref_storage(),
+ REF_STORE_ALL_CAPS);
return r->refs_private;
}
@@ refs/reftable-backend.c (new)
+ struct reftable_addition *add = NULL;
+ struct reftable_stack *stack =
+ transaction->nr ?
-+ stack_for(refs, transaction->updates[0]->refname) :
-+ refs->main_stack;
++ stack_for(refs, transaction->updates[0]->refname) :
++ refs->main_stack;
+ int err = refs->err;
+ if (err < 0) {
+ goto done;
@@ refs/reftable-backend.c (new)
+ return git_reftable_transaction_finish(ref_store, transaction, errmsg);
+}
+
-+struct write_pseudoref_arg {
-+ struct reftable_stack *stack;
-+ const char *pseudoref;
-+ const struct object_id *new_oid;
-+ const struct object_id *old_oid;
-+};
-+
-+static int write_pseudoref_table(struct reftable_writer *writer, void *argv)
-+{
-+ struct write_pseudoref_arg *arg = (struct write_pseudoref_arg *)argv;
-+ uint64_t ts = reftable_stack_next_update_index(arg->stack);
-+ int err = 0;
-+ struct reftable_ref_record read_ref = { NULL };
-+ struct reftable_ref_record write_ref = { NULL };
-+
-+ reftable_writer_set_limits(writer, ts, ts);
-+ if (arg->old_oid) {
-+ struct object_id read_oid;
-+ err = reftable_stack_read_ref(arg->stack, arg->pseudoref,
-+ &read_ref);
-+ if (err < 0)
-+ goto done;
-+
-+ if ((err > 0) != is_null_oid(arg->old_oid)) {
-+ err = REFTABLE_LOCK_ERROR;
-+ goto done;
-+ }
-+
-+ /* XXX If old_oid is set, and we have a symref? */
-+
-+ if (err == 0 && read_ref.value == NULL) {
-+ err = REFTABLE_LOCK_ERROR;
-+ goto done;
-+ }
-+
-+ hashcpy(read_oid.hash, read_ref.value);
-+ if (!oideq(arg->old_oid, &read_oid)) {
-+ err = REFTABLE_LOCK_ERROR;
-+ goto done;
-+ }
-+ }
-+
-+ write_ref.refname = (char *)arg->pseudoref;
-+ write_ref.update_index = ts;
-+ if (!is_null_oid(arg->new_oid))
-+ write_ref.value = (uint8_t *)arg->new_oid->hash;
-+
-+ err = reftable_writer_add_ref(writer, &write_ref);
-+done:
-+ assert(err != REFTABLE_API_ERROR);
-+ reftable_ref_record_clear(&read_ref);
-+ return err;
-+}
-+
-+static int git_reftable_write_pseudoref(struct ref_store *ref_store,
-+ const char *pseudoref,
-+ const struct object_id *oid,
-+ const struct object_id *old_oid,
-+ struct strbuf *errbuf)
-+{
-+ struct git_reftable_ref_store *refs =
-+ (struct git_reftable_ref_store *)ref_store;
-+ struct reftable_stack *stack = stack_for(refs, pseudoref);
-+ struct write_pseudoref_arg arg = {
-+ .stack = stack,
-+ .pseudoref = pseudoref,
-+ .new_oid = oid,
-+ };
-+ struct reftable_addition *add = NULL;
-+ int err = refs->err;
-+ if (err < 0) {
-+ goto done;
-+ }
-+
-+ err = reftable_stack_reload(stack);
-+ if (err) {
-+ goto done;
-+ }
-+ err = reftable_stack_new_addition(&add, stack);
-+ if (err) {
-+ goto done;
-+ }
-+ if (old_oid) {
-+ struct object_id actual_old_oid;
-+
-+ /* XXX this is cut & paste from files-backend - should factor
-+ * out? */
-+ if (read_ref(pseudoref, &actual_old_oid)) {
-+ if (!is_null_oid(old_oid)) {
-+ strbuf_addf(errbuf,
-+ _("could not read ref '%s'"),
-+ pseudoref);
-+ goto done;
-+ }
-+ } else if (is_null_oid(old_oid)) {
-+ strbuf_addf(errbuf, _("ref '%s' already exists"),
-+ pseudoref);
-+ goto done;
-+ } else if (!oideq(&actual_old_oid, old_oid)) {
-+ strbuf_addf(errbuf,
-+ _("unexpected object ID when writing '%s'"),
-+ pseudoref);
-+ goto done;
-+ }
-+ }
-+
-+ err = reftable_addition_add(add, &write_pseudoref_table, &arg);
-+ if (err < 0) {
-+ strbuf_addf(errbuf, "reftable: pseudoref update failure: %s",
-+ reftable_error_str(err));
-+ }
-+
-+ err = reftable_addition_commit(add);
-+ if (err < 0) {
-+ strbuf_addf(errbuf, "reftable: pseudoref commit failure: %s",
-+ reftable_error_str(err));
-+ }
-+
-+done:
-+ assert(err != REFTABLE_API_ERROR);
-+ reftable_addition_destroy(add);
-+ return err;
-+}
-+
-+static int reftable_delete_pseudoref(struct ref_store *ref_store,
-+ const char *pseudoref,
-+ const struct object_id *old_oid)
-+{
-+ struct strbuf errbuf = STRBUF_INIT;
-+ int ret = git_reftable_write_pseudoref(ref_store, pseudoref, &null_oid,
-+ old_oid, &errbuf);
-+ /* XXX what to do with the error message? */
-+ strbuf_release(&errbuf);
-+ return ret;
-+}
-+
+struct write_delete_refs_arg {
+ struct reftable_stack *stack;
+ struct string_list *refnames;
@@ refs/reftable-backend.c (new)
+static int git_reftable_reflog_exists(struct ref_store *ref_store,
+ const char *refname)
+{
-+ /* always exists. */
-+ return 1;
++ struct reftable_iterator it = { NULL };
++ struct git_reftable_ref_store *refs =
++ (struct git_reftable_ref_store *)ref_store;
++ struct reftable_stack *stack = stack_for(refs, refname);
++ struct reftable_merged_table *mt = reftable_stack_merged_table(stack);
++ struct reftable_log_record log = { NULL };
++ int err = refs->err;
++
++ if (err < 0) {
++ goto done;
++ }
++ err = reftable_merged_table_seek_log(mt, &it, refname);
++ if (err) {
++ goto done;
++ }
++ err = reftable_iterator_next_log(&it, &log);
++ if (err) {
++ goto done;
++ }
++
++ if (strcmp(log.refname, refname)) {
++ err = 1;
++ }
++
++done:
++ reftable_iterator_destroy(&it);
++ reftable_log_record_clear(&log);
++ return !err;
+}
+
+static int git_reftable_create_reflog(struct ref_store *ref_store,
@@ refs/reftable-backend.c (new)
+ git_reftable_rename_ref,
+ git_reftable_copy_ref,
+
-+ git_reftable_write_pseudoref,
-+ reftable_delete_pseudoref,
-+
+ git_reftable_ref_iterator_begin,
+ git_reftable_read_raw_ref,
+
@@ repository.h: struct repository {
*/
## setup.c ##
-@@ setup.c: static int check_repo_format(const char *var, const char *value, void *vdata)
- if (!value)
- return config_error_nonbool(var);
- data->partial_clone = xstrdup(value);
-- } else if (!strcmp(ext, "worktreeconfig"))
-+ } else if (!strcmp(ext, "worktreeconfig")) {
- data->worktree_config = git_config_bool(var, value);
-- else
-+ } else if (!strcmp(ext, "refstorage")) {
-+ data->ref_storage = xstrdup(value);
-+ } else
- string_list_append(&data->unknown_extensions, ext);
+@@ setup.c: static enum extension_result handle_extension(const char *var,
+ {
+ if (!strcmp(ext, "noop-v1")) {
+ return EXTENSION_OK;
++ } else if (!strcmp(ext, "refstorage")) {
++ data->ref_storage = xstrdup(value);
++ return EXTENSION_OK;
}
+-
+ return EXTENSION_UNKNOWN;
+ }
@@ setup.c: void clear_repository_format(struct repository_format *format)
- string_list_clear(&format->unknown_extensions, 0);
+ string_list_clear(&format->v1_only_extensions, 0);
free(format->work_tree);
free(format->partial_clone);
+ free(format->ref_storage);
-: ---------- > 15: a6449d4346 Read FETCH_HEAD as loose ref
15: 04c86e7395 ! 16: f13e4798c4 Hookup unittests for the reftable library. @@ Makefile: t/helper/test-svn-fe$X: $(VCSSVN_LIB)
$(QUIET_LINK)$(CC) $(ALL_CFLAGS) -o $@ $(ALL_LDFLAGS) $(filter %.o,$^) $(filter %.a,$^) $(LIBS)
check-sha1:: t/helper/test-tool$X
+@@ Makefile: cocciclean:
+ clean: profile-clean coverage-clean cocciclean
+ $(RM) *.res
+ $(RM) $(OBJECTS)
+- $(RM) $(LIB_FILE) $(XDIFF_LIB) $(VCSSVN_LIB) $(REFTABLE_LIB)
++ $(RM) $(LIB_FILE) $(XDIFF_LIB) $(VCSSVN_LIB) $(REFTABLE_LIB) $(REFTABLE_TEST_LIB)
+ $(RM) $(ALL_PROGRAMS) $(SCRIPT_LIB) $(BUILT_INS) git$X
+ $(RM) $(TEST_PROGRAMS)
+ $(RM) $(FUZZ_PROGRAMS)
## t/helper/test-reftable.c (new) ##
@@
16: c751265705 ! 17: 679dc37871 Add GIT_DEBUG_REFS debugging mechanism
@@ builtin/worktree.c: static int add_worktree(const char *path, const char *refnam
strbuf_reset(&sb);
- if (get_main_ref_store(the_repository)->be == &refs_be_reftable) {
+
-+ /* XXX: check GIT_TEST_REFTABLE because GIT_DEBUG_REFS obscures the
-+ * instance type. */
-+ if (get_main_ref_store(the_repository)->be == &refs_be_reftable ||
-+ getenv("GIT_TEST_REFTABLE") != NULL) {
++ if (!strcmp(ref_store_backend_name(get_main_ref_store(the_repository)),
++ "reftable")) {
/* XXX this is cut & paste from reftable_init_db. */
strbuf_addf(&sb, "%s/HEAD", sb_repo.buf);
write_file(sb.buf, "%s", "ref: refs/heads/.invalid\n");
## refs.c ##
+@@ refs.c: int ref_storage_backend_exists(const char *name)
+ return find_ref_storage_backend(name) != NULL;
+ }
+
++const char *ref_store_backend_name(struct ref_store *refs)
++{
++ return refs->be->name;
++}
++
+ /*
+ * How to handle various characters in refnames:
+ * 0: An acceptable character for refs
@@ refs.c: struct ref_store *get_main_ref_store(struct repository *r)
- r->ref_storage_format :
- default_ref_storage(),
+ r->ref_storage_format :
+ default_ref_storage(),
REF_STORE_ALL_CAPS);
+ if (getenv("GIT_DEBUG_REFS")) {
+ r->refs_private = debug_wrap(r->gitdir, r->refs_private);
@@ refs.c: struct ref_store *get_main_ref_store(struct repository *r)
}
+ ## refs.h ##
+@@ refs.h: int reflog_expire(const char *refname, const struct object_id *oid,
+ int ref_storage_backend_exists(const char *name);
+
+ struct ref_store *get_main_ref_store(struct repository *r);
++const char *ref_store_backend_name(struct ref_store *refs);
+
+ /**
+ * Submodules
+
## refs/debug.c (new) ##
@@
+
@@ refs/debug.c (new)
+struct ref_store *debug_wrap(const char *gitdir, struct ref_store *store)
+{
+ struct debug_ref_store *res = malloc(sizeof(struct debug_ref_store));
++ struct ref_storage_be *be_copy = malloc(sizeof(*be_copy));
++ *be_copy = refs_be_debug;
++ be_copy->name = ref_store_backend_name(store);
+ fprintf(stderr, "ref_store for %s\n", gitdir);
+ res->refs = store;
-+ base_ref_store_init((struct ref_store *)res, &refs_be_debug);
++ base_ref_store_init((struct ref_store *)res, be_copy);
+ return (struct ref_store *)res;
+}
+
@@ refs/debug.c (new)
+ struct debug_ref_store *drefs = (struct debug_ref_store *)ref_store;
+ int res =
+ drefs->refs->be->delete_refs(drefs->refs, msg, refnames, flags);
++ int i = 0;
++ fprintf(stderr, "delete_refs {\n");
++ for (i = 0; i < refnames->nr; i++)
++ fprintf(stderr, "%s\n", refnames->items[i].string);
++ fprintf(stderr, "}: %d\n", res);
+ return res;
+}
+
@@ refs/debug.c (new)
+ return res;
+}
+
-+static int debug_write_pseudoref(struct ref_store *ref_store,
-+ const char *pseudoref,
-+ const struct object_id *oid,
-+ const struct object_id *old_oid,
-+ struct strbuf *err)
-+{
-+ struct debug_ref_store *drefs = (struct debug_ref_store *)ref_store;
-+ int res = drefs->refs->be->write_pseudoref(drefs->refs, pseudoref, oid,
-+ old_oid, err);
-+ char o[100] = "null";
-+ char n[100] = "null";
-+ if (oid)
-+ oid_to_hex_r(o, oid);
-+ if (old_oid)
-+ oid_to_hex_r(n, old_oid);
-+ fprintf(stderr, "write_pseudoref: %s, %s => %s, err %s: %d\n",
-+ pseudoref, o, n, err->buf, res);
-+ return res;
-+}
-+
-+static int debug_delete_pseudoref(struct ref_store *ref_store,
-+ const char *pseudoref,
-+ const struct object_id *old_oid)
-+{
-+ struct debug_ref_store *drefs = (struct debug_ref_store *)ref_store;
-+ int res = drefs->refs->be->delete_pseudoref(drefs->refs, pseudoref,
-+ old_oid);
-+ char hex[100] = "null";
-+ if (old_oid)
-+ oid_to_hex_r(hex, old_oid);
-+ fprintf(stderr, "delete_pseudoref: %s (%s): %d\n", pseudoref, hex, res);
-+ return res;
-+}
-+
+struct debug_ref_iterator {
+ struct ref_iterator base;
+ struct ref_iterator *iter;
@@ refs/debug.c (new)
+ debug_rename_ref,
+ debug_copy_ref,
+
-+ debug_write_pseudoref,
-+ debug_delete_pseudoref,
-+
+ debug_ref_iterator_begin,
+ debug_read_raw_ref,
+
@@ refs/debug.c (new)
+};
## refs/refs-internal.h ##
-@@ refs/refs-internal.h: struct ref_store {
+@@ refs/refs-internal.h: int parse_loose_ref_contents(const char *buf, struct object_id *oid,
void base_ref_store_init(struct ref_store *refs,
const struct ref_storage_be *be);17: ef0dd45f07 = 18: 9e6cdbe204 vcxproj: adjust for the reftable changes 18: d4dc1deae5 = 19: 9cd73da381 git-prompt: prepare for reftable refs backend 19: 5a85abf9c4 = 20: a2e5b3082e Add reftable testing infrastructure 20: 0ebf7beb95 = 21: 539fa0935f Add "test-tool dump-reftable" command.
Signature · 1 line
gitgitgadget
PATCH v20 3/21 t1400: use git rev-parse for testing PSEUDOREF existence
From: Han-Wen Nienhuys <[email protected]>
This will allow these tests to run with alternative ref backends
--- t/t1400-update-ref.sh | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-)
t/t1400-update-ref.sh +10 -10
@@ -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_must_fail git rev-parse PSEUDOREF && test_i18ngrep "could not read ref" 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 $C = $(git rev-parse PSEUDOREF) && test_i18ngrep "unexpected object ID" 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 $A = $(git rev-parse PSEUDOREF) && test_i18ngrep "unexpected object ID" 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 '
Signature · 1 line
gitgitgadget
PATCH v20 4/21 Modify pseudo refs through ref backend storage
In reply to Han-Wen Nienhuys via GitGitGadgetFrom: Han-Wen Nienhuys <[email protected]>
The previous behavior was introduced in commit 74ec19d4be ("pseudorefs: create and use pseudoref update and delete functions", Jul 31, 2015), with the justification "alternate ref backends still need to store pseudorefs in GIT_DIR".
Refs such as REBASE_HEAD are read through the ref backend. This can only work consistently if they are written through the ref backend as well. Tooling that works directly on files under .git should be updated to use git commands to read refs instead.
The following behaviors change:
* Updates to pseudorefs (eg. ORIG_HEAD) with core.logAllRefUpdates=always will create reflogs for the pseudoref.
* non-HEAD pseudoref symrefs are also dereferenced on deletion. Update t1405 accordingly.
--- Documentation/git-update-ref.txt | 13 ++-- refs.c | 120 ++----------------------------- t/t1400-update-ref.sh | 10 +-- t/t1405-main-ref-store.sh | 5 +- 4 files changed, 23 insertions(+), 125 deletions(-)
Documentation/git-update-ref.txt +7 -6
@@ -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
refs.c +7 -113
138 lines not on this page · raw message
t/t1400-update-ref.sh +5 -5
@@ -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' '
@@ -476,7 +476,7 @@ 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_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' '
@@ -497,7 +497,7 @@ test_expect_success 'overwrite pseudoref with correct 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 $C = $(git rev-parse PSEUDOREF) && - test_i18ngrep "unexpected object ID" err + test_i18ngrep "cannot lock ref.*expected" err ' test_expect_success 'delete pseudoref' '
@@ -509,7 +509,7 @@ 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 = $(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' '
t/t1405-main-ref-store.sh +4 -1
@@ -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 -- '
Signature · 1 line
gitgitgadget
PATCH v20 5/21 Make HEAD a PSEUDOREF rather than PER_WORKTREE.
In reply to Han-Wen Nienhuys via GitGitGadgetFrom: Han-Wen Nienhuys <[email protected]>
This is consistent with the definition of REF_TYPE_PSEUDOREF (uppercase in the root ref namespace).
--- refs.c | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-)
refs.c +3 -4
@@ -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)
Signature · 1 line
gitgitgadget
PATCH v20 6/21 Make refs_ref_exists public
In reply to Han-Wen Nienhuys via GitGitGadgetFrom: Han-Wen Nienhuys <[email protected]>
--- refs.c | 2 +- refs.h | 2 ++ 2 files changed, 3 insertions(+), 1 deletion(-)
refs.c +1 -1
@@ -313,7 +313,7 @@ int read_ref(const char *refname, struct object_id *oid)return read_ref_full (refname,RESOLVE_REF_READING , oid,NULL ); } -static int refs_ref_exists (struct ref_store *refs,const char *refname) +int refs_ref_exists (struct ref_store *refs,const char *refname) {return !!refs_resolve_ref_unsafe (refs, refname,RESOLVE_REF_READING ,NULL ,NULL ); }
refs.h +2 -0
@@ -105,6 +105,8 @@ int refs_verify_refname_available(struct ref_store *refs,const struct string_list *skip, struct strbuf *err); +int refs_ref_exists (struct ref_store *refs,const char *refname); +int ref_exists (const char *refname);int should_autocreate_reflog (const char *refname);
Signature · 1 line
gitgitgadget
PATCH v20 7/21 Treat CHERRY_PICK_HEAD as a pseudo ref
In reply to Han-Wen Nienhuys via GitGitGadgetFrom: Han-Wen Nienhuys <[email protected]>
Check for existence and delete CHERRY_PICK_HEAD through ref functions. This will help cherry-pick work with alternate ref storage backends.
--- builtin/commit.c | 34 +++++++++++++++++++--------------- builtin/merge.c | 2 +- path.c | 1 - path.h | 7 ++++--- sequencer.c | 42 ++++++++++++++++++++++++++---------------- wt-status.c | 4 ++-- 6 files changed, 52 insertions(+), 38 deletions(-)
builtin/commit.c +19 -15
@@ -847,21 +847,25 @@ static int prepare_to_commit(const char *index_file, const char *prefix,if (cleanup_mode ==COMMIT_MSG_CLEANUP_SCISSORS && !merge_contains_scissors)wt_status_add_cut_line (s->fp); -status_printf_ln (s,GIT_COLOR_NORMAL , - whence ==FROM_MERGE - ?_ ("\n" -"It looks like you may be committing a merge.\n" -"If this is not correct, please remove the file\n" -" %s\n" -"and try again.\n" ) - :_ ("\n" -"It looks like you may be committing a cherry-pick.\n" -"If this is not correct, please remove the file\n" -" %s\n" -"and try again.\n" ), - whence ==FROM_MERGE ? -git_path_merge_head (the_repository) : -git_path_cherry_pick_head (the_repository)); +if (whence ==FROM_MERGE ) +status_printf_ln ( + s,GIT_COLOR_NORMAL , + +_ ("\n" +"It looks like you may be committing a merge.\n" +"If this is not correct, please remove the file\n" +" %s\n" +"and try again.\n" ), +git_path_merge_head (the_repository)); +else +status_printf_ln ( + s,GIT_COLOR_NORMAL , + +_ ("\n" +"It looks like you may be committing a cherry-pick.\n" +"If this is not correct, please run\n" +" git cherry-pick --abort\n" +"and try again.\n" )); }fprintf (s->fp,"\n" );
builtin/merge.c +1 -1
@@ -1352,7 +1352,7 @@ int cmd_merge(int argc, const char **argv, const char *prefix)else die (_ ("You have not concluded your merge (MERGE_HEAD exists)." )); } -if (file_exists (git_path_cherry_pick_head (the_repository))) { +if (ref_exists ("CHERRY_PICK_HEAD" )) {if (advice_resolve_conflict)die (_ ("You have not concluded your cherry-pick (CHERRY_PICK_HEAD exists).\n" "Please, commit your changes before you merge." ));
path.c +0 -1
@@ -1528,7 +1528,6 @@ char *xdg_cache_home(const char *filename)return NULL ; } -REPO_GIT_PATH_FUNC(cherry_pick_head, "CHERRY_PICK_HEAD") REPO_GIT_PATH_FUNC(revert_head, "REVERT_HEAD") REPO_GIT_PATH_FUNC(squash_msg, "SQUASH_MSG")REPO_GIT_PATH_FUNC (merge_msg,"MERGE_MSG" )
path.h +4 -3
@@ -170,7 +170,6 @@ void report_linked_checkout_garbage(void); }struct path_cache { -const char *cherry_pick_head;const char *revert_head;const char *squash_msg;const char *merge_msg;
@@ -182,9 +181,11 @@ struct path_cache {const char *shallow; }; -#define PATH_CACHE_INIT { NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL } +#define PATH_CACHE_INIT \ + { \ + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL \ + } -const char *git_path_cherry_pick_head (struct repository *r);const char *git_path_revert_head (struct repository *r);const char *git_path_squash_msg (struct repository *r);const char *git_path_merge_msg (struct repository *r);
sequencer.c +26 -16
114 lines not on this page · raw message
wt-status.c +2 -2
@@ -1673,8 +1673,8 @@ void wt_status_get_state(struct repository *r, state->merge_in_progress =1 ; }else if (wt_status_check_rebase (NULL , state)) { ;/* all set */ - }else if (!stat (git_path_cherry_pick_head (r), &st) && - !get_oid ("CHERRY_PICK_HEAD" , &oid)) { + }else if (refs_ref_exists (get_main_ref_store (r),"CHERRY_PICK_HEAD" ) && + !get_oid ("CHERRY_PICK_HEAD" , &oid)) { state->cherry_pick_in_progress =1 ;oidcpy (&state->cherry_pick_head_oid, &oid); }
Signature · 1 line
gitgitgadget
PATCH v20 8/21 Treat REVERT_HEAD as a pseudo ref
In reply to Han-Wen Nienhuys via GitGitGadgetFrom: Han-Wen Nienhuys <[email protected]>
--- path.c | 1 - path.h | 8 +++----- sequencer.c | 16 +++++++++------- wt-status.c | 2 +- 4 files changed, 13 insertions(+), 14 deletions(-)
path.c +0 -1
@@ -1528,7 +1528,6 @@ char *xdg_cache_home(const char *filename)return NULL ; } -REPO_GIT_PATH_FUNC(revert_head, "REVERT_HEAD") REPO_GIT_PATH_FUNC(squash_msg, "SQUASH_MSG") REPO_GIT_PATH_FUNC(merge_msg, "MERGE_MSG")REPO_GIT_PATH_FUNC (merge_rr,"MERGE_RR" )
path.h +3 -5
@@ -170,7 +170,6 @@ void report_linked_checkout_garbage(void); }struct path_cache { -const char *revert_head;const char *squash_msg;const char *merge_msg;const char *merge_rr;
@@ -181,12 +180,11 @@ struct path_cache {const char *shallow; }; -#define PATH_CACHE_INIT \ - { \ - NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL \ +#define PATH_CACHE_INIT \ + { \ + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL \ } -const char *git_path_revert_head (struct repository *r);const char *git_path_squash_msg (struct repository *r);const char *git_path_merge_msg (struct repository *r);const char *git_path_merge_rr (struct repository *r);
sequencer.c +9 -7
@@ -2317,8 +2317,10 @@ void sequencer_post_commit_cleanup(struct repository *r, int verbose) need_cleanup =1 ; } -if (file_exists (git_path_revert_head (r))) { -if (!unlink (git_path_revert_head (r)) && verbose) +if (refs_ref_exists (get_main_ref_store (r),"REVERT_HEAD" )) { +if (!refs_delete_ref (get_main_ref_store (r),"" ,"REVERT_HEAD" , +NULL ,0 ) && + verbose)warning (_ ("cancelling a revert in progress" )); opts.action =REPLAY_REVERT ; need_cleanup =1 ;
@@ -2677,7 +2679,7 @@ static int create_seq_dir(struct repository *r)const char *in_progress_error =NULL ;const char *in_progress_advice =NULL ;unsigned int advise_skip = -file_exists (git_path_revert_head (r)) || +refs_ref_exists (get_main_ref_store (r),"REVERT_HEAD" ) ||refs_ref_exists (get_main_ref_store (r),"CHERRY_PICK_HEAD" );if (!sequencer_get_last_command (r, &action)) {
@@ -2778,7 +2780,7 @@ static int rollback_single_pick(struct repository *r)struct object_id head_oid;if (!refs_ref_exists (get_main_ref_store (r),"CHERRY_PICK_HEAD" ) && - !file_exists (git_path_revert_head (r))) + !refs_ref_exists (get_main_ref_store (r),"REVERT_HEAD" ))return error (_ ("no cherry-pick or revert in progress" ));if (read_ref_full ("HEAD" ,0 , &head_oid,NULL ))return error (_ ("cannot resolve HEAD" ));
@@ -2872,7 +2874,7 @@ int sequencer_skip(struct repository *r, struct replay_opts *opts)*/ switch (opts->action) {case REPLAY_REVERT : -if (!file_exists (git_path_revert_head (r))) { +if (!refs_ref_exists (get_main_ref_store (r),"REVERT_HEAD" )) {if (action !=REPLAY_REVERT )return error (_ ("no revert in progress" ));if (!rollback_is_safe ())
@@ -4210,7 +4212,7 @@ static int continue_single_pick(struct repository *r)const char *argv[] = {"commit" ,NULL };if (!refs_ref_exists (get_main_ref_store (r),"CHERRY_PICK_HEAD" ) && - !file_exists (git_path_revert_head (r))) + !refs_ref_exists (get_main_ref_store (r),"REVERT_HEAD" ))return error (_ ("no cherry-pick or revert in progress" ));return run_command_v_opt (argv,RUN_GIT_CMD ); }
@@ -4390,7 +4392,7 @@ int sequencer_continue(struct repository *r, struct replay_opts *opts)/* Verify that the conflict has been resolved */ if (refs_ref_exists (get_main_ref_store (r),"CHERRY_PICK_HEAD" ) || -file_exists (git_path_revert_head (r))) { +refs_ref_exists (get_main_ref_store (r),"REVERT_HEAD" )) { res =continue_single_pick (r);if (res) goto release_todo_list;
wt-status.c +1 -1
@@ -1679,7 +1679,7 @@ void wt_status_get_state(struct repository *r,oidcpy (&state->cherry_pick_head_oid, &oid); }wt_status_check_bisect (NULL , state); -if (!stat (git_path_revert_head (r), &st) && +if (refs_ref_exists (get_main_ref_store (r),"REVERT_HEAD" ) && !get_oid ("REVERT_HEAD" , &oid)) { state->revert_in_progress =1 ;oidcpy (&state->revert_head_oid, &oid);
Signature · 1 line
gitgitgadget
PATCH v20 10/21 Iteration over entire ref namespace is iterating over "refs/"
In reply to Han-Wen Nienhuys via GitGitGadgetFrom: Han-Wen Nienhuys <[email protected]>
This changes behavior for in for_each_[raw]ref and for_each_fullref_in_pattern.
This happens implicitly in the files/packed ref backend; making it explicit simplifies adding alternate ref storage backends, such as reftable.
--- ref-filter.c | 7 ++++--- refs.c | 6 +++--- 2 files changed, 7 insertions(+), 6 deletions(-)
ref-filter.c +4 -3
@@ -1943,6 +1943,7 @@ static int for_each_fullref_in_pattern(struct ref_filter *filter, {struct string_list prefixes =STRING_LIST_INIT_DUP ;struct string_list_item *prefix; +const char *all ="refs/" ;int ret;if (!filter->match_as_path) {
@@ -1951,7 +1952,7 @@ static int for_each_fullref_in_pattern(struct ref_filter *filter,* prefixes like "refs/heads/" etc. are stripped off, * so we have to look at everything: */ -return for_each_fullref_in ("" , cb, cb_data, broken); +return for_each_fullref_in (all, cb, cb_data, broken); }if (filter->ignore_case) {
@@ -1960,12 +1961,12 @@ static int for_each_fullref_in_pattern(struct ref_filter *filter,* so just return everything and let the caller * sort it out. */ -return for_each_fullref_in ("" , cb, cb_data, broken); +return for_each_fullref_in (all, cb, cb_data, broken); }if (!filter->name_patterns[0 ]) {/* no patterns; we have to look at everything */ -return for_each_fullref_in ("" , cb, cb_data, broken); +return for_each_fullref_in (all, cb, cb_data, broken); }find_longest_prefixes (&prefixes, filter->name_patterns);
refs.c +3 -3
@@ -1458,7 +1458,7 @@ static int do_for_each_ref(struct ref_store *refs, const char *prefix,int refs_for_each_ref (struct ref_store *refs,each_ref_fn fn,void *cb_data) { -return do_for_each_ref (refs,"" , fn,0 ,0 , cb_data); +return do_for_each_ref (refs,"refs/" , fn,0 ,0 , cb_data); }int for_each_ref (each_ref_fn fn,void *cb_data)
@@ -1518,8 +1518,8 @@ int for_each_namespaced_ref(each_ref_fn fn, void *cb_data)int refs_for_each_rawref (struct ref_store *refs,each_ref_fn fn,void *cb_data) { -return do_for_each_ref (refs,"" , fn,0 , -DO_FOR_EACH_INCLUDE_BROKEN , cb_data); +return do_for_each_ref (refs,"refs/" , fn,0 ,DO_FOR_EACH_INCLUDE_BROKEN , + cb_data); }int for_each_rawref (each_ref_fn fn,void *cb_data)
Signature · 1 line
gitgitgadget
PATCH v20 2/21 Split off reading loose ref data in separate function
In reply to Han-Wen Nienhuys via GitGitGadgetFrom: Han-Wen Nienhuys <[email protected]>
This prepares for handling FETCH_HEAD (which is not a regular ref) separately in the reftable backend.
--- refs/files-backend.c | 34 +++++++++++++++++++--------------- refs/refs-internal.h | 6 ++++++ 2 files changed, 25 insertions(+), 15 deletions(-)
refs/files-backend.c +19 -15
@@ -360,7 +360,6 @@ static int files_read_raw_ref(struct ref_store *ref_store,struct strbuf sb_path =STRBUF_INIT ;const char *path;const char *buf; -const char *p;struct stat st;int fd;int ret =-1 ;
@@ -465,6 +464,21 @@ static int files_read_raw_ref(struct ref_store *ref_store,close (fd);strbuf_rtrim (&sb_contents); buf = sb_contents.buf; + + ret =parse_loose_ref_contents (buf, oid, referent, type); + +out: + save_errno = errno; +strbuf_release (&sb_path); +strbuf_release (&sb_contents); + errno = save_errno; +return ret; +} + +int parse_loose_ref_contents (const char *buf,struct object_id *oid, +struct strbuf *referent,unsigned int *type) +{ +const char *p;if (skip_prefix (buf,"ref:" , &buf)) {while (isspace (*buf)) buf++;
@@ -472,29 +486,19 @@ static int files_read_raw_ref(struct ref_store *ref_store,strbuf_reset (referent);strbuf_addstr (referent, buf); *type |=REF_ISSYMREF ; - ret =0 ; - goto out; +return 0 ; }/* -* Please note that FETCH_HEAD has additional -* data after the sha. +* FETCH_HEAD has additional data after the sha. */ if (parse_oid_hex (buf, oid, &p) || (*p !='\0' && !isspace (*p))) { *type |=REF_ISBROKEN ; errno =EINVAL ; - goto out; +return -1 ; } - - ret =0 ; - -out: - save_errno = errno; -strbuf_release (&sb_path); -strbuf_release (&sb_contents); - errno = save_errno; -return ret; +return 0 ; }static void unlock_ref (struct ref_lock *lock)
refs/refs-internal.h +6 -0
@@ -674,6 +674,12 @@ struct ref_store {const struct ref_storage_be *be; }; +/* +* Parse contents of a loose ref file. +*/ +int parse_loose_ref_contents (const char *buf,struct object_id *oid, +struct strbuf *referent,unsigned int *type); +/* * Fill in the generic part of refs and add it to our collection of * reference stores.
Signature · 1 line
gitgitgadget
PATCH v20 9/21 Move REF_LOG_ONLY to refs-internal.h
In reply to Han-Wen Nienhuys via GitGitGadgetFrom: Han-Wen Nienhuys <[email protected]>
REF_LOG_ONLY is used in the transaction preparation: if a symref is involved in a transaction, the referent of the symref should be updated, and the symref itself should only be updated in the reflog. Other ref backends will need to duplicate this logic.
--- refs/files-backend.c | 7 ------- refs/refs-internal.h | 7 +++++++ 2 files changed, 7 insertions(+), 7 deletions(-)
refs/files-backend.c +0 -7
@@ -38,13 +38,6 @@*/ #define REF_NEEDS_COMMIT (1 << 6) -/* -* Used as a flag in ref_update::flags when we want to log a ref -* update but not actually perform it. This is used when a symbolic -* ref update is split up. -*/ -#define REF_LOG_ONLY (1 << 7) -/* * Used as a flag in ref_update::flags when the ref_update was via an * update to HEAD.
refs/refs-internal.h +7 -0
@@ -31,6 +31,13 @@ struct ref_transaction;*/ #define REF_HAVE_OLD (1 << 3) +/* +* Used as a flag in ref_update::flags when we want to log a ref +* update but not actually perform it. This is used when a symbolic +* ref update is split up. +*/ +#define REF_LOG_ONLY (1 << 7) +/* * Return the length of time to retry acquiring a loose reference lock * before giving up, in milliseconds:
Signature · 1 line
gitgitgadget
PATCH v20 13/21 Add standalone build infrastructure for reftable
In reply to Han-Wen Nienhuys via GitGitGadgetFrom: Han-Wen Nienhuys <[email protected]>
The reftable library is integrates with Git, so it become a first class supported storage mechanism, but is sufficiently complex that other projects (e.g. libgit2) may want to consume the same source code.
To make this possible, the library also compiles completely standalone, which is demonstrated with the Bazel BUILD/WORKSPACE files that this commit adds.
--- reftable/BUILD | 203 ++++++++++++++++++++++++++++++++++++++++++++ reftable/README.md | 33 +++++++ reftable/WORKSPACE | 14 +++ reftable/zlib.BUILD | 36 ++++++++ 4 files changed, 286 insertions(+) create mode 100644 reftable/BUILD create mode 100644 reftable/README.md create mode 100644 reftable/WORKSPACE create mode 100644 reftable/zlib.BUILD
reftable/BUILD new file +203 -0
@@ -0,0 +1,203 @@ +# Mirror core-git COPTS so reftable compiles without warning in CGit. +GIT_COPTS = [ + "-DREFTABLE_STANDALONE", + "-Wall", + "-Werror", + "-Wdeclaration-after-statement", + "-Wstrict-prototypes", + "-Wformat-security", + "-Wno-format-zero-length", + "-Wold-style-definition", + "-Woverflow", + "-Wpointer-arith", + "-Wstrict-prototypes", + "-Wunused", + "-Wvla", + "-Wextra", + "-Wmissing-prototypes", + "-Wno-empty-body", + "-Wno-missing-field-initializers", + "-Wno-sign-compare", + "-Werror=strict-aliasing", + "-Wno-unused-parameter", +] + +cc_library( + name = "reftable", + srcs = [ + "basics.c", + "block.c", + "compat.c", + "file.c", + "iter.c", + "merged.c", + "pq.c", + "reader.c", + "record.c", + "refname.c", + "reftable.c", + "strbuf.c", + "stack.c", + "tree.c", + "writer.c", + "zlib-compat.c", + "basics.h", + "block.h", + "compat.h", + "constants.h", + "iter.h", + "merged.h", + "pq.h", + "reader.h", + "refname.h", + "record.h", + "strbuf.h", + "stack.h", + "system.h", + "tree.h", + "writer.h", + ], + hdrs = [ + "reftable.h", + ], + includes = [ + "include", + ], + copts = [ + "-fvisibility=protected", + ] + GIT_COPTS, + deps = ["@zlib"], + visibility = ["//visibility:public"] +) + +cc_library( + name = "testlib", + srcs = [ + "test_framework.c", + "dump.c", + "test_framework.h", + ], + hdrs = [ + "reftable-tests.h", + ], + copts = GIT_COPTS, + deps = [":reftable"], + visibility = ["//visibility:public"] +) + +cc_test( + name = "record_test", + srcs = ["record_test.c"], + deps = [ + ":reftable", + ":testlib", + ], + copts = [ + "-Drecord_test_main=main", + "-fvisibility=protected", + ] + GIT_COPTS, +) + +cc_test( + name = "reftable_test", + srcs = ["reftable_test.c"], + deps = [ + ":reftable", + ":testlib", + ], + copts = [ + "-Dreftable_test_main=main", + "-fvisibility=protected", + ] + GIT_COPTS, +) + +cc_test( + name = "strbuf_test", + srcs = ["strbuf_test.c"], + deps = [ + ":reftable", + ":testlib", + ] , + copts = [ + "-Dstrbuf_test_main=main", + "-fvisibility=protected", + ] + GIT_COPTS, +) + +cc_test( + name = "stack_test", + srcs = ["stack_test.c"], + deps = [ + ":reftable", + ":testlib", + ], + copts = [ + "-Dstack_test_main=main", + "-fvisibility=protected", + ] + GIT_COPTS, +) + +cc_test( + name = "tree_test", + srcs = ["tree_test.c"], + deps = [ + ":reftable", + ":testlib", + ], + copts = [ + "-Dtree_test_main=main", + "-fvisibility=protected", + ] + GIT_COPTS, +) + +cc_test( + name = "block_test", + srcs = ["block_test.c"], + deps = [ + ":reftable", + ":testlib", + ], + copts = [ + "-Dblock_test_main=main", + "-fvisibility=protected", + ] + GIT_COPTS, +) + +cc_test( + name = "refname_test", + srcs = ["refname_test.c"], + deps = [ + ":reftable", + ":testlib", + ], + copts = [ + "-Drefname_test_main=main", + "-fvisibility=protected", + ] + GIT_COPTS, +) + +cc_test( + name = "merged_test", + srcs = ["merged_test.c"], + deps = [ + ":reftable", + ":testlib", + ], + copts = [ + "-Dmerged_test_main=main", + "-fvisibility=protected", + ] + GIT_COPTS, +) + +[sh_test( + name = "%s_valgrind_test" % t, + srcs = [ "valgrind_test.sh" ], + args = [ t ], + data = [ t ]) + for t in ["record_test", + "merged_test", + "refname_test", + "tree_test", + "block_test", + "strbuf_test", + "stack_test"]]
reftable/README.md new file +33 -0
@@ -0,0 +1,33 @@ +This directory contains an implementation of the reftable library. + +The library is integrated into the git-core project, but can also be built +standalone, by compiling with -DREFTABLE_STANDALONE. The standalone build is +exercised by the accompanying BUILD/WORKSPACE files, and can be run as + + bazel test :all + +It includes a fragment of the zlib library to provide uncompress2(), which is a +recent addition to the API. zlib is licensed as follows: + +``` + (C) 1995-2017 Jean-loup Gailly and Mark Adler + + This software is provided 'as-is', without any express or implied + warranty. In no event will the authors be held liable for any damages + arising from the use of this software. + + Permission is granted to anyone to use this software for any purpose, + including commercial applications, and to alter it and redistribute it + freely, subject to the following restrictions: + + 1. The origin of this software must not be misrepresented; you must not + claim that you wrote the original software. If you use this software + in a product, an acknowledgment in the product documentation would be + appreciated but is not required. + 2. Altered source versions must be plainly marked as such, and must not be + misrepresented as being the original software. + 3. This notice may not be removed or altered from any source distribution. + + Jean-loup Gailly Mark Adler + [email protected] [email protected] +```
reftable/WORKSPACE new file +14 -0
@@ -0,0 +1,14 @@ +workspace(name = "reftable") + +load("@bazel_tools//tools/build_defs/repo:http.bzl", "http_archive") + +http_archive( + name = "zlib", + build_file = "@//:zlib.BUILD", + sha256 = "c3e5e9fdd5004dcb542feda5ee4f0ff0744628baf8ed2dd5d66f8ca1197cb1a1", + strip_prefix = "zlib-1.2.11", + urls = [ + "https://mirror.bazel.build/zlib.net/zlib-1.2.11.tar.gz", + "https://zlib.net/zlib-1.2.11.tar.gz", + ], +)
reftable/zlib.BUILD new file +36 -0
@@ -0,0 +1,36 @@ +package(default_visibility = ["//visibility:public"]) + +licenses(["notice"]) # BSD/MIT-like license (for zlib) + +cc_library( + name = "zlib", + srcs = [ + "adler32.c", + "compress.c", + "crc32.c", + "crc32.h", + "deflate.c", + "deflate.h", + "gzclose.c", + "gzguts.h", + "gzlib.c", + "gzread.c", + "gzwrite.c", + "infback.c", + "inffast.c", + "inffast.h", + "inffixed.h", + "inflate.c", + "inflate.h", + "inftrees.c", + "inftrees.h", + "trees.c", + "trees.h", + "uncompr.c", + "zconf.h", + "zutil.c", + "zutil.h", + ], + hdrs = ["zlib.h"], + includes = ["."], +)
Signature · 1 line
gitgitgadget
PATCH v20 11/21 Add .gitattributes for the reftable/ directory
In reply to Han-Wen Nienhuys via GitGitGadgetFrom: Han-Wen Nienhuys <[email protected]>
--- reftable/.gitattributes | 1 + 1 file changed, 1 insertion(+) create mode 100644 reftable/.gitattributes
reftable/.gitattributes new file +1 -0
@@ -0,0 +1 @@ +/zlib-compat.c whitespace=-indent-with-non-tab,-trailing-space
Signature · 1 line
gitgitgadget
PATCH v20 15/21 Read FETCH_HEAD as loose ref
In reply to Han-Wen Nienhuys via GitGitGadgetFrom: Han-Wen Nienhuys <[email protected]>
FETCH_HEAD is a loose ref (either symref or OID), followed by further metadata. It can therefore not be read through a ref backend normally. Special case this in reftable-backend.c.
This functionality is shared between all backends, but the ref backend interface doesn't have a method to retrieve the repository directory, hence this functionality must be pushed down to the backend implementation.
--- refs/reftable-backend.c | 31 +++++++++++++++++++++++++++++++ t/t0031-reftable.sh | 9 ++++++++- 2 files changed, 39 insertions(+), 1 deletion(-)
refs/reftable-backend.c +31 -0
@@ -1304,6 +1304,33 @@ git_reftable_reflog_expire(struct ref_store *ref_store, const char *refname,return err; } +static int read_fetch_head (struct git_reftable_ref_store *refs, +const char *refname,struct object_id *oid, +struct strbuf *referent,unsigned int *type) +{ +struct strbuf sb =STRBUF_INIT ; +struct strbuf path_sb =STRBUF_INIT ; +int ret =-1 ; +int fd; +strbuf_addf (&path_sb,"%s/%s" , refs->repo_dir, refname); + fd =open (path_sb.buf,O_RDONLY ); +if (fd <0 ) { + goto out; + } +strbuf_reset (&sb); +if (strbuf_read (&sb, fd,256 ) <0 ) { + ret =-1 ; + } +strbuf_rtrim (&sb); + + ret =parse_loose_ref_contents (sb.buf, oid, referent, type); +out: +close (fd); +strbuf_release (&sb); +strbuf_release (&path_sb); +return ret; +} + static int git_reftable_read_raw_ref(struct ref_store *ref_store, const char *refname, struct object_id *oid, struct strbuf *referent,
@@ -1319,6 +1346,10 @@ static int git_reftable_read_raw_ref(struct ref_store *ref_store,return refs->err; } +if (!strcmp (refname,"FETCH_HEAD" )) { +return read_fetch_head (refs, refname, oid, referent, type); + } +/* This is usually not needed, but Git doesn't signal to ref backend if a subprocess updated the ref DB. So we always check. */
t/t0031-reftable.sh +8 -1
@@ -169,5 +169,12 @@ test_expect_success 'worktrees 2' ' git worktree add --detach existing_empty master ' -test_done +test_expect_success 'FETCH_HEAD' ' + initialize && + test_commit one && + (git init sub && cd sub && test_commit two) && + git fetch sub && + git checkout FETCH_HEAD +' +test_done
Signature · 1 line
gitgitgadget
PATCH v20 16/21 Hookup unittests for the reftable library.
In reply to Han-Wen Nienhuys via GitGitGadgetFrom: Han-Wen Nienhuys <[email protected]>
The unittests are under reftable/*_test.c, so all of the reftable code stays in one directory. They are called from t/helpers/test-reftable.c in t0031-reftable.sh
--- Makefile | 19 +++++++++++++++++-- t/helper/test-reftable.c | 15 +++++++++++++++ t/helper/test-tool.c | 1 + t/helper/test-tool.h | 1 + t/t0031-reftable.sh | 5 +++++ 5 files changed, 39 insertions(+), 2 deletions(-) create mode 100644 t/helper/test-reftable.c
Makefile +17 -2
@@ -725,6 +725,7 @@ TEST_BUILTINS_OBJS += test-read-cache.o TEST_BUILTINS_OBJS += test-read-graph.o TEST_BUILTINS_OBJS += test-read-midx.o TEST_BUILTINS_OBJS += test-ref-store.o +TEST_BUILTINS_OBJS += test-reftable.o TEST_BUILTINS_OBJS += test-regex.o TEST_BUILTINS_OBJS += test-repository.o TEST_BUILTINS_OBJS += test-revision-walking.o
@@ -808,6 +809,7 @@ LIB_FILE = libgit.a XDIFF_LIB = xdiff/lib.a VCSSVN_LIB = vcs-svn/lib.a REFTABLE_LIB = reftable/libreftable.a +REFTABLE_TEST_LIB = reftable/libreftable_test.a GENERATED_H += config-list.h GENERATED_H += command-list.h
@@ -2371,6 +2373,15 @@ REFTABLE_OBJS += reftable/tree.o REFTABLE_OBJS += reftable/writer.o REFTABLE_OBJS += reftable/zlib-compat.o +REFTABLE_TEST_OBJS += reftable/block_test.o +REFTABLE_TEST_OBJS += reftable/merged_test.o +REFTABLE_TEST_OBJS += reftable/record_test.o +REFTABLE_TEST_OBJS += reftable/refname_test.o +REFTABLE_TEST_OBJS += reftable/reftable_test.o +REFTABLE_TEST_OBJS += reftable/strbuf_test.o +REFTABLE_TEST_OBJS += reftable/stack_test.o +REFTABLE_TEST_OBJS += reftable/tree_test.o +REFTABLE_TEST_OBJS += reftable/test_framework.o TEST_OBJS := $(patsubst %$X,%.o,$(TEST_PROGRAMS)) $(patsubst %,t/helper/%,$(TEST_BUILTINS_OBJS)) OBJECTS := $(LIB_OBJS) $(BUILTIN_OBJS) $(PROGRAM_OBJS) $(TEST_OBJS) \
@@ -2378,6 +2389,7 @@ OBJECTS := $(LIB_OBJS) $(BUILTIN_OBJS) $(PROGRAM_OBJS) $(TEST_OBJS) \ $(VCSSVN_OBJS) \ $(FUZZ_OBJS) \ $(REFTABLE_OBJS) \ + $(REFTABLE_TEST_OBJS) \ common-main.o \ git.o ifndef NO_CURL
@@ -2521,6 +2533,9 @@ $(VCSSVN_LIB): $(VCSSVN_OBJS) $(REFTABLE_LIB): $(REFTABLE_OBJS) $(QUIET_AR)$(RM) $@ && $(AR) $(ARFLAGS) $@ $^ +$(REFTABLE_TEST_LIB): $(REFTABLE_TEST_OBJS) + $(QUIET_AR)$(RM) $@ && $(AR) $(ARFLAGS) $@ $^ + export DEFAULT_EDITOR DEFAULT_PAGER Documentation/GIT-EXCLUDED-PROGRAMS: FORCE
@@ -2803,7 +2818,7 @@ t/helper/test-svn-fe$X: $(VCSSVN_LIB) t/helper/test-tool$X: $(patsubst %,t/helper/%,$(TEST_BUILTINS_OBJS)) -t/helper/test-%$X: t/helper/test-%.o GIT-LDFLAGS $(GITLIBS) +t/helper/test-%$X: t/helper/test-%.o GIT-LDFLAGS $(GITLIBS) $(REFTABLE_TEST_LIB) $(QUIET_LINK)$(CC) $(ALL_CFLAGS) -o $@ $(ALL_LDFLAGS) $(filter %.o,$^) $(filter %.a,$^) $(LIBS) check-sha1:: t/helper/test-tool$X
@@ -3136,7 +3151,7 @@ cocciclean: clean: profile-clean coverage-clean cocciclean $(RM) *.res $(RM) $(OBJECTS) - $(RM) $(LIB_FILE) $(XDIFF_LIB) $(VCSSVN_LIB) $(REFTABLE_LIB) + $(RM) $(LIB_FILE) $(XDIFF_LIB) $(VCSSVN_LIB) $(REFTABLE_LIB) $(REFTABLE_TEST_LIB) $(RM) $(ALL_PROGRAMS) $(SCRIPT_LIB) $(BUILT_INS) git$X $(RM) $(TEST_PROGRAMS) $(RM) $(FUZZ_PROGRAMS)
t/helper/test-reftable.c new file +15 -0
@@ -0,0 +1,15 @@ +#include "reftable/reftable-tests.h" +#include "test-tool.h" + +int cmd__reftable (int argc,const char **argv) +{ +block_test_main (argc, argv); +merged_test_main (argc, argv); +record_test_main (argc, argv); +refname_test_main (argc, argv); +reftable_test_main (argc, argv); +strbuf_test_main (argc, argv); +stack_test_main (argc, argv); +tree_test_main (argc, argv); +return 0 ; +}
t/helper/test-tool.c +1 -0
@@ -52,6 +52,7 @@ static struct test_cmd cmds[] = { { "read-graph", cmd__read_graph }, { "read-midx", cmd__read_midx }, { "ref-store", cmd__ref_store }, + { "reftable", cmd__reftable }, { "regex", cmd__regex }, { "repository", cmd__repository }, { "revision-walking", cmd__revision_walking },
t/helper/test-tool.h +1 -0
@@ -41,6 +41,7 @@ int cmd__read_cache(int argc, const char **argv);int cmd__read_graph (int argc,const char **argv);int cmd__read_midx (int argc,const char **argv);int cmd__ref_store (int argc,const char **argv); +int cmd__reftable (int argc,const char **argv);int cmd__regex (int argc,const char **argv);int cmd__repository (int argc,const char **argv);int cmd__revision_walking (int argc,const char **argv);
t/t0031-reftable.sh +5 -0
@@ -15,6 +15,11 @@ initialize () { mv .git/hooks .git/hooks-disabled } +test_expect_success 'unittests' ' + test-tool reftable +' + + test_expect_success 'delete ref' ' initialize && test_commit file &&
Signature · 1 line
gitgitgadget
PATCH v20 14/21 Reftable support for git-core
In reply to Han-Wen Nienhuys via GitGitGadgetFrom: Han-Wen Nienhuys <[email protected]>
For background, see the previous commit introducing the library.
This introduces the file refs/reftable-backend.c containing a reftable-powered ref storage backend.
It can be activated by passing --ref-storage=reftable to "git init", or setting GIT_TEST_REFTABLE in the environment.
Example use: see t/t0031-reftable.sh
--- .../technical/repository-version.txt | 7 + Makefile | 28 +- builtin/clone.c | 4 +- builtin/init-db.c | 55 +- builtin/worktree.c | 27 +- cache.h | 8 +- refs.c | 27 +- refs.h | 3 + refs/refs-internal.h | 1 + refs/reftable-backend.c | 1384 +++++++++++++++++ reftable/update.sh | 3 - repository.c | 2 + repository.h | 3 + setup.c | 10 +- t/t0031-reftable.sh | 173 +++ 15 files changed, 1698 insertions(+), 37 deletions(-) create mode 100644 refs/reftable-backend.c create mode 100755 t/t0031-reftable.sh
Documentation/technical/repository-version.txt +7 -0
@@ -100,3 +100,10 @@ If set, by default "git config" reads from both "config" and multiple working directory mode, "config" file is shared while "config.worktree" is per-working directory (i.e., it's in GIT_COMMON_DIR/worktrees/<id>/config.worktree) + +==== `refStorage` + +Specifies the file format for the ref database. Values are `files` +(for the traditional packed + loose ref format) and `reftable` for the +binary reftable format. See https://github.com/google/reftable for +more information.
Makefile +26 -2
@@ -807,6 +807,7 @@ TEST_SHELL_PATH = $(SHELL_PATH) LIB_FILE = libgit.a XDIFF_LIB = xdiff/lib.a VCSSVN_LIB = vcs-svn/lib.a +REFTABLE_LIB = reftable/libreftable.a GENERATED_H += config-list.h GENERATED_H += command-list.h
@@ -959,6 +960,7 @@ LIB_OBJS += ref-filter.o LIB_OBJS += reflog-walk.o LIB_OBJS += refs.o LIB_OBJS += refs/files-backend.o +LIB_OBJS += refs/reftable-backend.o LIB_OBJS += refs/iterator.o LIB_OBJS += refs/packed-backend.o LIB_OBJS += refs/ref-cache.o
@@ -1162,7 +1164,7 @@ THIRD_PARTY_SOURCES += compat/regex/% THIRD_PARTY_SOURCES += sha1collisiondetection/% THIRD_PARTY_SOURCES += sha1dc/% -GITLIBS = common-main.o $(LIB_FILE) $(XDIFF_LIB) +GITLIBS = common-main.o $(LIB_FILE) $(XDIFF_LIB) $(REFTABLE_LIB) EXTLIBS = GIT_USER_AGENT = git/$(GIT_VERSION)
@@ -2352,11 +2354,30 @@ VCSSVN_OBJS += vcs-svn/sliding_window.o VCSSVN_OBJS += vcs-svn/svndiff.o VCSSVN_OBJS += vcs-svn/svndump.o +REFTABLE_OBJS += reftable/basics.o +REFTABLE_OBJS += reftable/block.o +REFTABLE_OBJS += reftable/compat.o +REFTABLE_OBJS += reftable/file.o +REFTABLE_OBJS += reftable/iter.o +REFTABLE_OBJS += reftable/merged.o +REFTABLE_OBJS += reftable/pq.o +REFTABLE_OBJS += reftable/reader.o +REFTABLE_OBJS += reftable/record.o +REFTABLE_OBJS += reftable/refname.o +REFTABLE_OBJS += reftable/reftable.o +REFTABLE_OBJS += reftable/strbuf.o +REFTABLE_OBJS += reftable/stack.o +REFTABLE_OBJS += reftable/tree.o +REFTABLE_OBJS += reftable/writer.o +REFTABLE_OBJS += reftable/zlib-compat.o + + TEST_OBJS := $(patsubst %$X,%.o,$(TEST_PROGRAMS)) $(patsubst %,t/helper/%,$(TEST_BUILTINS_OBJS)) OBJECTS := $(LIB_OBJS) $(BUILTIN_OBJS) $(PROGRAM_OBJS) $(TEST_OBJS) \ $(XDIFF_OBJS) \ $(VCSSVN_OBJS) \ $(FUZZ_OBJS) \ + $(REFTABLE_OBJS) \ common-main.o \ git.o ifndef NO_CURL
@@ -2497,6 +2518,9 @@ $(XDIFF_LIB): $(XDIFF_OBJS) $(VCSSVN_LIB): $(VCSSVN_OBJS) $(QUIET_AR)$(RM) $@ && $(AR) $(ARFLAGS) $@ $^ +$(REFTABLE_LIB): $(REFTABLE_OBJS) + $(QUIET_AR)$(RM) $@ && $(AR) $(ARFLAGS) $@ $^ + export DEFAULT_EDITOR DEFAULT_PAGER Documentation/GIT-EXCLUDED-PROGRAMS: FORCE
@@ -3112,7 +3136,7 @@ cocciclean: clean: profile-clean coverage-clean cocciclean $(RM) *.res $(RM) $(OBJECTS) - $(RM) $(LIB_FILE) $(XDIFF_LIB) $(VCSSVN_LIB) + $(RM) $(LIB_FILE) $(XDIFF_LIB) $(VCSSVN_LIB) $(REFTABLE_LIB) $(RM) $(ALL_PROGRAMS) $(SCRIPT_LIB) $(BUILT_INS) git$X $(RM) $(TEST_PROGRAMS) $(RM) $(FUZZ_PROGRAMS)
builtin/clone.c +2 -2
@@ -1120,7 +1120,7 @@ int cmd_clone(int argc, const char **argv, const char *prefix) }init_db (git_dir, real_git_dir, option_template,GIT_HASH_UNKNOWN ,NULL , -INIT_DB_QUIET ); +default_ref_storage (),INIT_DB_QUIET );if (real_git_dir) git_dir = real_git_dir;
@@ -1235,7 +1235,7 @@ int cmd_clone(int argc, const char **argv, const char *prefix)* Now that we know what algorithm the remote side is using, * let's set ours to the same thing. */ -initialize_repository_version (hash_algo); +initialize_repository_version (hash_algo,default_ref_storage ());repo_set_hash_algo (the_repository, hash_algo); mapped_refs =wanted_peer_refs (refs, &remote->fetch);
builtin/init-db.c +41 -14
133 lines not on this page · raw message
builtin/worktree.c +24 -3
@@ -12,6 +12,7 @@#include "submodule.h" #include "utf8.h" #include "worktree.h" +#include "../refs/refs-internal.h" static const char *const worktree_usage[] = {N_ ("git worktree add [<options>] <path> [<commit-ish>]" ),
@@ -402,9 +403,29 @@ static int add_worktree(const char *path, const char *refname,* worktree. */ strbuf_reset (&sb); -strbuf_addf (&sb,"%s/HEAD" , sb_repo.buf); -write_file (sb.buf,"%s" ,oid_to_hex (&null_oid)); -strbuf_reset (&sb); +if (get_main_ref_store (the_repository)->be == &refs_be_reftable) { +/* XXX this is cut & paste from reftable_init_db. */ +strbuf_addf (&sb,"%s/HEAD" , sb_repo.buf); +write_file (sb.buf,"%s" ,"ref: refs/heads/.invalid\n" ); +strbuf_reset (&sb); + +strbuf_addf (&sb,"%s/refs" , sb_repo.buf); +safe_create_dir (sb.buf,1 ); +strbuf_reset (&sb); + +strbuf_addf (&sb,"%s/refs/heads" , sb_repo.buf); +write_file (sb.buf,"this repository uses the reftable format" ); +strbuf_reset (&sb); + +strbuf_addf (&sb,"%s/reftable" , sb_repo.buf); +safe_create_dir (sb.buf,1 ); +strbuf_reset (&sb); + }else { +strbuf_addf (&sb,"%s/HEAD" , sb_repo.buf); +write_file (sb.buf,"%s" ,oid_to_hex (&null_oid)); +strbuf_reset (&sb); + } +strbuf_addf (&sb,"%s/commondir" , sb_repo.buf);write_file (sb.buf,"../.." );
cache.h +5 -3
@@ -627,9 +627,10 @@ int path_inside_repo(const char *prefix, const char *path);#define INIT_DB_EXIST_OK 0x0002int init_db (const char *git_dir,const char *real_git_dir, -const char *template_dir,int hash_algo, -const char *initial_branch,unsigned int flags); -void initialize_repository_version (int hash_algo); +const char *template_dir,int hash_algo,const char *initial_branch, +const char *ref_storage_format,unsigned int flags); +void initialize_repository_version (int hash_algo, +const char *ref_storage_format);void sanitize_stdfds (void );int daemonize (void );
@@ -1043,6 +1044,7 @@ struct repository_format {int is_bare;int hash_algo;char *work_tree; +char *ref_storage;struct string_list unknown_extensions;struct string_list v1_only_extensions; };
refs.c +19 -8
@@ -19,10 +19,16 @@#include "repository.h" #include "sigchain.h" +const char *default_ref_storage (void ) +{ +const char *test =getenv ("GIT_TEST_REFTABLE" ); +return test ?"reftable" :"files" ; +} +/* * List of all available backends */ -static struct ref_storage_be *refs_backends = &refs_be_files; +static struct ref_storage_be *refs_backends = &refs_be_reftable;static struct ref_storage_be *find_ref_storage_backend (const char *name) {
@@ -1725,13 +1731,13 @@ static struct ref_store *lookup_ref_store_map(struct hashmap *map,* Create, record, and return a ref_store instance for the specified * gitdir. */ -static struct ref_store *ref_store_init (const char *gitdir, +static struct ref_store *ref_store_init (const char *gitdir,const char *be_name,unsigned int flags) { -const char *be_name ="files" ; -struct ref_storage_be *be =find_ref_storage_backend (be_name); +struct ref_storage_be *be;struct ref_store *refs; + be =find_ref_storage_backend (be_name);if (!be)BUG ("reference backend %s is unknown" , be_name);
@@ -1747,7 +1753,11 @@ struct ref_store *get_main_ref_store(struct repository *r)if (!r->gitdir)BUG ("attempting to get main_ref_store outside of repository" ); - r->refs_private =ref_store_init (r->gitdir,REF_STORE_ALL_CAPS ); + r->refs_private =ref_store_init (r->gitdir, + r->ref_storage_format ? + r->ref_storage_format : +default_ref_storage (), +REF_STORE_ALL_CAPS );return r->refs_private; }
@@ -1802,7 +1812,7 @@ struct ref_store *get_submodule_ref_store(const char *submodule) goto done;/* assume that add_submodule_odb() has been called */ - refs =ref_store_init (submodule_sb.buf, + refs =ref_store_init (submodule_sb.buf,default_ref_storage (),REF_STORE_READ |REF_STORE_ODB );register_ref_store_map (&submodule_ref_stores,"submodule" , refs, submodule);
@@ -1816,6 +1826,7 @@ struct ref_store *get_submodule_ref_store(const char *submodule)struct ref_store *get_worktree_ref_store (const struct worktree *wt) { +const char *format =default_ref_storage ();struct ref_store *refs;const char *id;
@@ -1829,9 +1840,9 @@ struct ref_store *get_worktree_ref_store(const struct worktree *wt)if (wt->id) refs =ref_store_init (git_common_path ("worktrees/%s" , wt->id), -REF_STORE_ALL_CAPS ); + format,REF_STORE_ALL_CAPS );else - refs =ref_store_init (get_git_common_dir (), + refs =ref_store_init (get_git_common_dir (), format,REF_STORE_ALL_CAPS );if (refs)
refs.h +3 -0
@@ -9,6 +9,9 @@ struct string_list;struct string_list_item ;struct worktree ; +/* Returns the ref storage backend to use by default. */ +const char *default_ref_storage (void ); +/* * Resolve a reference, recursively following symbolic refererences. *
refs/refs-internal.h +1 -0
@@ -669,6 +669,7 @@ struct ref_storage_be { };extern struct ref_storage_be refs_be_files; +extern struct ref_storage_be refs_be_reftable;extern struct ref_storage_be refs_be_packed;/*
refs/reftable-backend.c new file +1384 -0
1,384 lines not on this page · raw message
reftable/update.sh +0 -3
@@ -16,7 +16,4 @@ cp reftable-repo/LICENSE reftable/ git --git-dir reftable-repo/.git show --no-patch --format=oneline HEAD \ > reftable/VERSION -mv reftable/system.h reftable/system.h~ -sed 's|if REFTABLE_IN_GITCORE|if 1 /* REFTABLE_IN_GITCORE */|' < reftable/system.h~ > reftable/system.h - git add reftable/*.[ch] reftable/LICENSE reftable/VERSION
repository.c +2 -0
@@ -178,6 +178,8 @@ int repo_init(struct repository *repo,if (worktree)repo_set_worktree (repo, worktree); + repo->ref_storage_format =xstrdup_or_null (format.ref_storage); +clear_repository_format (&format);return 0 ;
repository.h +3 -0
@@ -74,6 +74,9 @@ struct repository {*/ struct ref_store *refs_private; +/* The format to use for the ref database. */ +char *ref_storage_format; +/* * Contains path to often used file names. */
setup.c +8 -2
@@ -490,8 +490,10 @@ static enum extension_result handle_extension(const char *var, {if (!strcmp (ext,"noop-v1" )) {return EXTENSION_OK ; + }else if (!strcmp (ext,"refstorage" )) { + data->ref_storage =xstrdup (value); +return EXTENSION_OK ; } -return EXTENSION_UNKNOWN ; }
@@ -642,6 +644,7 @@ void clear_repository_format(struct repository_format *format)string_list_clear (&format->v1_only_extensions,0 );free (format->work_tree);free (format->partial_clone); +free (format->ref_storage);init_repository_format (format); }
@@ -1299,8 +1302,11 @@ const char *setup_git_directory_gently(int *nongit_ok) gitdir =DEFAULT_GIT_DIR_ENVIRONMENT ;setup_git_env (gitdir); } -if (startup_info->have_repository) +if (startup_info->have_repository) {repo_set_hash_algo (the_repository, repo_fmt.hash_algo); + the_repository->ref_storage_format = +xstrdup_or_null (repo_fmt.ref_storage); + } }strbuf_release (&dir);
t/t0031-reftable.sh new file +173 -0
173 lines not on this page · raw message
Signature · 1 line
gitgitgadget
PATCH v20 18/21 vcxproj: adjust for the reftable changes
In reply to Han-Wen Nienhuys via GitGitGadgetFrom: Johannes Schindelin <[email protected]>
This allows Git to be compiled via Visual Studio again after integrating the hn/reftable branch.
--- config.mak.uname | 2 +- contrib/buildsystems/Generators/Vcxproj.pm | 11 ++++++++++- 2 files changed, 11 insertions(+), 2 deletions(-)
config.mak.uname +1 -1
@@ -709,7 +709,7 @@ vcxproj: # Make .vcxproj files and add them unset QUIET_GEN QUIET_BUILT_IN; \ perl contrib/buildsystems/generate -g Vcxproj - git add -f git.sln {*,*/lib,t/helper/*}/*.vcxproj + git add -f git.sln {*,*/lib,*/libreftable,t/helper/*}/*.vcxproj # Generate the LinkOrCopyBuiltins.targets and LinkOrCopyRemoteHttp.targets file (echo '<Project xmlns="http://schemas.microsoft.com/developer/msbuild/2003">' && \
contrib/buildsystems/Generators/Vcxproj.pm +10 -1
@@ -77,7 +77,7 @@ sub createProject { my $libs_release = "\n "; my $libs_debug = "\n "; if (!$static_library) { - $libs_release = join(";", sort(grep /^(?!libgit\.lib|xdiff\/lib\.lib|vcs-svn\/lib\.lib)/, @{$$build_structure{"$prefix${name}_LIBS"}})); + $libs_release = join(";", sort(grep /^(?!libgit\.lib|xdiff\/lib\.lib|vcs-svn\/lib\.lib|reftable\/libreftable\.lib)/, @{$$build_structure{"$prefix${name}_LIBS"}})); $libs_debug = $libs_release; $libs_debug =~ s/zlib\.lib/zlibd\.lib/g; $libs_debug =~ s/libcurl\.lib/libcurl-d\.lib/g;
@@ -231,6 +231,7 @@ sub createProject { EOM if (!$static_library || $target =~ 'vcs-svn' || $target =~ 'xdiff') { my $uuid_libgit = $$build_structure{"LIBS_libgit_GUID"}; + my $uuid_libreftable = $$build_structure{"LIBS_reftable/libreftable_GUID"}; my $uuid_xdiff_lib = $$build_structure{"LIBS_xdiff/lib_GUID"}; print F << "EOM";
@@ -240,6 +241,14 @@ sub createProject { <ReferenceOutputAssembly>false</ReferenceOutputAssembly> </ProjectReference> EOM + if (!($name =~ /xdiff|libreftable/)) { + print F << "EOM"; + <ProjectReference Include="$cdup\\reftable\\libreftable\\libreftable.vcxproj"> + <Project>$uuid_libreftable</Project> + <ReferenceOutputAssembly>false</ReferenceOutputAssembly> + </ProjectReference> +EOM + } if (!($name =~ 'xdiff')) { print F << "EOM"; <ProjectReference Include="$cdup\\xdiff\\lib\\xdiff_lib.vcxproj">
Signature · 1 line
gitgitgadget
PATCH v20 19/21 git-prompt: prepare for reftable refs backend
In reply to Han-Wen Nienhuys via GitGitGadgetFrom: =?UTF-8?q?SZEDER=20G=C3=A1bor?= <[email protected]>
In our git-prompt script we strive to use Bash builtins wherever possible, because fork()-ing subshells for command substitutions and fork()+exec()-ing Git commands are expensive on some platforms. We even read and parse '.git/HEAD' using Bash builtins to get the name of the current branch [1]. However, the upcoming reftable refs backend won't use '.git/HEAD' at all, but will write an invalid refname as placeholder for backwards compatibility instead, which will break our git-prompt script.
Update the git-prompt script to recognize the placeholder '.git/HEAD' written by the reftable backend (its content is specified in the reftable specs), and then fall back to use 'git symbolic-ref' to get the name of the current branch.
[1] 3a43c4b5bd (bash prompt: use bash builtins to find out current
branch, 2011-03-31)
--- contrib/completion/git-prompt.sh | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-)
contrib/completion/git-prompt.sh +6 -1
@@ -476,10 +476,15 @@ __git_ps1 () if ! __git_eread "$g/HEAD" head; then return $exit fi - # is it a symbolic ref? b="${head#ref: }" if [ "$head" = "$b" ]; then detached=yes + elif [ "$b" = "refs/heads/.invalid" ]; then + # Reftable + b="$(git symbolic-ref HEAD 2>/dev/null)" || + detached=yes + fi + if [ "$detached" = yes ]; then b="$( case "${GIT_PS1_DESCRIBE_STYLE-}" in (contains)
Signature · 1 line
gitgitgadget
PATCH v20 21/21 Add "test-tool dump-reftable" command.
In reply to Han-Wen Nienhuys via GitGitGadgetFrom: Han-Wen Nienhuys <[email protected]>
This command dumps individual tables or a stack of of tables.
--- Makefile | 1 + t/helper/test-reftable.c | 5 +++++ t/helper/test-tool.c | 1 + t/helper/test-tool.h | 1 + 4 files changed, 8 insertions(+)
Makefile +1 -0
@@ -2375,6 +2375,7 @@ REFTABLE_OBJS += reftable/writer.o REFTABLE_OBJS += reftable/zlib-compat.o REFTABLE_TEST_OBJS += reftable/block_test.o +REFTABLE_TEST_OBJS += reftable/dump.o REFTABLE_TEST_OBJS += reftable/merged_test.o REFTABLE_TEST_OBJS += reftable/record_test.o REFTABLE_TEST_OBJS += reftable/refname_test.o
t/helper/test-reftable.c +5 -0
@@ -13,3 +13,8 @@ int cmd__reftable(int argc, const char **argv)tree_test_main (argc, argv);return 0 ; } + +int cmd__dump_reftable (int argc,const char **argv) +{ +return reftable_dump_main (argc, (char *const *)argv); +}
t/helper/test-tool.c +1 -0
@@ -53,6 +53,7 @@ static struct test_cmd cmds[] = { { "read-midx", cmd__read_midx }, { "ref-store", cmd__ref_store }, { "reftable", cmd__reftable }, + { "dump-reftable", cmd__dump_reftable }, { "regex", cmd__regex }, { "repository", cmd__repository }, { "revision-walking", cmd__revision_walking },
t/helper/test-tool.h +1 -0
@@ -17,6 +17,7 @@ int cmd__dump_cache_tree(int argc, const char **argv);int cmd__dump_fsmonitor (int argc,const char **argv);int cmd__dump_split_index (int argc,const char **argv);int cmd__dump_untracked_cache (int argc,const char **argv); +int cmd__dump_reftable (int argc,const char **argv);int cmd__example_decorate (int argc,const char **argv);int cmd__genrandom (int argc,const char **argv);int cmd__genzeros (int argc,const char **argv);
Signature · 1 line
gitgitgadget
PATCH v20 20/21 Add reftable testing infrastructure
In reply to Han-Wen Nienhuys via GitGitGadgetFrom: Han-Wen Nienhuys <[email protected]>
* Add GIT_TEST_REFTABLE environment var to control default ref storage
* Add test_prerequisite REFTABLE.
* Skip some tests that are incompatible:
* t3210-pack-refs.sh - does not apply
* t1450-fsck.sh - manipulates .git/ directly to create invalid state
Major test failures:
* t1400-update-ref.sh - Reads from .git/{refs,logs} directly
* t1404-update-ref-errors.sh - Manipulates .git/refs/ directly
* t1405 - inspecs .git/ directly.
--- t/t1409-avoid-packing-refs.sh | 6 ++++++ t/t1450-fsck.sh | 6 ++++++ t/t3210-pack-refs.sh | 6 ++++++ t/test-lib.sh | 5 +++++ 4 files changed, 23 insertions(+)
t/t1409-avoid-packing-refs.sh +6 -0
@@ -4,6 +4,12 @@ test_description='avoid rewriting packed-refs unnecessarily' . ./test-lib.sh +if test_have_prereq REFTABLE +then + skip_all='skipping pack-refs tests; incompatible with reftable' + test_done +fi + # Add an identifying mark to the packed-refs file header line. This # shouldn't upset readers, and it should be omitted if the file is # ever rewritten.
t/t1450-fsck.sh +6 -0
@@ -8,6 +8,12 @@ test_description='git fsck random collection of tests . ./test-lib.sh +if test_have_prereq REFTABLE +then + skip_all='skipping tests; incompatible with reftable' + test_done +fi + test_expect_success setup ' test_oid_init && git config gc.auto 0 &&
t/t3210-pack-refs.sh +6 -0
@@ -11,6 +11,12 @@ semantic is still the same. ' . ./test-lib.sh +if test_have_prereq REFTABLE +then + skip_all='skipping pack-refs tests; incompatible with reftable' + test_done +fi + test_expect_success 'enable reflogs' ' git config core.logallrefupdates true '
t/test-lib.sh +5 -0
@@ -1508,6 +1508,11 @@ parisc* | hppa*) ;; esac +if test -n "$GIT_TEST_REFTABLE" +then + test_set_prereq REFTABLE +fi + ( COLUMNS=1 && test $COLUMNS = 1 ) && test_set_prereq COLUMNS_CAN_BE_1 test -z "$NO_PERL" && test_set_prereq PERL test -z "$NO_PTHREADS" && test_set_prereq PTHREADS
Signature · 1 line
gitgitgadget
PATCH v20 12/21 Add reftable library
In reply to Han-Wen Nienhuys via GitGitGadgetFrom: Han-Wen Nienhuys <[email protected]>
Reftable is a format for storing the ref database. The rationale and format layout is detailed in commit 35e6c47404 ("reftable: file format documentation", 2020-05-20).
This commits imports a fully functioning library for reading and writing reftables, along with unittests.
It is suggested to read the code in the following order:
* The specification under Documentation/technical/reftable.txt
* reftable.h - the public API
* record.{c,h} - reading and writing records
* block.{c,h} - reading and writing blocks.
* reader.{c,h} - reading a complete reftable file.
* writer.{c,h} - writing a complete reftable file.
* merged.{c,h} and pq.{c,h} - reading a stack of reftables
* stack.{c,h} - writing and compacting stacks of reftable on the filesystem.
--- reftable/LICENSE | 31 + reftable/VERSION | 1 + reftable/basics.c | 215 +++++++ reftable/basics.h | 53 ++ reftable/block.c | 432 +++++++++++++ reftable/block.h | 129 ++++ reftable/block_test.c | 157 +++++ reftable/compat.c | 98 +++ reftable/compat.h | 48 ++ reftable/constants.h | 21 + reftable/dump.c | 212 +++++++ reftable/file.c | 95 +++ reftable/iter.c | 242 ++++++++ reftable/iter.h | 72 +++ reftable/merged.c | 317 ++++++++++ reftable/merged.h | 43 ++ reftable/merged_test.c | 286 +++++++++ reftable/pq.c | 115 ++++ reftable/pq.h | 34 + reftable/reader.c | 744 ++++++++++++++++++++++ reftable/reader.h | 65 ++ reftable/record.c | 1126 ++++++++++++++++++++++++++++++++++ reftable/record.h | 143 +++++ reftable/record_test.c | 410 +++++++++++++ reftable/refname.c | 209 +++++++ reftable/refname.h | 38 ++ reftable/refname_test.c | 99 +++ reftable/reftable-tests.h | 22 + reftable/reftable.c | 154 +++++ reftable/reftable.h | 585 ++++++++++++++++++ reftable/reftable_test.c | 632 +++++++++++++++++++ reftable/stack.c | 1225 +++++++++++++++++++++++++++++++++++++ reftable/stack.h | 50 ++ reftable/stack_test.c | 787 ++++++++++++++++++++++++ reftable/strbuf.c | 206 +++++++ reftable/strbuf.h | 88 +++ reftable/strbuf_test.c | 39 ++ reftable/system.h | 53 ++ reftable/test_framework.c | 69 +++ reftable/test_framework.h | 64 ++ reftable/tree.c | 63 ++ reftable/tree.h | 34 + reftable/tree_test.c | 62 ++ reftable/update.sh | 22 + reftable/writer.c | 663 ++++++++++++++++++++ reftable/writer.h | 60 ++ reftable/zlib-compat.c | 92 +++ 47 files changed, 10405 insertions(+) create mode 100644 reftable/LICENSE create mode 100644 reftable/VERSION create mode 100644 reftable/basics.c create mode 100644 reftable/basics.h create mode 100644 reftable/block.c create mode 100644 reftable/block.h create mode 100644 reftable/block_test.c create mode 100644 reftable/compat.c create mode 100644 reftable/compat.h create mode 100644 reftable/constants.h create mode 100644 reftable/dump.c create mode 100644 reftable/file.c create mode 100644 reftable/iter.c create mode 100644 reftable/iter.h create mode 100644 reftable/merged.c create mode 100644 reftable/merged.h create mode 100644 reftable/merged_test.c create mode 100644 reftable/pq.c create mode 100644 reftable/pq.h create mode 100644 reftable/reader.c create mode 100644 reftable/reader.h create mode 100644 reftable/record.c create mode 100644 reftable/record.h create mode 100644 reftable/record_test.c create mode 100644 reftable/refname.c create mode 100644 reftable/refname.h create mode 100644 reftable/refname_test.c create mode 100644 reftable/reftable-tests.h create mode 100644 reftable/reftable.c create mode 100644 reftable/reftable.h create mode 100644 reftable/reftable_test.c create mode 100644 reftable/stack.c create mode 100644 reftable/stack.h create mode 100644 reftable/stack_test.c create mode 100644 reftable/strbuf.c create mode 100644 reftable/strbuf.h create mode 100644 reftable/strbuf_test.c create mode 100644 reftable/system.h create mode 100644 reftable/test_framework.c create mode 100644 reftable/test_framework.h create mode 100644 reftable/tree.c create mode 100644 reftable/tree.h create mode 100644 reftable/tree_test.c create mode 100755 reftable/update.sh create mode 100644 reftable/writer.c create mode 100644 reftable/writer.h create mode 100644 reftable/zlib-compat.c
reftable/LICENSE new file +31 -0
@@ -0,0 +1,31 @@ +BSD License + +Copyright (c) 2020, Google LLC +All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are +met: + +* Redistributions of source code must retain the above copyright notice, +this list of conditions and the following disclaimer. + +* Redistributions in binary form must reproduce the above copyright +notice, this list of conditions and the following disclaimer in the +documentation and/or other materials provided with the distribution. + +* Neither the name of Google LLC nor the names of its contributors may +be used to endorse or promote products derived from this software +without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
reftable/VERSION new file +1 -0
@@ -0,0 +1 @@ +994cc2f626ff626ff04be5240413775f832110fb C: formatting tweaks
reftable/basics.c new file +215 -0
215 lines not on this page · raw message
reftable/basics.h new file +53 -0
53 lines not on this page · raw message
reftable/block.c new file +432 -0
432 lines not on this page · raw message
reftable/block.h new file +129 -0
129 lines not on this page · raw message
reftable/block_test.c new file +157 -0
157 lines not on this page · raw message
reftable/compat.c new file +98 -0
98 lines not on this page · raw message
reftable/compat.h new file +48 -0
48 lines not on this page · raw message
reftable/constants.h new file +21 -0
@@ -0,0 +1,21 @@ +/* +Copyright 2020 Google LLC + +Use of this source code is governed by a BSD-style +license that can be found in the LICENSE file or at +https://developers.google.com/open-source/licenses/bsd +*/ + +#ifndef CONSTANTS_H +#define CONSTANTS_H + +#define BLOCK_TYPE_LOG 'g' +#define BLOCK_TYPE_INDEX 'i' +#define BLOCK_TYPE_REF 'r' +#define BLOCK_TYPE_OBJ 'o' +#define BLOCK_TYPE_ANY 0 + +#define MAX_RESTARTS ((1 << 16) - 1) +#define DEFAULT_BLOCK_SIZE 4096 + +#endif
reftable/dump.c new file +212 -0
212 lines not on this page · raw message
reftable/file.c new file +95 -0
95 lines not on this page · raw message
reftable/iter.c new file +242 -0
242 lines not on this page · raw message
reftable/iter.h new file +72 -0
72 lines not on this page · raw message
reftable/merged.c new file +317 -0
317 lines not on this page · raw message
reftable/merged.h new file +43 -0
43 lines not on this page · raw message
reftable/merged_test.c new file +286 -0
286 lines not on this page · raw message
reftable/pq.c new file +115 -0
115 lines not on this page · raw message
reftable/pq.h new file +34 -0
@@ -0,0 +1,34 @@ +/* +Copyright 2020 Google LLC + +Use of this source code is governed by a BSD-style +license that can be found in the LICENSE file or at +https://developers.google.com/open-source/licenses/bsd +*/ + +#ifndef PQ_H +#define PQ_H + +#include "record.h" + +struct pq_entry { +int index; +struct reftable_record rec; +}; + +int pq_less (struct pq_entry a,struct pq_entry b); + +struct merged_iter_pqueue { +struct pq_entry *heap; +size_t len; +size_t cap; +}; + +struct pq_entry merged_iter_pqueue_top (struct merged_iter_pqueue pq); +bool merged_iter_pqueue_is_empty (struct merged_iter_pqueue pq); +void merged_iter_pqueue_check (struct merged_iter_pqueue pq); +struct pq_entry merged_iter_pqueue_remove (struct merged_iter_pqueue *pq); +void merged_iter_pqueue_add (struct merged_iter_pqueue *pq,struct pq_entry e); +void merged_iter_pqueue_clear (struct merged_iter_pqueue *pq); + +#endif
reftable/reader.c new file +744 -0
399 lines not on this page · raw message
reftable/reader.h new file +65 -0
65 lines not on this page · raw message
reftable/record.c new file +1126 -0
1,126 lines not on this page · raw message
reftable/record.h new file +143 -0
143 lines not on this page · raw message
reftable/record_test.c new file +410 -0
410 lines not on this page · raw message
reftable/refname.c new file +209 -0
209 lines not on this page · raw message
reftable/refname_test.c new file +99 -0
99 lines not on this page · raw message
reftable/reftable.c new file +154 -0
154 lines not on this page · raw message
reftable/reftable.h new file +585 -0
585 lines not on this page · raw message
reftable/reftable_test.c new file +632 -0
632 lines not on this page · raw message
reftable/stack.c new file +1225 -0
1,225 lines not on this page · raw message
reftable/stack.h new file +50 -0
50 lines not on this page · raw message
reftable/stack_test.c new file +787 -0
787 lines not on this page · raw message
reftable/strbuf.c new file +206 -0
206 lines not on this page · raw message
reftable/strbuf.h new file +88 -0
88 lines not on this page · raw message
reftable/system.h new file +53 -0
53 lines not on this page · raw message
reftable/test_framework.c new file +69 -0
69 lines not on this page · raw message
reftable/test_framework.h new file +64 -0
64 lines not on this page · raw message
reftable/tree.c new file +63 -0
63 lines not on this page · raw message
reftable/tree_test.c new file +62 -0
62 lines not on this page · raw message
reftable/writer.c new file +663 -0
663 lines not on this page · raw message
reftable/writer.h new file +60 -0
60 lines not on this page · raw message
reftable/zlib-compat.c new file +92 -0
92 lines not on this page · raw message
The rest of this diff is not shown. View the raw message.
Signature · 1 line
gitgitgadget
Part of the diff is not shown here. View the raw message.
PATCH v20 17/21 Add GIT_DEBUG_REFS debugging mechanism
In reply to Han-Wen Nienhuys via GitGitGadgetFrom: Han-Wen Nienhuys <[email protected]>
When set in the environment, GIT_DEBUG_REFS makes git print operations and results as they flow through the ref storage backend. This helps debug discrepancies between different ref backends.
--- Makefile | 1 + builtin/worktree.c | 4 +- refs.c | 8 + refs.h | 1 + refs/debug.c | 387 ++++++++++++++++++++++++++++++++++++++++++ refs/refs-internal.h | 6 + t/t0033-debug-refs.sh | 18 ++ 7 files changed, 424 insertions(+), 1 deletion(-) create mode 100644 refs/debug.c create mode 100755 t/t0033-debug-refs.sh
Makefile +1 -0
@@ -961,6 +961,7 @@ LIB_OBJS += rebase.o LIB_OBJS += ref-filter.o LIB_OBJS += reflog-walk.o LIB_OBJS += refs.o +LIB_OBJS += refs/debug.o LIB_OBJS += refs/files-backend.o LIB_OBJS += refs/reftable-backend.o LIB_OBJS += refs/iterator.o
builtin/worktree.c +3 -1
@@ -403,7 +403,9 @@ static int add_worktree(const char *path, const char *refname,* worktree. */ strbuf_reset (&sb); -if (get_main_ref_store (the_repository)->be == &refs_be_reftable) { + +if (!strcmp (ref_store_backend_name (get_main_ref_store (the_repository)), +"reftable" )) {/* XXX this is cut & paste from reftable_init_db. */ strbuf_addf (&sb,"%s/HEAD" , sb_repo.buf);write_file (sb.buf,"%s" ,"ref: refs/heads/.invalid\n" );
refs.c +8 -0
@@ -44,6 +44,11 @@ int ref_storage_backend_exists(const char *name)return find_ref_storage_backend (name) !=NULL ; } +const char *ref_store_backend_name (struct ref_store *refs) +{ +return refs->be->name; +} +/* * How to handle various characters in refnames: * 0: An acceptable character for refs
@@ -1758,6 +1763,9 @@ struct ref_store *get_main_ref_store(struct repository *r) r->ref_storage_format :default_ref_storage (), REF_STORE_ALL_CAPS); +if (getenv ("GIT_DEBUG_REFS" )) { + r->refs_private =debug_wrap (r->gitdir, r->refs_private); + }return r->refs_private; }
refs.h +1 -0
@@ -825,6 +825,7 @@ int reflog_expire(const char *refname, const struct object_id *oid,int ref_storage_backend_exists (const char *name);struct ref_store *get_main_ref_store (struct repository *r); +const char *ref_store_backend_name (struct ref_store *refs);/** * Submodules
refs/debug.c new file +387 -0
387 lines not on this page · raw message
refs/refs-internal.h +6 -0
@@ -695,4 +695,10 @@ int parse_loose_ref_contents(const char *buf, struct object_id *oid,void base_ref_store_init (struct ref_store *refs,const struct ref_storage_be *be); +/* +* Print out ref operations as they occur. Useful for debugging alternate ref +* backends. +*/ +struct ref_store *debug_wrap (const char *gitdir,struct ref_store *store); +#endif /* REFS_REFS_INTERNAL_H */
t/t0033-debug-refs.sh new file +18 -0
@@ -0,0 +1,18 @@ +#!/bin/sh +# +# Copyright (c) 2020 Google LLC +# + +test_description='cross-check reftable with files, using GIT_DEBUG_REFS output' + +. ./test-lib.sh + +test_expect_success 'GIT_DEBUG_REFS' ' + git init --ref-storage=files files && + git init --ref-storage=reftable reftable && + (cd files && GIT_DEBUG_REFS=1 test_commit message file) > files.txt && + (cd reftable && GIT_DEBUG_REFS=1 test_commit message file) > reftable.txt && + test_cmp files.txt reftable.txt +' + +test_done
Signature · 1 line
gitgitgadget