Subject: [PATCH v19 00/20] Reftable support git-core

From: "Han-Wen Nienhuys via GitGitGadget" <[email-masked]>
Date: Mon, 29 Jun 2020 18:56:38 +0000

This adds the reftable library, and hooks it up as a ref backend. 

Includes testing support, to test: make -C t/ GIT_TEST_REFTABLE=1

Summary 21852 tests pass 556 tests fail

v22

 * worktree support

Han-Wen Nienhuys (18):
  lib-t6000.sh: write tag using git-update-ref
  t3432: use git-reflog to inspect the reflog for HEAD
  checkout: add '\n' to reflog message
  Write pseudorefs through ref backends.
  Make refs_ref_exists public
  Treat BISECT_HEAD as a pseudo ref
  Treat CHERRY_PICK_HEAD as a pseudo ref
  Treat REVERT_HEAD as a pseudo ref
  Move REF_LOG_ONLY to refs-internal.h
  Iterate over the "refs/" namespace in for_each_[raw]ref
  Add .gitattributes for the reftable/ directory
  Add reftable library
  Add standalone build infrastructure for reftable
  Reftable support for git-core
  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

 .../technical/repository-version.txt          |    7 +
 Makefile                                      |   47 +-
 builtin/bisect--helper.c                      |    3 +-
 builtin/checkout.c                            |    5 +-
 builtin/clone.c                               |    4 +-
 builtin/commit.c                              |   34 +-
 builtin/init-db.c                             |   54 +-
 builtin/merge.c                               |    2 +-
 builtin/worktree.c                            |   31 +-
 cache.h                                       |    8 +-
 config.mak.uname                              |    2 +-
 contrib/buildsystems/Generators/Vcxproj.pm    |   11 +-
 contrib/completion/git-prompt.sh              |    7 +-
 git-bisect.sh                                 |    4 +-
 path.c                                        |    2 -
 path.h                                        |    9 +-
 refs.c                                        |  157 +-
 refs.h                                        |   16 +
 refs/debug.c                                  |  416 +++++
 refs/files-backend.c                          |  121 +-
 refs/packed-backend.c                         |   21 +-
 refs/refs-internal.h                          |   32 +
 refs/reftable-backend.c                       | 1497 +++++++++++++++++
 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                                       |   12 +-
 t/helper/test-reftable.c                      |   20 +
 t/helper/test-tool.c                          |    2 +
 t/helper/test-tool.h                          |    2 +
 t/lib-t6000.sh                                |    5 +-
 t/t0031-reftable.sh                           |  178 ++
 t/t0033-debug-refs.sh                         |   18 +
 t/t1409-avoid-packing-refs.sh                 |    6 +
 t/t1450-fsck.sh                               |    6 +
 t/t3210-pack-refs.sh                          |    6 +
 t/t3432-rebase-fast-forward.sh                |    7 +-
 t/test-lib.sh                                 |    5 +
 wt-status.c                                   |    6 +-
 91 files changed, 13304 insertions(+), 209 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: b9a2d1a0207fb9ded3fa524f54db3bc322a12cc4
Published-As: https://github.com/gitgitgadget/git/releases/tag/pr-539%2Fhanwen%2Freftable-v19
Fetch-It-Via: git fetch https://github.com/gitgitgadget/git pr-539/hanwen/reftable-v19
Pull-Request: https://github.com/gitgitgadget/git/pull/539

Range-diff vs v18:

  1:  b968b795af =  1:  596c316da4 lib-t6000.sh: write tag using git-update-ref
  -:  ---------- >  2:  277da0cf7e t3432: use git-reflog to inspect the reflog for HEAD
  2:  5210225977 =  3:  125695ce92 checkout: add '\n' to reflog message
  3:  15c9dd66e1 =  4:  5715681b3f Write pseudorefs through ref backends.
  4:  a5bce2e3fe =  5:  c8cf2d2ce1 Make refs_ref_exists public
  5:  a29d898907 =  6:  e36b29de79 Treat BISECT_HEAD as a pseudo ref
  6:  11a690d2b8 =  7:  1676df9851 Treat CHERRY_PICK_HEAD as a pseudo ref
  7:  4e52ec0dbc =  8:  0a5f97ea34 Treat REVERT_HEAD as a pseudo ref
  8:  37e350af15 =  9:  9463ed9093 Move REF_LOG_ONLY to refs-internal.h
  9:  468f00eaf6 = 10:  a116aebe11 Iterate over the "refs/" namespace in for_each_[raw]ref
 10:  21febeaa81 = 11:  e4545658ed Add .gitattributes for the reftable/ directory
 11:  3c84f43cfa ! 12:  169f6c7f54 Add reftable library
     @@ reftable/LICENSE (new)
      
       ## reftable/VERSION (new) ##
      @@
     -+d7472cbd1afe6bf3da53e94971b1cc79ce183fa8 Remove outdated bits of the README file
     ++994cc2f626ff626ff04be5240413775f832110fb C: formatting tweaks
      
       ## reftable/basics.c (new) ##
      @@
     @@ reftable/basics.c (new)
      +void parse_names(char *buf, int size, char ***namesp)
      +{
      +	char **names = NULL;
     -+	int names_cap = 0;
     -+	int names_len = 0;
     ++	size_t names_cap = 0;
     ++	size_t names_len = 0;
      +
      +	char *p = buf;
      +	char *end = buf + size;
     @@ reftable/block_test.c (new)
      +		snprintf(name, sizeof(name), "branch%02d", i);
      +		memset(hash, i, sizeof(hash));
      +
     -+		ref.ref_name = name;
     ++		ref.refname = name;
      +		ref.value = hash;
      +		names[i] = xstrdup(name);
      +		n = block_writer_add(&bw, &rec);
     -+		ref.ref_name = NULL;
     ++		ref.refname = NULL;
      +		ref.value = NULL;
      +		assert(n == 0);
      +	}
     @@ reftable/block_test.c (new)
      +		if (r > 0) {
      +			break;
      +		}
     -+		assert_streq(names[j], ref.ref_name);
     ++		assert_streq(names[j], ref.refname);
      +		j++;
      +	}
      +
     @@ reftable/block_test.c (new)
      +		n = block_iter_next(&it, &rec);
      +		assert(n == 0);
      +
     -+		assert_streq(names[i], ref.ref_name);
     ++		assert_streq(names[i], ref.refname);
      +
      +		want.len--;
      +		n = block_reader_seek(&br, &it, &want);
     @@ reftable/block_test.c (new)
      +
      +		n = block_iter_next(&it, &rec);
      +		assert(n == 0);
     -+		assert_streq(names[10 * (i / 10)], ref.ref_name);
     ++		assert_streq(names[10 * (i / 10)], ref.refname);
      +
      +		block_iter_close(&it);
      +	}
     @@ reftable/iter.c (new)
      +			struct reftable_iterator it = { 0 };
      +
      +			err = reftable_table_seek_ref(&fri->tab, &it,
     -+						      ref->ref_name);
     ++						      ref->refname);
      +			if (err == 0) {
      +				err = reftable_iterator_next_ref(&it, ref);
      +			}
     @@ reftable/merged.c (new)
      +}
      +
      +int reftable_new_merged_table(struct reftable_merged_table **dest,
     -+			      struct reftable_reader **stack, int n,
     ++			      struct reftable_table *stack, int n,
      +			      uint32_t hash_id)
      +{
      +	struct reftable_merged_table *m = NULL;
     @@ reftable/merged.c (new)
      +	uint64_t first_min = 0;
      +	int i = 0;
      +	for (i = 0; i < n; i++) {
     -+		struct reftable_reader *r = stack[i];
     -+		if (r->hash_id != hash_id) {
     ++		uint64_t min = reftable_table_min_update_index(&stack[i]);
     ++		uint64_t max = reftable_table_max_update_index(&stack[i]);
     ++
     ++		if (reftable_table_hash_id(&stack[i]) != hash_id) {
      +			return REFTABLE_FORMAT_ERROR;
      +		}
     -+		if (i > 0 && last_max >= reftable_reader_min_update_index(r)) {
     -+			return REFTABLE_FORMAT_ERROR;
     ++		if (i == 0 || min < first_min) {
     ++			first_min = min;
      +		}
     -+		if (i == 0) {
     -+			first_min = reftable_reader_min_update_index(r);
     ++		if (i == 0 || max > last_max) {
     ++			last_max = max;
      +		}
     -+
     -+		last_max = reftable_reader_max_update_index(r);
      +	}
      +
      +	m = (struct reftable_merged_table *)reftable_calloc(
     @@ reftable/merged.c (new)
      +	return 0;
      +}
      +
     -+void reftable_merged_table_close(struct reftable_merged_table *mt)
     -+{
     -+	int i = 0;
     -+	for (i = 0; i < mt->stack_len; i++) {
     -+		reftable_reader_free(mt->stack[i]);
     -+	}
     -+	FREE_AND_NULL(mt->stack);
     -+	mt->stack_len = 0;
     -+}
     -+
      +/* clears the list of subtable, without affecting the readers themselves. */
      +void merged_table_clear(struct reftable_merged_table *mt)
      +{
     @@ reftable/merged.c (new)
      +	int err = 0;
      +	int i = 0;
      +	for (i = 0; i < mt->stack_len && err == 0; i++) {
     -+		int e = reader_seek(mt->stack[i], &iters[n], rec);
     ++		int e = reftable_table_seek_record(&mt->stack[i], &iters[n],
     ++						   rec);
      +		if (e < 0) {
      +			err = e;
      +		}
     @@ reftable/merged.c (new)
      +				   const char *name)
      +{
      +	struct reftable_ref_record ref = {
     -+		.ref_name = (char *)name,
     ++		.refname = (char *)name,
      +	};
      +	struct reftable_record rec = { 0 };
      +	reftable_record_from_ref(&rec, &ref);
     @@ reftable/merged.c (new)
      +				      const char *name, uint64_t update_index)
      +{
      +	struct reftable_log_record log = {
     -+		.ref_name = (char *)name,
     ++		.refname = (char *)name,
      +		.update_index = update_index,
      +	};
      +	struct reftable_record rec = { 0 };
     @@ reftable/merged.c (new)
      +{
      +	uint64_t max = ~((uint64_t)0);
      +	return reftable_merged_table_seek_log_at(mt, it, name, max);
     ++}
     ++
     ++uint32_t reftable_merged_table_hash_id(struct reftable_merged_table *mt)
     ++{
     ++	return mt->hash_id;
      +}
      
       ## reftable/merged.h (new) ##
     @@ reftable/merged.h (new)
      +#include "reftable.h"
      +
      +struct reftable_merged_table {
     -+	struct reftable_reader **stack;
     -+	int stack_len;
     ++	struct reftable_table *stack;
     ++	size_t stack_len;
      +	uint32_t hash_id;
      +	bool suppress_deletions;
      +
     @@ reftable/merged.h (new)
      +struct merged_iter {
      +	struct reftable_iterator *stack;
      +	uint32_t hash_id;
     -+	int stack_len;
     ++	size_t stack_len;
      +	uint8_t typ;
      +	bool suppress_deletions;
      +	struct merged_iter_pqueue pq;
     @@ reftable/merged.h (new)
      +			     struct reftable_iterator *it,
      +			     struct reftable_record *rec);
      +
     ++int reftable_table_seek_record(struct reftable_table *tab,
     ++			       struct reftable_iterator *it,
     ++			       struct reftable_record *rec);
     ++
      +#endif
      
       ## reftable/merged_test.c (new) ##
     @@ reftable/merged_test.c (new)
      +			reftable_new_record(BLOCK_TYPE_REF);
      +		struct pq_entry e = { 0 };
      +
     -+		reftable_record_as_ref(&rec)->ref_name = names[i];
     ++		reftable_record_as_ref(&rec)->refname = names[i];
      +		e.rec = rec;
      +		merged_iter_pqueue_add(&pq, e);
      +		merged_iter_pqueue_check(pq);
     @@ reftable/merged_test.c (new)
      +		merged_iter_pqueue_check(pq);
      +
      +		if (last != NULL) {
     -+			assert(strcmp(last, ref->ref_name) < 0);
     ++			assert(strcmp(last, ref->refname) < 0);
      +		}
     -+		last = ref->ref_name;
     -+		ref->ref_name = NULL;
     ++		last = ref->refname;
     ++		ref->refname = NULL;
      +		reftable_free(ref);
      +	}
      +
     @@ reftable/merged_test.c (new)
      +
      +static struct reftable_merged_table *
      +merged_table_from_records(struct reftable_ref_record **refs,
     -+			  struct reftable_block_source **source, int *sizes,
     ++			  struct reftable_block_source **source,
     ++			  struct reftable_reader ***readers, int *sizes,
      +			  struct strbuf *buf, int n)
      +{
     -+	struct reftable_reader **rd = reftable_calloc(n * sizeof(*rd));
      +	int i = 0;
      +	struct reftable_merged_table *mt = NULL;
      +	int err;
     ++	struct reftable_table *tabs =
     ++		reftable_calloc(n * sizeof(struct reftable_table));
     ++	*readers = reftable_calloc(n * sizeof(struct reftable_reader *));
      +	*source = reftable_calloc(n * sizeof(**source));
      +	for (i = 0; i < n; i++) {
      +		write_test_table(&buf[i], refs[i], sizes[i]);
      +		block_source_from_strbuf(&(*source)[i], &buf[i]);
      +
     -+		err = reftable_new_reader(&rd[i], &(*source)[i], "name");
     ++		err = reftable_new_reader(&(*readers)[i], &(*source)[i],
     ++					  "name");
      +		assert_err(err);
     ++		reftable_table_from_reader(&tabs[i], (*readers)[i]);
      +	}
      +
     -+	err = reftable_new_merged_table(&mt, rd, n, SHA1_ID);
     ++	err = reftable_new_merged_table(&mt, tabs, n, SHA1_ID);
      +	assert_err(err);
      +	return mt;
      +}
      +
     ++static void readers_destroy(struct reftable_reader **readers, size_t n)
     ++{
     ++	int i = 0;
     ++	for (; i < n; i++)
     ++		reftable_reader_free(readers[i]);
     ++	reftable_free(readers);
     ++}
     ++
      +static void test_merged_between(void)
      +{
      +	uint8_t hash1[SHA1_SIZE] = { 1, 2, 3, 0 };
      +
      +	struct reftable_ref_record r1[] = { {
     -+		.ref_name = "b",
     ++		.refname = "b",
      +		.update_index = 1,
      +		.value = hash1,
      +	} };
      +	struct reftable_ref_record r2[] = { {
     -+		.ref_name = "a",
     ++		.refname = "a",
      +		.update_index = 2,
      +	} };
      +
     @@ reftable/merged_test.c (new)
      +	int sizes[] = { 1, 1 };
      +	struct strbuf bufs[2] = { STRBUF_INIT, STRBUF_INIT };
      +	struct reftable_block_source *bs = NULL;
     ++	struct reftable_reader **readers = NULL;
      +	struct reftable_merged_table *mt =
     -+		merged_table_from_records(refs, &bs, sizes, bufs, 2);
     ++		merged_table_from_records(refs, &bs, &readers, sizes, bufs, 2);
      +	int i;
      +	struct reftable_ref_record ref = { 0 };
      +	struct reftable_iterator it = { 0 };
     @@ reftable/merged_test.c (new)
      +	assert_err(err);
      +	assert(ref.update_index == 2);
      +	reftable_ref_record_clear(&ref);
     -+
      +	reftable_iterator_destroy(&it);
     -+	reftable_merged_table_close(mt);
     ++	readers_destroy(readers, 2);
      +	reftable_merged_table_free(mt);
      +	for (i = 0; i < ARRAY_SIZE(bufs); i++) {
      +		strbuf_release(&bufs[i]);
     @@ reftable/merged_test.c (new)
      +	uint8_t hash1[SHA1_SIZE] = { 1 };
      +	uint8_t hash2[SHA1_SIZE] = { 2 };
      +	struct reftable_ref_record r1[] = { {
     -+						    .ref_name = "a",
     ++						    .refname = "a",
      +						    .update_index = 1,
      +						    .value = hash1,
      +					    },
      +					    {
     -+						    .ref_name = "b",
     ++						    .refname = "b",
      +						    .update_index = 1,
      +						    .value = hash1,
      +					    },
      +					    {
     -+						    .ref_name = "c",
     ++						    .refname = "c",
      +						    .update_index = 1,
      +						    .value = hash1,
      +					    } };
      +	struct reftable_ref_record r2[] = { {
     -+		.ref_name = "a",
     ++		.refname = "a",
      +		.update_index = 2,
      +	} };
      +	struct reftable_ref_record r3[] = {
      +		{
     -+			.ref_name = "c",
     ++			.refname = "c",
      +			.update_index = 3,
      +			.value = hash2,
      +		},
      +		{
     -+			.ref_name = "d",
     ++			.refname = "d",
      +			.update_index = 3,
      +			.value = hash1,
      +		},
     @@ reftable/merged_test.c (new)
      +	int sizes[3] = { 3, 1, 2 };
      +	struct strbuf bufs[3] = { STRBUF_INIT, STRBUF_INIT, STRBUF_INIT };
      +	struct reftable_block_source *bs = NULL;
     -+
     ++	struct reftable_reader **readers = NULL;
      +	struct reftable_merged_table *mt =
     -+		merged_table_from_records(refs, &bs, sizes, bufs, 3);
     ++		merged_table_from_records(refs, &bs, &readers, sizes, bufs, 3);
      +
      +	struct reftable_iterator it = { 0 };
      +	int err = reftable_merged_table_seek_ref(mt, &it, "a");
      +	struct reftable_ref_record *out = NULL;
     -+	int len = 0;
     -+	int cap = 0;
     ++	size_t len = 0;
     ++	size_t cap = 0;
      +	int i = 0;
      +
      +	assert_err(err);
     @@ reftable/merged_test.c (new)
      +	for (i = 0; i < 3; i++) {
      +		strbuf_release(&bufs[i]);
      +	}
     -+	reftable_merged_table_close(mt);
     ++	readers_destroy(readers, 3);
      +	reftable_merged_table_free(mt);
      +	reftable_free(bs);
      +}
     @@ reftable/pq.h (new)
      +
      +struct merged_iter_pqueue {
      +	struct pq_entry *heap;
     -+	int len;
     -+	int cap;
     ++	size_t len;
     ++	size_t cap;
      +};
      +
      +struct pq_entry merged_iter_pqueue_top(struct merged_iter_pqueue pq);
     @@ reftable/reader.c (new)
      +			     uint64_t next_off, uint8_t want_typ)
      +{
      +	int32_t guess_block_size = r->block_size ? r->block_size :
     -+						   DEFAULT_BLOCK_SIZE;
     ++							 DEFAULT_BLOCK_SIZE;
      +	struct reftable_block block = { 0 };
      +	uint8_t block_typ = 0;
      +	int err = 0;
     @@ reftable/reader.c (new)
      +			     struct reftable_iterator *it, const char *name)
      +{
      +	struct reftable_ref_record ref = {
     -+		.ref_name = (char *)name,
     ++		.refname = (char *)name,
      +	};
      +	struct reftable_record rec = { 0 };
      +	reftable_record_from_ref(&rec, &ref);
     @@ reftable/reader.c (new)
      +				uint64_t update_index)
      +{
      +	struct reftable_log_record log = {
     -+		.ref_name = (char *)name,
     ++		.refname = (char *)name,
      +		.update_index = update_index,
      +	};
      +	struct reftable_record rec = { 0 };
     @@ reftable/record.c (new)
      +	const struct reftable_ref_record *rec =
      +		(const struct reftable_ref_record *)r;
      +	strbuf_reset(dest);
     -+	strbuf_addstr(dest, rec->ref_name);
     ++	strbuf_addstr(dest, rec->refname);
      +}
      +
      +static void reftable_ref_record_copy_from(void *rec, const void *src_rec,
     @@ reftable/record.c (new)
      +	/* This is simple and correct, but we could probably reuse the hash
      +	   fields. */
      +	reftable_ref_record_clear(ref);
     -+	if (src->ref_name != NULL) {
     -+		ref->ref_name = xstrdup(src->ref_name);
     ++	if (src->refname != NULL) {
     ++		ref->refname = xstrdup(src->refname);
      +	}
      +
      +	if (src->target != NULL) {
     @@ reftable/record.c (new)
      +			       uint32_t hash_id)
      +{
      +	char hex[SHA256_SIZE + 1] = { 0 };
     -+	printf("ref{%s(%" PRIu64 ") ", ref->ref_name, ref->update_index);
     ++	printf("ref{%s(%" PRIu64 ") ", ref->refname, ref->update_index);
      +	if (ref->value != NULL) {
      +		hex_format(hex, ref->value, hash_size(hash_id));
      +		printf("%s", hex);
     @@ reftable/record.c (new)
      +
      +void reftable_ref_record_clear(struct reftable_ref_record *ref)
      +{
     -+	reftable_free(ref->ref_name);
     ++	reftable_free(ref->refname);
      +	reftable_free(ref->target);
      +	reftable_free(ref->target_value);
      +	reftable_free(ref->value);
     @@ reftable/record.c (new)
      +
      +	string_view_consume(&in, n);
      +
     -+	r->ref_name = reftable_realloc(r->ref_name, key.len + 1);
     -+	memcpy(r->ref_name, key.buf, key.len);
     -+	r->ref_name[key.len] = 0;
     ++	r->refname = reftable_realloc(r->refname, key.len + 1);
     ++	memcpy(r->refname, key.buf, key.len);
     ++	r->refname[key.len] = 0;
      +
      +	switch (val_type) {
      +	case 1:
     @@ reftable/record.c (new)
      +{
      +	char hex[SHA256_SIZE + 1] = { 0 };
      +
     -+	printf("log{%s(%" PRIu64 ") %s <%s> %" PRIu64 " %04d\n", log->ref_name,
     ++	printf("log{%s(%" PRIu64 ") %s <%s> %" PRIu64 " %04d\n", log->refname,
      +	       log->update_index, log->name, log->email, log->time,
      +	       log->tz_offset);
      +	hex_format(hex, log->old_hash, hash_size(hash_id));
     @@ reftable/record.c (new)
      +{
      +	const struct reftable_log_record *rec =
      +		(const struct reftable_log_record *)r;
     -+	int len = strlen(rec->ref_name);
     ++	int len = strlen(rec->refname);
      +	uint8_t i64[8];
      +	uint64_t ts = 0;
      +	strbuf_reset(dest);
     -+	strbuf_add(dest, (uint8_t *)rec->ref_name, len + 1);
     ++	strbuf_add(dest, (uint8_t *)rec->refname, len + 1);
      +
      +	ts = (~ts) - rec->update_index;
      +	put_be64(&i64[0], ts);
     @@ reftable/record.c (new)
      +
      +	reftable_log_record_clear(dst);
      +	*dst = *src;
     -+	if (dst->ref_name != NULL) {
     -+		dst->ref_name = xstrdup(dst->ref_name);
     ++	if (dst->refname != NULL) {
     ++		dst->refname = xstrdup(dst->refname);
      +	}
      +	if (dst->email != NULL) {
      +		dst->email = xstrdup(dst->email);
     @@ reftable/record.c (new)
      +
      +void reftable_log_record_clear(struct reftable_log_record *r)
      +{
     -+	reftable_free(r->ref_name);
     ++	reftable_free(r->refname);
      +	reftable_free(r->new_hash);
      +	reftable_free(r->old_hash);
      +	reftable_free(r->name);
     @@ reftable/record.c (new)
      +	if (key.len <= 9 || key.buf[key.len - 9] != 0)
      +		return REFTABLE_FORMAT_ERROR;
      +
     -+	r->ref_name = reftable_realloc(r->ref_name, key.len - 8);
     -+	memcpy(r->ref_name, key.buf, key.len - 8);
     ++	r->refname = reftable_realloc(r->refname, key.len - 8);
     ++	memcpy(r->refname, key.buf, key.len - 8);
      +	ts = get_be64(key.buf + key.len - 8);
      +
      +	r->update_index = (~max) - ts;
     @@ reftable/record.c (new)
      +			       struct reftable_ref_record *b, int hash_size)
      +{
      +	assert(hash_size > 0);
     -+	return 0 == strcmp(a->ref_name, b->ref_name) &&
     ++	return 0 == strcmp(a->refname, b->refname) &&
      +	       a->update_index == b->update_index &&
      +	       hash_equal(a->value, b->value, hash_size) &&
      +	       hash_equal(a->target_value, b->target_value, hash_size) &&
     @@ reftable/record.c (new)
      +
      +int reftable_ref_record_compare_name(const void *a, const void *b)
      +{
     -+	return strcmp(((struct reftable_ref_record *)a)->ref_name,
     -+		      ((struct reftable_ref_record *)b)->ref_name);
     ++	return strcmp(((struct reftable_ref_record *)a)->refname,
     ++		      ((struct reftable_ref_record *)b)->refname);
      +}
      +
      +bool reftable_ref_record_is_deletion(const struct reftable_ref_record *ref)
     @@ reftable/record.c (new)
      +	struct reftable_log_record *la = (struct reftable_log_record *)a;
      +	struct reftable_log_record *lb = (struct reftable_log_record *)b;
      +
     -+	int cmp = strcmp(la->ref_name, lb->ref_name);
     ++	int cmp = strcmp(la->refname, lb->refname);
      +	if (cmp)
      +		return cmp;
      +	if (la->update_index > lb->update_index)
     @@ reftable/record.h (new)
      +*/
      +struct string_view {
      +	uint8_t *buf;
     -+	int len;
     ++	size_t len;
      +};
      +
      +/* Advance `s.buf` by `n`, and decrease length. */
     @@ reftable/record_test.c (new)
      +	for (i = 0; i <= 3; i++) {
      +		struct reftable_ref_record in = { 0 };
      +		struct reftable_ref_record out = {
     -+			.ref_name = xstrdup("old name"),
     ++			.refname = xstrdup("old name"),
      +			.value = reftable_calloc(SHA1_SIZE),
      +			.target_value = reftable_calloc(SHA1_SIZE),
      +			.target = xstrdup("old value"),
     @@ reftable/record_test.c (new)
      +			in.target = xstrdup("target");
      +			break;
      +		}
     -+		in.ref_name = xstrdup("refs/heads/master");
     ++		in.refname = xstrdup("refs/heads/master");
      +
      +		reftable_record_from_ref(&rec, &in);
      +		test_copy(&rec);
     @@ reftable/record_test.c (new)
      +{
      +	struct reftable_log_record in[2] = {
      +		{
     -+			.ref_name = xstrdup("refs/heads/master"),
     ++			.refname = xstrdup("refs/heads/master"),
      +			.update_index = 42,
      +		},
      +		{
     -+			.ref_name = xstrdup("refs/heads/master"),
     ++			.refname = xstrdup("refs/heads/master"),
      +			.update_index = 22,
      +		}
      +	};
     @@ reftable/record_test.c (new)
      +{
      +	struct reftable_log_record in[2] = {
      +		{
     -+			.ref_name = xstrdup("refs/heads/master"),
     ++			.refname = xstrdup("refs/heads/master"),
      +			.old_hash = reftable_malloc(SHA1_SIZE),
      +			.new_hash = reftable_malloc(SHA1_SIZE),
      +			.name = xstrdup("han-wen"),
     @@ reftable/record_test.c (new)
      +			.tz_offset = 100,
      +		},
      +		{
     -+			.ref_name = xstrdup("refs/heads/master"),
     ++			.refname = xstrdup("refs/heads/master"),
      +			.update_index = 22,
      +		}
      +	};
     @@ reftable/record_test.c (new)
      +		};
      +		/* populate out, to check for leaks. */
      +		struct reftable_log_record out = {
     -+			.ref_name = xstrdup("old name"),
     ++			.refname = xstrdup("old name"),
      +			.new_hash = reftable_calloc(SHA1_SIZE),
      +			.old_hash = reftable_calloc(SHA1_SIZE),
      +			.name = xstrdup("old name"),
     @@ reftable/refname.c (new)
      +		if (mod->del_len > 0) {
      +			struct find_arg arg = {
      +				.names = mod->del,
     -+				.want = ref.ref_name,
     ++				.want = ref.refname,
      +			};
      +			int idx = binsearch(mod->del_len, find_name, &arg);
      +			if (idx < mod->del_len &&
     -+			    !strcmp(ref.ref_name, mod->del[idx])) {
     ++			    !strcmp(ref.refname, mod->del[idx])) {
      +				continue;
      +			}
      +		}
      +
     -+		if (strncmp(ref.ref_name, prefix, strlen(prefix))) {
     ++		if (strncmp(ref.refname, prefix, strlen(prefix))) {
      +			err = 1;
      +			goto done;
      +		}
     @@ reftable/refname.c (new)
      +	return err;
      +}
      +
     -+int validate_ref_name(const char *name)
     ++int validate_refname(const char *name)
      +{
      +	while (true) {
      +		char *next = strchr(name, '/');
     @@ reftable/refname.c (new)
      +	int err = 0;
      +	for (; i < sz; i++) {
      +		if (reftable_ref_record_is_deletion(&recs[i])) {
     -+			mod.del[mod.del_len++] = recs[i].ref_name;
     ++			mod.del[mod.del_len++] = recs[i].refname;
      +		} else {
     -+			mod.add[mod.add_len++] = recs[i].ref_name;
     ++			mod.add[mod.add_len++] = recs[i].refname;
      +		}
      +	}
      +
     @@ reftable/refname.c (new)
      +	int err = 0;
      +	int i = 0;
      +	for (; i < mod->add_len; i++) {
     -+		err = validate_ref_name(mod->add[i]);
     ++		err = validate_refname(mod->add[i]);
      +		if (err)
      +			goto done;
      +		strbuf_reset(&slashed);
     @@ reftable/refname.h (new)
      +				     const char *prefix);
      +
      +// 0 = OK.
     -+int validate_ref_name(const char *name);
     ++int validate_refname(const char *name);
      +
      +int validate_ref_record_addition(struct reftable_table tab,
      +				 struct reftable_ref_record *recs, size_t sz);
     @@ reftable/refname_test.c (new)
      +	struct reftable_writer *w =
      +		reftable_new_writer(&strbuf_add_void, &buf, &opts);
      +	struct reftable_ref_record rec = {
     -+		.ref_name = "a/b",
     ++		.refname = "a/b",
      +		.target = "destination", /* make sure it's not a symref. */
      +		.update_index = 1,
      +	};
     @@ reftable/reftable.c (new)
      +#include "merged.h"
      +
      +struct reftable_table_vtable {
     -+	int (*seek)(void *tab, struct reftable_iterator *it,
     -+		    struct reftable_record *);
     ++	int (*seek_record)(void *tab, struct reftable_iterator *it,
     ++			   struct reftable_record *);
     ++	uint32_t (*hash_id)(void *tab);
     ++	uint64_t (*min_update_index)(void *tab);
     ++	uint64_t (*max_update_index)(void *tab);
      +};
      +
      +static int reftable_reader_seek_void(void *tab, struct reftable_iterator *it,
     @@ reftable/reftable.c (new)
      +	return reader_seek((struct reftable_reader *)tab, it, rec);
      +}
      +
     ++static uint32_t reftable_reader_hash_id_void(void *tab)
     ++{
     ++	return reftable_reader_hash_id((struct reftable_reader *)tab);
     ++}
     ++
     ++static uint64_t reftable_reader_min_update_index_void(void *tab)
     ++{
     ++	return reftable_reader_min_update_index((struct reftable_reader *)tab);
     ++}
     ++
     ++static uint64_t reftable_reader_max_update_index_void(void *tab)
     ++{
     ++	return reftable_reader_max_update_index((struct reftable_reader *)tab);
     ++}
     ++
      +static struct reftable_table_vtable reader_vtable = {
     -+	.seek = reftable_reader_seek_void,
     ++	.seek_record = reftable_reader_seek_void,
     ++	.hash_id = reftable_reader_hash_id_void,
     ++	.min_update_index = reftable_reader_min_update_index_void,
     ++	.max_update_index = reftable_reader_max_update_index_void,
      +};
      +
      +static int reftable_merged_table_seek_void(void *tab,
     @@ reftable/reftable.c (new)
      +					rec);
      +}
      +
     ++static uint32_t reftable_merged_table_hash_id_void(void *tab)
     ++{
     ++	return reftable_merged_table_hash_id(
     ++		(struct reftable_merged_table *)tab);
     ++}
     ++
     ++static uint64_t reftable_merged_table_min_update_index_void(void *tab)
     ++{
     ++	return reftable_merged_table_min_update_index(
     ++		(struct reftable_merged_table *)tab);
     ++}
     ++
     ++static uint64_t reftable_merged_table_max_update_index_void(void *tab)
     ++{
     ++	return reftable_merged_table_max_update_index(
     ++		(struct reftable_merged_table *)tab);
     ++}
     ++
      +static struct reftable_table_vtable merged_table_vtable = {
     -+	.seek = reftable_merged_table_seek_void,
     ++	.seek_record = reftable_merged_table_seek_void,
     ++	.hash_id = reftable_merged_table_hash_id_void,
     ++	.min_update_index = reftable_merged_table_min_update_index_void,
     ++	.max_update_index = reftable_merged_table_max_update_index_void,
      +};
      +
      +int reftable_table_seek_ref(struct reftable_table *tab,
      +			    struct reftable_iterator *it, const char *name)
      +{
      +	struct reftable_ref_record ref = {
     -+		.ref_name = (char *)name,
     ++		.refname = (char *)name,
      +	};
      +	struct reftable_record rec = { 0 };
      +	reftable_record_from_ref(&rec, &ref);
     -+	return tab->ops->seek(tab->table_arg, it, &rec);
     ++	return tab->ops->seek_record(tab->table_arg, it, &rec);
      +}
      +
      +void reftable_table_from_reader(struct reftable_table *tab,
     @@ reftable/reftable.c (new)
      +	if (err)
      +		goto done;
      +
     -+	if (strcmp(ref->ref_name, name) ||
     ++	if (strcmp(ref->refname, name) ||
      +	    reftable_ref_record_is_deletion(ref)) {
      +		reftable_ref_record_clear(ref);
      +		err = 1;
     @@ reftable/reftable.c (new)
      +done:
      +	reftable_iterator_destroy(&it);
      +	return err;
     ++}
     ++
     ++int reftable_table_seek_record(struct reftable_table *tab,
     ++			       struct reftable_iterator *it,
     ++			       struct reftable_record *rec)
     ++{
     ++	return tab->ops->seek_record(tab->table_arg, it, rec);
     ++}
     ++
     ++uint64_t reftable_table_max_update_index(struct reftable_table *tab)
     ++{
     ++	return tab->ops->max_update_index(tab->table_arg);
     ++}
     ++
     ++uint64_t reftable_table_min_update_index(struct reftable_table *tab)
     ++{
     ++	return tab->ops->min_update_index(tab->table_arg);
     ++}
     ++
     ++uint32_t reftable_table_hash_id(struct reftable_table *tab)
     ++{
     ++	return tab->ops->hash_id(tab->table_arg);
      +}
      
       ## reftable/reftable.h (new) ##
     @@ reftable/reftable.h (new)
      +
      +/* reftable_ref_record holds a ref database entry target_value */
      +struct reftable_ref_record {
     -+	char *ref_name; /* Name of the ref, malloced. */
     ++	char *refname; /* Name of the ref, malloced. */
      +	uint64_t update_index; /* Logical timestamp at which this value is
      +				  written */
      +	uint8_t *value; /* SHA1, or NULL. malloced. */
     @@ reftable/reftable.h (new)
      +
      +/* reftable_log_record holds a reflog entry */
      +struct reftable_log_record {
     -+	char *ref_name;
     ++	char *refname;
      +	uint64_t update_index; /* logical timestamp of a transactional update.
      +				*/
      +	uint8_t *new_hash;
     @@ reftable/reftable.h (new)
      +	REFTABLE_LOCK_ERROR = -5,
      +
      +	/* Misuse of the API:
     -+	   - on writing a record with NULL ref_name.
     ++	   - on writing a record with NULL refname.
      +	   - on writing a reftable_ref_record outside the table limits
      +	   - on writing a ref or log record before the stack's next_update_index
      +	   - on writing a log record with multiline message with
     @@ reftable/reftable.h (new)
      +/* A merged table is implements seeking/iterating over a stack of tables. */
      +struct reftable_merged_table;
      +
     ++/* A generic reftable; see below. */
     ++struct reftable_table;
     ++
      +/* reftable_new_merged_table creates a new merged table. It takes ownership of
      +   the stack array.
      +*/
      +int reftable_new_merged_table(struct reftable_merged_table **dest,
     -+			      struct reftable_reader **stack, int n,
     ++			      struct reftable_table *stack, int n,
      +			      uint32_t hash_id);
      +
      +/* returns an iterator positioned just before 'name' */
     @@ reftable/reftable.h (new)
      +uint64_t
      +reftable_merged_table_min_update_index(struct reftable_merged_table *mt);
      +
     -+/* closes readers for the merged tables */
     -+void reftable_merged_table_close(struct reftable_merged_table *mt);
     -+
      +/* releases memory for the merged_table */
      +void reftable_merged_table_free(struct reftable_merged_table *m);
      +
     ++/* return the hash ID of the merged table. */
     ++uint32_t reftable_merged_table_hash_id(struct reftable_merged_table *m);
     ++
      +/****************************************************************
      + Generic tables
      +
     @@ reftable/reftable.h (new)
      +
      +void reftable_table_from_reader(struct reftable_table *tab,
      +				struct reftable_reader *reader);
     ++
     ++/* returns the hash ID from a generic reftable_table */
     ++uint32_t reftable_table_hash_id(struct reftable_table *tab);
     ++
     ++/* create a generic table from reftable_merged_table */
      +void reftable_table_from_merged_table(struct reftable_table *tab,
      +				      struct reftable_merged_table *table);
      +
     ++/* returns the max update_index covered by this table. */
     ++uint64_t reftable_table_max_update_index(struct reftable_table *tab);
     ++
     ++/* returns the min update_index covered by this table. */
     ++uint64_t reftable_table_min_update_index(struct reftable_table *tab);
     ++
      +/* convenience function to read a single ref. Returns < 0 for error, 0
      +   for success, and 1 if ref not found. */
      +int reftable_table_read_ref(struct reftable_table *tab, const char *name,
     @@ reftable/reftable_test.c (new)
      +		reftable_new_writer(&strbuf_add_void, &buf, &opts);
      +
      +	struct reftable_ref_record rec = {
     -+		.ref_name = "master",
     ++		.refname = "master",
      +		.update_index = 1,
      +	};
      +	int err;
      +	struct reftable_block_source source = { 0 };
     -+	struct reftable_reader **readers = malloc(sizeof(*readers) * 1);
     ++	struct reftable_reader **readers =
     ++		reftable_calloc(sizeof(*readers) * 1);
     ++	struct reftable_table *tab = reftable_calloc(sizeof(*tab) * 1);
      +	uint32_t hash_id;
      +	struct reftable_reader *rd = NULL;
      +	struct reftable_merged_table *merged = NULL;
     @@ reftable/reftable_test.c (new)
      +	hash_id = reftable_reader_hash_id(rd);
      +	assert(hash_id == SHA1_ID);
      +
     -+	readers[0] = rd;
     -+
     -+	err = reftable_new_merged_table(&merged, readers, 1, SHA1_ID);
     ++	reftable_table_from_reader(&tab[0], rd);
     ++	err = reftable_new_merged_table(&merged, tab, 1, SHA1_ID);
      +	assert_err(err);
      +
     -+	reftable_merged_table_close(merged);
     ++	reader_close(rd);
      +	reftable_merged_table_free(merged);
      +	strbuf_release(&buf);
      +}
     @@ reftable/reftable_test.c (new)
      +
      +		snprintf(name, sizeof(name), "refs/heads/branch%02d", i);
      +
     -+		ref.ref_name = name;
     ++		ref.refname = name;
      +		ref.value = hash;
      +		ref.update_index = update_index;
      +		(*names)[i] = xstrdup(name);
     @@ reftable/reftable_test.c (new)
      +
      +		snprintf(name, sizeof(name), "refs/heads/branch%02d", i);
      +
     -+		log.ref_name = name;
     ++		log.refname = name;
      +		log.new_hash = hash;
      +		log.update_index = update_index;
      +		log.message = "message";
     @@ reftable/reftable_test.c (new)
      +	};
      +	int err;
      +	struct reftable_log_record log = {
     -+		.ref_name = "refs/heads/master",
     ++		.refname = "refs/heads/master",
      +		.name = "Han-Wen Nienhuys",
      +		.email = "[email-masked]",
      +		.tz_offset = 100,
     @@ reftable/reftable_test.c (new)
      +		snprintf(name, sizeof(name), "b%02d%0*d", i, 130, 7);
      +		names[i] = xstrdup(name);
      +		puts(name);
     -+		ref.ref_name = name;
     ++		ref.refname = name;
      +		ref.update_index = i;
      +
      +		err = reftable_writer_add_ref(w, &ref);
     @@ reftable/reftable_test.c (new)
      +		set_test_hash(hash1, i);
      +		set_test_hash(hash2, i + 1);
      +
     -+		log.ref_name = names[i];
     ++		log.refname = names[i];
      +		log.update_index = i;
      +		log.old_hash = hash1;
      +		log.new_hash = hash2;
     @@ reftable/reftable_test.c (new)
      +		}
      +
      +		assert_err(err);
     -+		assert_streq(names[i], log.ref_name);
     ++		assert_streq(names[i], log.refname);
      +		assert(i == log.update_index);
      +		i++;
      +		reftable_log_record_clear(&log);
     @@ reftable/reftable_test.c (new)
      +		if (r > 0) {
      +			break;
      +		}
     -+		assert(0 == strcmp(names[j], ref.ref_name));
     ++		assert(0 == strcmp(names[j], ref.refname));
      +		assert(update_index == ref.update_index);
      +
      +		j++;
     @@ reftable/reftable_test.c (new)
      +		assert_err(err);
      +		err = reftable_iterator_next_ref(&it, &ref);
      +		assert_err(err);
     -+		assert(0 == strcmp(names[i], ref.ref_name));
     ++		assert(0 == strcmp(names[i], ref.refname));
      +		assert(i == ref.value[0]);
      +
      +		reftable_ref_record_clear(&ref);
     @@ reftable/reftable_test.c (new)
      +		/* Put the variable part in the start */
      +		snprintf(name, sizeof(name), "br%02d%s", i, fill);
      +		name[40] = 0;
     -+		ref.ref_name = name;
     ++		ref.refname = name;
      +
      +		set_test_hash(hash1, i / 4);
      +		set_test_hash(hash2, 3 + i / 4);
     @@ reftable/reftable_test.c (new)
      +		}
      +
      +		assert(j < want_names_len);
     -+		assert(0 == strcmp(ref.ref_name, want_names[j]));
     ++		assert(0 == strcmp(ref.refname, want_names[j]));
      +		j++;
      +		reftable_ref_record_clear(&ref);
      +	}
     @@ reftable/stack.c (new)
      +void reftable_stack_destroy(struct reftable_stack *st)
      +{
      +	if (st->merged != NULL) {
     -+		reftable_merged_table_close(st->merged);
      +		reftable_merged_table_free(st->merged);
      +		st->merged = NULL;
      +	}
     ++
     ++	if (st->readers != NULL) {
     ++		int i = 0;
     ++		for (i = 0; i < st->readers_len; i++) {
     ++			reftable_reader_free(st->readers[i]);
     ++		}
     ++		st->readers_len = 0;
     ++		FREE_AND_NULL(st->readers);
     ++	}
      +	FREE_AND_NULL(st->list_file);
      +	FREE_AND_NULL(st->reftable_dir);
      +	reftable_free(st);
     @@ reftable/stack.c (new)
      +		reftable_calloc(sizeof(struct reftable_reader *) * cur_len);
      +	int i = 0;
      +	for (i = 0; i < cur_len; i++) {
     -+		cur[i] = st->merged->stack[i];
     ++		cur[i] = st->readers[i];
      +	}
      +	return cur;
      +}
     @@ reftable/stack.c (new)
      +	struct reftable_reader **cur = stack_copy_readers(st, cur_len);
      +	int err = 0;
      +	int names_len = names_length(names);
     -+	struct reftable_reader **new_tables =
     -+		reftable_malloc(sizeof(struct reftable_reader *) * names_len);
     -+	int new_tables_len = 0;
     ++	struct reftable_reader **new_readers =
     ++		reftable_calloc(sizeof(struct reftable_reader *) * names_len);
     ++	struct reftable_table *new_tables =
     ++		reftable_calloc(sizeof(struct reftable_table) * names_len);
     ++	int new_readers_len = 0;
      +	struct reftable_merged_table *new_merged = NULL;
      +	int i;
      +
     @@ reftable/stack.c (new)
      +				goto done;
      +		}
      +
     -+		new_tables[new_tables_len++] = rd;
     ++		new_readers[new_readers_len] = rd;
     ++		reftable_table_from_reader(&new_tables[new_readers_len], rd);
     ++		new_readers_len++;
      +	}
      +
      +	/* success! */
     -+	err = reftable_new_merged_table(&new_merged, new_tables, new_tables_len,
     -+					st->config.hash_id);
     ++	err = reftable_new_merged_table(&new_merged, new_tables,
     ++					new_readers_len, st->config.hash_id);
      +	if (err < 0)
      +		goto done;
      +
      +	new_tables = NULL;
     -+	new_tables_len = 0;
     ++	st->readers_len = new_readers_len;
      +	if (st->merged != NULL) {
      +		merged_table_clear(st->merged);
      +		reftable_merged_table_free(st->merged);
      +	}
     ++	if (st->readers != NULL) {
     ++		reftable_free(st->readers);
     ++	}
     ++	st->readers = new_readers;
     ++	new_readers = NULL;
     ++	new_readers_len = 0;
     ++
      +	new_merged->suppress_deletions = true;
      +	st->merged = new_merged;
     -+
      +	for (i = 0; i < cur_len; i++) {
      +		if (cur[i] != NULL) {
      +			reader_close(cur[i]);
     @@ reftable/stack.c (new)
      +	}
      +
      +done:
     -+	for (i = 0; i < new_tables_len; i++) {
     -+		reader_close(new_tables[i]);
     -+		reftable_reader_free(new_tables[i]);
     ++	for (i = 0; i < new_readers_len; i++) {
     ++		reader_close(new_readers[i]);
     ++		reftable_reader_free(new_readers[i]);
      +	}
     ++	reftable_free(new_readers);
      +	reftable_free(new_tables);
      +	reftable_free(cur);
      +	return err;
     @@ reftable/stack.c (new)
      +	if (err < 0)
      +		return err;
      +
     -+	for (i = 0; i < st->merged->stack_len; i++) {
     ++	for (i = 0; i < st->readers_len; i++) {
      +		if (names[i] == NULL) {
      +			err = 1;
      +			goto done;
      +		}
      +
     -+		if (strcmp(st->merged->stack[i]->name, names[i])) {
     ++		if (strcmp(st->readers[i]->name, names[i])) {
      +			err = 1;
      +			goto done;
      +		}
     @@ reftable/stack.c (new)
      +		goto done;
      +
      +	for (i = 0; i < add->stack->merged->stack_len; i++) {
     -+		strbuf_addstr(&table_list, add->stack->merged->stack[i]->name);
     ++		strbuf_addstr(&table_list, add->stack->readers[i]->name);
      +		strbuf_addstr(&table_list, "\n");
      +	}
      +	for (i = 0; i < add->new_tables_len; i++) {
     @@ reftable/stack.c (new)
      +{
      +	int sz = st->merged->stack_len;
      +	if (sz > 0)
     -+		return reftable_reader_max_update_index(
     -+			       st->merged->stack[sz - 1]) +
     ++		return reftable_reader_max_update_index(st->readers[sz - 1]) +
      +		       1;
      +	return 1;
      +}
     @@ reftable/stack.c (new)
      +	int err = 0;
      +
      +	format_name(&next_name,
     -+		    reftable_reader_min_update_index(st->merged->stack[first]),
     -+		    reftable_reader_max_update_index(st->merged->stack[first]));
     ++		    reftable_reader_min_update_index(st->readers[first]),
     ++		    reftable_reader_max_update_index(st->readers[first]));
      +
      +	strbuf_reset(temp_tab);
      +	strbuf_addstr(temp_tab, st->reftable_dir);
     @@ reftable/stack.c (new)
      +			struct reftable_log_expiry_config *config)
      +{
      +	int subtabs_len = last - first + 1;
     -+	struct reftable_reader **subtabs = reftable_calloc(
     -+		sizeof(struct reftable_reader *) * (last - first + 1));
     ++	struct reftable_table *subtabs = reftable_calloc(
     ++		sizeof(struct reftable_table) * (last - first + 1));
      +	struct reftable_merged_table *mt = NULL;
      +	int err = 0;
      +	struct reftable_iterator it = { 0 };
     @@ reftable/stack.c (new)
      +
      +	int i = 0, j = 0;
      +	for (i = first, j = 0; i <= last; i++) {
     -+		struct reftable_reader *t = st->merged->stack[i];
     -+		subtabs[j++] = t;
     ++		struct reftable_reader *t = st->readers[i];
     ++		reftable_table_from_reader(&subtabs[j++], t);
      +		st->stats.bytes += t->size;
      +	}
     -+	reftable_writer_set_limits(wr,
     -+				   st->merged->stack[first]->min_update_index,
     -+				   st->merged->stack[last]->max_update_index);
     ++	reftable_writer_set_limits(wr, st->readers[first]->min_update_index,
     ++				   st->readers[last]->max_update_index);
      +
      +	err = reftable_new_merged_table(&mt, subtabs, subtabs_len,
      +					st->config.hash_id);
     @@ reftable/stack.c (new)
      +
      +		strbuf_addstr(&subtab_file_name, st->reftable_dir);
      +		strbuf_addstr(&subtab_file_name, "/");
     -+		strbuf_addstr(&subtab_file_name,
     -+			      reader_name(st->merged->stack[i]));
     ++		strbuf_addstr(&subtab_file_name, reader_name(st->readers[i]));
      +
      +		strbuf_reset(&subtab_lock);
      +		strbuf_addbuf(&subtab_lock, &subtab_file_name);
     @@ reftable/stack.c (new)
      +	}
      +	have_lock = true;
      +
     -+	format_name(&new_table_name, st->merged->stack[first]->min_update_index,
     -+		    st->merged->stack[last]->max_update_index);
     ++	format_name(&new_table_name, st->readers[first]->min_update_index,
     ++		    st->readers[last]->max_update_index);
      +	strbuf_addstr(&new_table_name, ".ref");
      +
      +	strbuf_reset(&new_table_path);
     @@ reftable/stack.c (new)
      +	}
      +
      +	for (i = 0; i < first; i++) {
     -+		strbuf_addstr(&ref_list_contents, st->merged->stack[i]->name);
     ++		strbuf_addstr(&ref_list_contents, st->readers[i]->name);
      +		strbuf_addstr(&ref_list_contents, "\n");
      +	}
      +	if (!is_empty_table) {
     @@ reftable/stack.c (new)
      +		strbuf_addstr(&ref_list_contents, "\n");
      +	}
      +	for (i = last + 1; i < st->merged->stack_len; i++) {
     -+		strbuf_addstr(&ref_list_contents, st->merged->stack[i]->name);
     ++		strbuf_addstr(&ref_list_contents, st->readers[i]->name);
      +		strbuf_addstr(&ref_list_contents, "\n");
      +	}
      +
     @@ reftable/stack.c (new)
      +	int overhead = header_size(version) - 1;
      +	int i = 0;
      +	for (i = 0; i < st->merged->stack_len; i++) {
     -+		sizes[i] = st->merged->stack[i]->size - overhead;
     ++		sizes[i] = st->readers[i]->size - overhead;
      +	}
      +	return sizes;
      +}
     @@ reftable/stack.c (new)
      +	if (err)
      +		goto done;
      +
     -+	if (strcmp(log->ref_name, refname) ||
     ++	if (strcmp(log->refname, refname) ||
      +	    reftable_log_record_is_deletion(log)) {
      +		err = 1;
      +		goto done;
     @@ reftable/stack.h (new)
      +
      +	struct reftable_write_options config;
      +
     ++	struct reftable_reader **readers;
     ++	size_t readers_len;
      +	struct reftable_merged_table *merged;
      +	struct reftable_compaction_stats stats;
      +};
     @@ reftable/stack_test.c (new)
      +	struct reftable_stack *st = NULL;
      +	int err;
      +	struct reftable_ref_record ref = {
     -+		.ref_name = "HEAD",
     ++		.refname = "HEAD",
      +		.update_index = 1,
      +		.target = "master",
      +	};
     @@ reftable/stack_test.c (new)
      +	err = reftable_stack_add(st, &write_test_ref, &ref);
      +	assert_err(err);
      +
     -+	err = reftable_stack_read_ref(st, ref.ref_name, &dest);
     ++	err = reftable_stack_read_ref(st, ref.refname, &dest);
      +	assert_err(err);
      +	assert(0 == strcmp("master", dest.target));
      +
     @@ reftable/stack_test.c (new)
      +	char dir[256] = "/tmp/stack_test.XXXXXX";
      +	int err;
      +	struct reftable_ref_record ref1 = {
     -+		.ref_name = "HEAD",
     ++		.refname = "HEAD",
      +		.update_index = 1,
      +		.target = "master",
      +	};
      +	struct reftable_ref_record ref2 = {
     -+		.ref_name = "branch2",
     ++		.refname = "branch2",
      +		.update_index = 2,
      +		.target = "master",
      +	};
     @@ reftable/stack_test.c (new)
      +	struct reftable_addition *add = NULL;
      +
      +	struct reftable_ref_record ref = {
     -+		.ref_name = "HEAD",
     ++		.refname = "HEAD",
      +		.update_index = 1,
      +		.target = "master",
      +	};
     @@ reftable/stack_test.c (new)
      +
      +	reftable_addition_destroy(add);
      +
     -+	err = reftable_stack_read_ref(st, ref.ref_name, &dest);
     ++	err = reftable_stack_read_ref(st, ref.refname, &dest);
      +	assert_err(err);
      +	assert(0 == strcmp("master", dest.target));
      +
     @@ reftable/stack_test.c (new)
      +	char dir[256] = "/tmp/stack_test.XXXXXX";
      +	int i;
      +	struct reftable_ref_record ref = {
     -+		.ref_name = "a/b",
     ++		.refname = "a/b",
      +		.update_index = 1,
      +		.target = "master",
      +	};
     @@ reftable/stack_test.c (new)
      +
      +	for (i = 0; i < ARRAY_SIZE(additions); i++) {
      +		struct reftable_ref_record ref = {
     -+			.ref_name = additions[i],
     ++			.refname = additions[i],
      +			.update_index = 1,
      +			.target = "master",
      +		};
     @@ reftable/stack_test.c (new)
      +	struct reftable_stack *st = NULL;
      +	int err;
      +	struct reftable_ref_record ref1 = {
     -+		.ref_name = "name1",
     ++		.refname = "name1",
      +		.update_index = 1,
      +		.target = "master",
      +	};
      +	struct reftable_ref_record ref2 = {
     -+		.ref_name = "name2",
     ++		.refname = "name2",
      +		.update_index = 1,
      +		.target = "master",
      +	};
     @@ reftable/stack_test.c (new)
      +	for (i = 0; i < N; i++) {
      +		char buf[256];
      +		snprintf(buf, sizeof(buf), "branch%02d", i);
     -+		refs[i].ref_name = xstrdup(buf);
     ++		refs[i].refname = xstrdup(buf);
      +		refs[i].value = reftable_malloc(SHA1_SIZE);
      +		refs[i].update_index = i + 1;
      +		set_test_hash(refs[i].value, i);
      +
     -+		logs[i].ref_name = xstrdup(buf);
     ++		logs[i].refname = xstrdup(buf);
      +		logs[i].update_index = N + i + 1;
      +		logs[i].new_hash = reftable_malloc(SHA1_SIZE);
      +		logs[i].email = xstrdup("identity@invalid");
     @@ reftable/stack_test.c (new)
      +
      +	for (i = 0; i < N; i++) {
      +		struct reftable_ref_record dest = { 0 };
     -+		int err = reftable_stack_read_ref(st, refs[i].ref_name, &dest);
     ++		int err = reftable_stack_read_ref(st, refs[i].refname, &dest);
      +		assert_err(err);
      +		assert(reftable_ref_record_equal(&dest, refs + i, SHA1_SIZE));
      +		reftable_ref_record_clear(&dest);
     @@ reftable/stack_test.c (new)
      +
      +	for (i = 0; i < N; i++) {
      +		struct reftable_log_record dest = { 0 };
     -+		int err = reftable_stack_read_log(st, refs[i].ref_name, &dest);
     ++		int err = reftable_stack_read_log(st, refs[i].refname, &dest);
      +		assert_err(err);
      +		assert(reftable_log_record_equal(&dest, logs + i, SHA1_SIZE));
      +		reftable_log_record_clear(&dest);
     @@ reftable/stack_test.c (new)
      +	uint8_t h1[SHA1_SIZE] = { 0x01 }, h2[SHA1_SIZE] = { 0x02 };
      +
      +	struct reftable_log_record input = {
     -+		.ref_name = "branch",
     ++		.refname = "branch",
      +		.update_index = 1,
      +		.new_hash = h1,
      +		.old_hash = h2,
     @@ reftable/stack_test.c (new)
      +	err = reftable_stack_add(st, &write_test_log, &arg);
      +	assert_err(err);
      +
     -+	err = reftable_stack_read_log(st, input.ref_name, &dest);
     ++	err = reftable_stack_read_log(st, input.refname, &dest);
      +	assert_err(err);
      +	assert(0 == strcmp(dest.message, "one\n"));
      +
     @@ reftable/stack_test.c (new)
      +	arg.update_index = 2;
      +	err = reftable_stack_add(st, &write_test_log, &arg);
      +	assert_err(err);
     -+	err = reftable_stack_read_log(st, input.ref_name, &dest);
     ++	err = reftable_stack_read_log(st, input.refname, &dest);
      +	assert_err(err);
      +	assert(0 == strcmp(dest.message, "two\n"));
      +
     @@ reftable/stack_test.c (new)
      +
      +	for (i = 0; i < N; i++) {
      +		const char *buf = "branch";
     -+		refs[i].ref_name = xstrdup(buf);
     ++		refs[i].refname = xstrdup(buf);
      +		refs[i].update_index = i + 1;
      +		if (i % 2 == 0) {
      +			refs[i].value = reftable_malloc(SHA1_SIZE);
      +			set_test_hash(refs[i].value, i);
      +		}
     -+		logs[i].ref_name = xstrdup(buf);
     ++		logs[i].refname = xstrdup(buf);
      +		/* update_index is part of the key. */
      +		logs[i].update_index = 42;
      +		if (i % 2 == 0) {
     @@ reftable/stack_test.c (new)
      +	int err;
      +
      +	struct reftable_ref_record ref = {
     -+		.ref_name = "master",
     ++		.refname = "master",
      +		.target = "target",
      +		.update_index = 1,
      +	};
     @@ reftable/stack_test.c (new)
      +		char buf[256];
      +		snprintf(buf, sizeof(buf), "branch%02d", i);
      +
     -+		logs[i].ref_name = xstrdup(buf);
     ++		logs[i].refname = xstrdup(buf);
      +		logs[i].update_index = i;
      +		logs[i].time = i;
      +		logs[i].new_hash = reftable_malloc(SHA1_SIZE);
     @@ reftable/stack_test.c (new)
      +	err = reftable_stack_compact_all(st, &expiry);
      +	assert_err(err);
      +
     -+	err = reftable_stack_read_log(st, logs[9].ref_name, &log);
     ++	err = reftable_stack_read_log(st, logs[9].refname, &log);
      +	assert(err == 1);
      +
     -+	err = reftable_stack_read_log(st, logs[11].ref_name, &log);
     ++	err = reftable_stack_read_log(st, logs[11].refname, &log);
      +	assert_err(err);
      +
      +	expiry.min_update_index = 15;
      +	err = reftable_stack_compact_all(st, &expiry);
      +	assert_err(err);
      +
     -+	err = reftable_stack_read_log(st, logs[14].ref_name, &log);
     ++	err = reftable_stack_read_log(st, logs[14].refname, &log);
      +	assert(err == 1);
      +
     -+	err = reftable_stack_read_log(st, logs[16].ref_name, &log);
     ++	err = reftable_stack_read_log(st, logs[16].refname, &log);
      +	assert_err(err);
      +
      +	/* cleanup */
     @@ reftable/stack_test.c (new)
      +	for (i = 0; i < N; i++) {
      +		char name[100];
      +		struct reftable_ref_record ref = {
     -+			.ref_name = name,
     ++			.refname = name,
      +			.update_index = reftable_stack_next_update_index(st),
      +			.target = "master",
      +		};
     @@ reftable/strbuf.h (new)
      +  x = STRBUF_INIT;"
      + */
      +struct strbuf {
     -+	int len;
     -+	int cap;
     ++	size_t len;
     ++	size_t cap;
      +	char *buf;
      +
      +	/* Used to enforce initialization with STRBUF_INIT */
     @@ reftable/writer.c (new)
      +struct obj_index_tree_node {
      +	struct strbuf hash;
      +	uint64_t *offsets;
     -+	int offset_len;
     -+	int offset_cap;
     ++	size_t offset_len;
     ++	size_t offset_cap;
      +};
     ++
      +#define OBJ_INDEX_TREE_NODE_INIT    \
      +	{                           \
      +		.hash = STRBUF_INIT \
     @@ reftable/writer.c (new)
      +	struct reftable_ref_record copy = *ref;
      +	int err = 0;
      +
     -+	if (ref->ref_name == NULL)
     ++	if (ref->refname == NULL)
      +		return REFTABLE_API_ERROR;
      +	if (ref->update_index < w->min_update_index ||
      +	    ref->update_index > w->max_update_index)
     @@ reftable/writer.c (new)
      +	char *input_log_message = log->message;
      +	struct strbuf cleaned_message = STRBUF_INIT;
      +	int err;
     -+	if (log->ref_name == NULL)
     ++	if (log->refname == NULL)
      +		return REFTABLE_API_ERROR;
      +
      +	if (w->block_writer != NULL &&
     @@ reftable/writer.h (new)
      +
      +	/* pending index records for the current section */
      +	struct reftable_index_record *index;
     -+	int index_len;
     -+	int index_cap;
     ++	size_t index_len;
     ++	size_t index_cap;
      +
      +	/*
      +	  tree for use with tsearch; used to populate the 'o' inverse OID
 12:  c92b8d12ec = 13:  d155240b16 Add standalone build infrastructure for reftable
 13:  479fe884e9 ! 14:  073bff7279 Reftable support for git-core
     @@ Commit message
      
          For background, see the previous commit introducing the library.
      
     -    This introduces the refs/reftable-backend.c containing reftable powered ref
     -    storage backend.
     +    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".
     +    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
      
     @@ Makefile: cocciclean:
      
       ## builtin/clone.c ##
      @@ builtin/clone.c: int cmd_clone(int argc, const char **argv, const char *prefix)
     - 		}
       	}
       
     --	init_db(git_dir, real_git_dir, option_template, GIT_HASH_UNKNOWN, INIT_DB_QUIET);
     -+	init_db(git_dir, real_git_dir, option_template, GIT_HASH_UNKNOWN,
     + 	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;
     +@@ builtin/clone.c: 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 ##
      @@ builtin/init-db.c: static int needs_work_tree_config(const char *git_dir, const char *work_tree)
     @@ builtin/init-db.c: static int create_default_files(const char *template_path,
       	 * We need to create a "refs" dir in any case so that older
       	 * versions of git can tell that this is a repository.
      @@ builtin/init-db.c: static int create_default_files(const char *template_path,
     - 	 * Create the default symlink from ".git/HEAD" to the "master"
     - 	 * branch, if it does not exist yet.
     + 	 * Point the HEAD symref to the initial branch with if HEAD does
     + 	 * not yet exist.
       	 */
      -	path = git_path_buf(&buf, "HEAD");
      -	reinit = (!access(path, R_OK)
      -		  || readlink(path, junk, sizeof(junk)-1) != -1);
       	if (!reinit) {
     - 		if (create_symref("HEAD", "refs/heads/master", NULL) < 0)
     - 			exit(1);
     + 		char *ref;
     + 
     +@@ builtin/init-db.c: static int create_default_files(const char *template_path,
     + 		free(ref);
       	}
       
      -	initialize_repository_version(fmt->hash_algo);
     @@ builtin/init-db.c: static int create_default_files(const char *template_path,
       	/* Check filemode trustability */
       	path = git_path_buf(&buf, "config");
      @@ builtin/init-db.c: static void validate_hash_algorithm(struct repository_format *repo_fmt, int hash
     - }
       
       int init_db(const char *git_dir, const char *real_git_dir,
     --	    const char *template_dir, int hash, unsigned int flags)
     -+	    const char *template_dir, int hash, const char *ref_storage_format,
     -+	    unsigned int flags)
     + 	    const char *template_dir, int hash, const char *initial_branch,
     +-	    unsigned int flags)
     ++	    const char *ref_storage_format, unsigned int flags)
       {
       	int reinit;
       	int exist_ok = flags & INIT_DB_EXIST_OK;
     @@ builtin/init-db.c: static const char *const init_db_usage[] = {
       	const char *work_tree;
       	const char *template_dir = NULL;
      @@ builtin/init-db.c: int cmd_init_db(int argc, const char **argv, const char *prefix)
     - 	const char *object_format = NULL;
     + 	const char *initial_branch = NULL;
       	int hash_algo = GIT_HASH_UNKNOWN;
       	const struct option init_db_options[] = {
      -		OPT_STRING(0, "template", &template_dir, N_("template-directory"),
     @@ builtin/init-db.c: int cmd_init_db(int argc, const char **argv, const char *pref
      +			   N_("the ref storage format to use")),
       		OPT_STRING(0, "separate-git-dir", &real_git_dir, N_("gitdir"),
       			   N_("separate git dir from working tree")),
     - 		OPT_STRING(0, "object-format", &object_format, N_("hash"),
     + 		OPT_STRING('b', "initial-branch", &initial_branch, N_("name"),
      @@ builtin/init-db.c: int cmd_init_db(int argc, const char **argv, const char *prefix)
       	}
       
     @@ builtin/init-db.c: int cmd_init_db(int argc, const char **argv, const char *pref
       	UNLEAK(work_tree);
       
       	flags |= INIT_DB_EXIST_OK;
     --	return init_db(git_dir, real_git_dir, template_dir, hash_algo, flags);
     -+	return init_db(git_dir, real_git_dir, template_dir, hash_algo,
     -+		       ref_storage_format, flags);
     + 	return init_db(git_dir, real_git_dir, template_dir, hash_algo,
     +-		       initial_branch, flags);
     ++		       initial_branch, ref_storage_format, flags);
       }
      
     + ## builtin/worktree.c ##
     +@@
     + #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>]"),
     +@@ builtin/worktree.c: 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 ##
      @@ cache.h: int path_inside_repo(const char *prefix, const char *path);
     + #define INIT_DB_EXIST_OK 0x0002
       
       int init_db(const char *git_dir, const char *real_git_dir,
     - 	    const char *template_dir, int hash_algo,
     --	    unsigned int flags);
     +-	    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);
     @@ cache.h: struct repository_format {
      
       ## refs.c ##
      @@
     - #include "argv-array.h"
       #include "repository.h"
     + #include "sigchain.h"
       
      +const char *default_ref_storage(void)
      +{
     @@ 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/refs-internal.h: struct ref_storage_be {
       ## refs/reftable-backend.c (new) ##
      @@
      +#include "../cache.h"
     ++#include "../chdir-notify.h"
      +#include "../config.h"
     -+#include "../refs.h"
     -+#include "refs-internal.h"
      +#include "../iterator.h"
      +#include "../lockfile.h"
     -+#include "../chdir-notify.h"
     -+
     ++#include "../refs.h"
      +#include "../reftable/reftable.h"
     ++#include "../worktree.h"
     ++#include "refs-internal.h"
      +
      +extern struct ref_storage_be refs_be_reftable;
      +
     @@ refs/reftable-backend.c (new)
      +
      +	int err;
      +	char *repo_dir;
     ++
      +	char *reftable_dir;
     -+	struct reftable_stack *stack;
     ++	char *worktree_reftable_dir;
     ++
     ++	struct reftable_stack *main_stack;
     ++	struct reftable_stack *worktree_stack;
      +};
      +
     -+static int reftable_read_raw_ref(struct ref_store *ref_store,
     -+				 const char *refname, struct object_id *oid,
     -+				 struct strbuf *referent, unsigned int *type);
     ++static struct reftable_stack *stack_for(struct git_reftable_ref_store *store,
     ++					const char *refname)
     ++{
     ++	if (store->worktree_stack == NULL)
     ++		return store->main_stack;
     ++
     ++	switch (ref_type(refname)) {
     ++	case REF_TYPE_PER_WORKTREE:
     ++	case REF_TYPE_PSEUDOREF:
     ++	case REF_TYPE_OTHER_PSEUDOREF:
     ++		return store->worktree_stack;
     ++	default:
     ++	case REF_TYPE_MAIN_PSEUDOREF:
     ++	case REF_TYPE_NORMAL:
     ++		return store->main_stack;
     ++	}
     ++}
     ++
     ++static int git_reftable_read_raw_ref(struct ref_store *ref_store,
     ++				     const char *refname, struct object_id *oid,
     ++				     struct strbuf *referent,
     ++				     unsigned int *type);
      +
      +static void clear_reftable_log_record(struct reftable_log_record *log)
      +{
      +	log->old_hash = NULL;
      +	log->new_hash = NULL;
      +	log->message = NULL;
     -+	log->ref_name = NULL;
     ++	log->refname = NULL;
      +	reftable_log_record_clear(log);
      +}
      +
     @@ refs/reftable-backend.c (new)
      +	log->tz_offset = sign * atoi(split.tz_begin);
      +}
      +
     ++static int has_suffix(struct strbuf *b, const char *suffix)
     ++{
     ++	size_t len = strlen(suffix);
     ++
     ++	if (len > b->len) {
     ++		return 0;
     ++	}
     ++
     ++	return 0 == strncmp(b->buf + b->len - len, suffix, len);
     ++}
     ++
     ++static int trim_component(struct strbuf *b)
     ++{
     ++	char *last;
     ++	last = strrchr(b->buf, '/');
     ++	if (!last)
     ++		return -1;
     ++	strbuf_setlen(b, last - b->buf);
     ++	return 0;
     ++}
     ++
     ++static int is_worktree(struct strbuf *b)
     ++{
     ++	if (trim_component(b) < 0) {
     ++		return 0;
     ++	}
     ++	if (!has_suffix(b, "/worktrees")) {
     ++		return 0;
     ++	}
     ++	trim_component(b);
     ++	return 1;
     ++}
     ++
      +static struct ref_store *git_reftable_ref_store_create(const char *path,
      +						       unsigned int store_flags)
      +{
     @@ refs/reftable-backend.c (new)
      +		.hash_id = the_hash_algo->format_id,
      +	};
      +	struct strbuf sb = STRBUF_INIT;
     ++	const char *gitdir = path;
     ++	struct strbuf wt_buf = STRBUF_INIT;
     ++	int wt = 0;
     ++
     ++	strbuf_addstr(&wt_buf, path);
     ++
     ++	/* this is clumsy, but the official worktree functions (eg.
     ++	 * get_worktrees()) function will try to initialize a ref storage
     ++	 * backend, leading to infinite recursion.  */
     ++	wt = is_worktree(&wt_buf);
     ++	if (wt) {
     ++		gitdir = wt_buf.buf;
     ++	}
      +
      +	base_ref_store_init(ref_store, &refs_be_reftable);
      +	refs->store_flags = store_flags;
     -+	refs->repo_dir = xstrdup(path);
     -+	strbuf_addf(&sb, "%s/reftable", path);
     ++	refs->repo_dir = xstrdup(gitdir);
     ++	strbuf_addf(&sb, "%s/reftable", gitdir);
      +	refs->reftable_dir = xstrdup(sb.buf);
      +	strbuf_reset(&sb);
      +
     -+	refs->err = reftable_new_stack(&refs->stack, refs->reftable_dir, cfg);
     ++	refs->err =
     ++		reftable_new_stack(&refs->main_stack, refs->reftable_dir, cfg);
      +	assert(refs->err != REFTABLE_API_ERROR);
     ++
     ++	if (refs->err == 0 && wt) {
     ++		strbuf_addf(&sb, "%s/reftable", path);
     ++		refs->worktree_reftable_dir = xstrdup(sb.buf);
     ++
     ++		refs->err = reftable_new_stack(&refs->worktree_stack,
     ++					       refs->worktree_reftable_dir,
     ++					       cfg);
     ++		assert(refs->err != REFTABLE_API_ERROR);
     ++	}
     ++
      +	strbuf_release(&sb);
     ++	strbuf_release(&wt_buf);
      +	return ref_store;
      +}
      +
     -+static int reftable_init_db(struct ref_store *ref_store, struct strbuf *err)
     ++static int git_reftable_init_db(struct ref_store *ref_store, struct strbuf *err)
      +{
      +	struct git_reftable_ref_store *refs =
      +		(struct git_reftable_ref_store *)ref_store;
      +	struct strbuf sb = STRBUF_INIT;
      +
      +	safe_create_dir(refs->reftable_dir, 1);
     ++	assert(refs->worktree_reftable_dir == NULL);
      +
      +	strbuf_addf(&sb, "%s/HEAD", refs->repo_dir);
      +	write_file(sb.buf, "ref: refs/heads/.invalid");
     @@ refs/reftable-backend.c (new)
      +	struct reftable_ref_record ref;
      +	struct object_id oid;
      +	struct ref_store *ref_store;
     ++
     ++	/* In case we must iterate over 2 stacks, this is non-null. */
     ++	struct reftable_merged_table *merged;
      +	unsigned int flags;
      +	int err;
      +	const char *prefix;
     @@ refs/reftable-backend.c (new)
      +		   a PSEUDOREF, but a PER_WORKTREE, b/c each worktree can have
      +		   its own HEAD.
      +		 */
     -+		ri->base.refname = ri->ref.ref_name;
     ++		ri->base.refname = ri->ref.refname;
      +		if (ri->prefix != NULL &&
     -+		    strncmp(ri->prefix, ri->ref.ref_name, strlen(ri->prefix))) {
     ++		    strncmp(ri->prefix, ri->ref.refname, strlen(ri->prefix))) {
      +			ri->err = 1;
      +			break;
      +		}
     @@ refs/reftable-backend.c (new)
      +		} else if (ri->ref.target != NULL) {
      +			int out_flags = 0;
      +			const char *resolved = refs_resolve_ref_unsafe(
     -+				ri->ref_store, ri->ref.ref_name,
     ++				ri->ref_store, ri->ref.refname,
      +				RESOLVE_REF_READING, &ri->oid, &out_flags);
      +			ri->base.flags = out_flags;
      +			if (resolved == NULL &&
     @@ refs/reftable-backend.c (new)
      +		(struct git_reftable_iterator *)ref_iterator;
      +	reftable_ref_record_clear(&ri->ref);
      +	reftable_iterator_destroy(&ri->iter);
     ++	if (ri->merged) {
     ++		reftable_merged_table_free(ri->merged);
     ++	}
      +	return 0;
      +}
      +
     @@ refs/reftable-backend.c (new)
      +};
      +
      +static struct ref_iterator *
     -+reftable_ref_iterator_begin(struct ref_store *ref_store, const char *prefix,
     -+			    unsigned int flags)
     ++git_reftable_ref_iterator_begin(struct ref_store *ref_store, const char *prefix,
     ++				unsigned int flags)
      +{
      +	struct git_reftable_ref_store *refs =
      +		(struct git_reftable_ref_store *)ref_store;
      +	struct git_reftable_iterator *ri = xcalloc(1, sizeof(*ri));
     -+	struct reftable_merged_table *mt = NULL;
      +
      +	if (refs->err < 0) {
      +		ri->err = refs->err;
     -+	} else {
     -+		mt = reftable_stack_merged_table(refs->stack);
     ++	} else if (refs->worktree_stack == NULL) {
     ++		struct reftable_merged_table *mt =
     ++			reftable_stack_merged_table(refs->main_stack);
      +		ri->err = reftable_merged_table_seek_ref(mt, &ri->iter, prefix);
     ++	} else {
     ++		struct reftable_merged_table *mt1 =
     ++			reftable_stack_merged_table(refs->main_stack);
     ++		struct reftable_merged_table *mt2 =
     ++			reftable_stack_merged_table(refs->worktree_stack);
     ++		struct reftable_table *tabs =
     ++			xcalloc(2, sizeof(struct reftable_table));
     ++		reftable_table_from_merged_table(&tabs[0], mt1);
     ++		reftable_table_from_merged_table(&tabs[1], mt2);
     ++		ri->err = reftable_new_merged_table(&ri->merged, tabs, 2,
     ++						    the_hash_algo->format_id);
     ++		if (ri->err == 0)
     ++			ri->err = reftable_merged_table_seek_ref(
     ++				ri->merged, &ri->iter, prefix);
      +	}
      +
      +	base_ref_iterator_init(&ri->base, &reftable_ref_iterator_vtable, 1);
     @@ refs/reftable-backend.c (new)
      +		struct ref_update *update = transaction->updates[i];
      +		struct object_id old_oid;
      +
     -+		err = reftable_read_raw_ref(ref_store, update->refname,
     -+					    &old_oid, &referent,
     -+					    /* mutate input, like
     -+					       files-backend.c */
     -+					    &update->type);
     ++		err = git_reftable_read_raw_ref(ref_store, update->refname,
     ++						&old_oid, &referent,
     ++						/* mutate input, like
     ++						   files-backend.c */
     ++						&update->type);
      +		if (err < 0 && errno == ENOENT &&
      +		    is_null_oid(&update->old_oid)) {
      +			err = 0;
     @@ refs/reftable-backend.c (new)
      +	return err;
      +}
      +
     -+static int reftable_transaction_prepare(struct ref_store *ref_store,
     -+					struct ref_transaction *transaction,
     -+					struct strbuf *errbuf)
     ++static int git_reftable_transaction_prepare(struct ref_store *ref_store,
     ++					    struct ref_transaction *transaction,
     ++					    struct strbuf *errbuf)
      +{
      +	struct git_reftable_ref_store *refs =
      +		(struct git_reftable_ref_store *)ref_store;
      +	struct reftable_addition *add = NULL;
     ++	struct reftable_stack *stack =
     ++		transaction->nr ?
     ++			      stack_for(refs, transaction->updates[0]->refname) :
     ++			      refs->main_stack;
      +	int err = refs->err;
      +	if (err < 0) {
      +		goto done;
      +	}
      +
     -+	err = reftable_stack_reload(refs->stack);
     ++	err = reftable_stack_reload(stack);
      +	if (err) {
      +		goto done;
      +	}
      +
     -+	err = reftable_stack_new_addition(&add, refs->stack);
     ++	err = reftable_stack_new_addition(&add, stack);
      +	if (err) {
      +		goto done;
      +	}
     @@ refs/reftable-backend.c (new)
      +	return err;
      +}
      +
     -+static int reftable_transaction_abort(struct ref_store *ref_store,
     -+				      struct ref_transaction *transaction,
     -+				      struct strbuf *err)
     ++static int git_reftable_transaction_abort(struct ref_store *ref_store,
     ++					  struct ref_transaction *transaction,
     ++					  struct strbuf *err)
      +{
      +	struct reftable_addition *add =
      +		(struct reftable_addition *)transaction->backend_data;
     @@ refs/reftable-backend.c (new)
      +	struct ref_transaction *transaction = (struct ref_transaction *)arg;
      +	struct git_reftable_ref_store *refs =
      +		(struct git_reftable_ref_store *)transaction->ref_store;
     -+	uint64_t ts = reftable_stack_next_update_index(refs->stack);
     ++	struct reftable_stack *stack =
     ++		stack_for(refs, transaction->updates[0]->refname);
     ++	uint64_t ts = reftable_stack_next_update_index(stack);
      +	int err = 0;
      +	int i = 0;
      +	struct reftable_log_record *logs =
     @@ refs/reftable-backend.c (new)
      +		struct ref_update *u = sorted[i];
      +		struct reftable_log_record *log = &logs[i];
      +		fill_reftable_log_record(log);
     -+		log->ref_name = (char *)u->refname;
     ++		log->refname = (char *)u->refname;
      +		log->old_hash = u->old_oid.hash;
      +		log->new_hash = u->new_oid.hash;
      +		log->update_index = ts;
     @@ refs/reftable-backend.c (new)
      +			struct object_id peeled;
      +
      +			int peel_error = peel_object(&u->new_oid, &peeled);
     -+			ref.ref_name = (char *)u->refname;
     ++			ref.refname = (char *)u->refname;
      +
      +			if (!is_null_oid(&u->new_oid)) {
      +				ref.value = u->new_oid.hash;
     @@ refs/reftable-backend.c (new)
      +	return err;
      +}
      +
     -+static int reftable_transaction_finish(struct ref_store *ref_store,
     -+				       struct ref_transaction *transaction,
     -+				       struct strbuf *errmsg)
     ++static int git_reftable_transaction_finish(struct ref_store *ref_store,
     ++					   struct ref_transaction *transaction,
     ++					   struct strbuf *errmsg)
      +{
      +	struct reftable_addition *add =
      +		(struct reftable_addition *)transaction->backend_data;
     @@ refs/reftable-backend.c (new)
      +			}
      +		}
      +	}
     -+
     -+	err = reftable_addition_add(add, &write_transaction_table, transaction);
     -+	if (err < 0) {
     -+		goto done;
     ++	if (transaction->nr) {
     ++		err = reftable_addition_add(add, &write_transaction_table,
     ++					    transaction);
     ++		if (err < 0) {
     ++			goto done;
     ++		}
      +	}
      +
      +	err = reftable_addition_commit(add);
     @@ refs/reftable-backend.c (new)
      +}
      +
      +static int
     -+reftable_transaction_initial_commit(struct ref_store *ref_store,
     -+				    struct ref_transaction *transaction,
     -+				    struct strbuf *errmsg)
     ++git_reftable_transaction_initial_commit(struct ref_store *ref_store,
     ++					struct ref_transaction *transaction,
     ++					struct strbuf *errmsg)
      +{
     -+	int err = reftable_transaction_prepare(ref_store, transaction, errmsg);
     ++	int err = git_reftable_transaction_prepare(ref_store, transaction,
     ++						   errmsg);
      +	if (err)
      +		return err;
      +
     -+	return reftable_transaction_finish(ref_store, transaction, errmsg);
     ++	return git_reftable_transaction_finish(ref_store, transaction, errmsg);
      +}
      +
      +struct write_pseudoref_arg {
     @@ refs/reftable-backend.c (new)
      +		}
      +	}
      +
     -+	write_ref.ref_name = (char *)arg->pseudoref;
     ++	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;
     @@ refs/reftable-backend.c (new)
      +	return err;
      +}
      +
     -+static int 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)
     ++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 = refs->stack,
     ++		.stack = stack,
      +		.pseudoref = pseudoref,
      +		.new_oid = oid,
      +	};
     @@ refs/reftable-backend.c (new)
      +		goto done;
      +	}
      +
     -+	err = reftable_stack_reload(refs->stack);
     ++	err = reftable_stack_reload(stack);
      +	if (err) {
      +		goto done;
      +	}
     -+	err = reftable_stack_new_addition(&add, refs->stack);
     ++	err = reftable_stack_new_addition(&add, stack);
      +	if (err) {
      +		goto done;
      +	}
     @@ refs/reftable-backend.c (new)
      +				     const struct object_id *old_oid)
      +{
      +	struct strbuf errbuf = STRBUF_INIT;
     -+	int ret = reftable_write_pseudoref(ref_store, pseudoref, &null_oid,
     -+					   old_oid, &errbuf);
     ++	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;
     @@ refs/reftable-backend.c (new)
      +	reftable_writer_set_limits(writer, ts, ts);
      +	for (i = 0; i < arg->refnames->nr; i++) {
      +		struct reftable_ref_record ref = {
     -+			.ref_name = (char *)arg->refnames->items[i].string,
     ++			.refname = (char *)arg->refnames->items[i].string,
      +			.update_index = ts,
      +		};
      +		err = reftable_writer_add_ref(writer, &ref);
     @@ refs/reftable-backend.c (new)
      +		log.new_hash = NULL;
      +		log.old_hash = NULL;
      +		log.update_index = ts;
     -+		log.ref_name = (char *)arg->refnames->items[i].string;
     ++		log.refname = (char *)arg->refnames->items[i].string;
      +
     -+		if (reftable_stack_read_ref(arg->stack, log.ref_name,
     ++		if (reftable_stack_read_ref(arg->stack, log.refname,
      +					    &current) == 0) {
      +			log.old_hash = current.value;
      +		}
     @@ refs/reftable-backend.c (new)
      +	return 0;
      +}
      +
     -+static int reftable_delete_refs(struct ref_store *ref_store, const char *msg,
     -+				struct string_list *refnames,
     -+				unsigned int flags)
     ++static int git_reftable_delete_refs(struct ref_store *ref_store,
     ++				    const char *msg,
     ++				    struct string_list *refnames,
     ++				    unsigned int flags)
      +{
      +	struct git_reftable_ref_store *refs =
      +		(struct git_reftable_ref_store *)ref_store;
     ++	struct reftable_stack *stack =
     ++		stack_for(refs, refnames->items[0].string);
      +	struct write_delete_refs_arg arg = {
     -+		.stack = refs->stack,
     ++		.stack = stack,
      +		.refnames = refnames,
      +		.logmsg = msg,
      +		.flags = flags,
     @@ refs/reftable-backend.c (new)
      +	}
      +
      +	string_list_sort(refnames);
     -+	err = reftable_stack_reload(refs->stack);
     ++	err = reftable_stack_reload(stack);
      +	if (err) {
      +		goto done;
      +	}
     -+	err = reftable_stack_add(refs->stack, &write_delete_refs_table, &arg);
     ++	err = reftable_stack_add(stack, &write_delete_refs_table, &arg);
      +done:
      +	assert(err != REFTABLE_API_ERROR);
      +	return err;
      +}
      +
     -+static int reftable_pack_refs(struct ref_store *ref_store, unsigned int flags)
     ++static int git_reftable_pack_refs(struct ref_store *ref_store,
     ++				  unsigned int flags)
      +{
      +	struct git_reftable_ref_store *refs =
      +		(struct git_reftable_ref_store *)ref_store;
     -+	if (refs->err < 0) {
     -+		return refs->err;
     ++	int err = refs->err;
     ++	if (err < 0) {
     ++		return err;
      +	}
     -+	return reftable_stack_compact_all(refs->stack, NULL);
     ++	err = reftable_stack_compact_all(refs->main_stack, NULL);
     ++	if (err == 0 && refs->worktree_stack != NULL)
     ++		err = reftable_stack_compact_all(refs->worktree_stack, NULL);
     ++	return err;
      +}
      +
      +struct write_create_symref_arg {
      +	struct git_reftable_ref_store *refs;
     ++	struct reftable_stack *stack;
      +	const char *refname;
      +	const char *target;
      +	const char *logmsg;
     @@ refs/reftable-backend.c (new)
      +{
      +	struct write_create_symref_arg *create =
      +		(struct write_create_symref_arg *)arg;
     -+	uint64_t ts = reftable_stack_next_update_index(create->refs->stack);
     ++	uint64_t ts = reftable_stack_next_update_index(create->stack);
      +	int err = 0;
      +
      +	struct reftable_ref_record ref = {
     -+		.ref_name = (char *)create->refname,
     ++		.refname = (char *)create->refname,
      +		.target = (char *)create->target,
      +		.update_index = ts,
      +	};
     @@ refs/reftable-backend.c (new)
      +		struct object_id old_oid;
      +
      +		fill_reftable_log_record(&log);
     -+		log.ref_name = (char *)create->refname;
     ++		log.refname = (char *)create->refname;
      +		log.message = (char *)create->logmsg;
      +		log.update_index = ts;
      +		if (refs_resolve_ref_unsafe(
     @@ refs/reftable-backend.c (new)
      +		if (log.old_hash != NULL || log.new_hash != NULL) {
      +			err = reftable_writer_add_log(writer, &log);
      +		}
     -+		log.ref_name = NULL;
     ++		log.refname = NULL;
      +		log.message = NULL;
      +		log.old_hash = NULL;
      +		log.new_hash = NULL;
     @@ refs/reftable-backend.c (new)
      +	return err;
      +}
      +
     -+static int reftable_create_symref(struct ref_store *ref_store,
     -+				  const char *refname, const char *target,
     -+				  const char *logmsg)
     ++static int git_reftable_create_symref(struct ref_store *ref_store,
     ++				      const char *refname, const char *target,
     ++				      const char *logmsg)
      +{
      +	struct git_reftable_ref_store *refs =
      +		(struct git_reftable_ref_store *)ref_store;
     ++	struct reftable_stack *stack = stack_for(refs, refname);
      +	struct write_create_symref_arg arg = { .refs = refs,
     ++					       .stack = stack,
      +					       .refname = refname,
      +					       .target = target,
      +					       .logmsg = logmsg };
     @@ refs/reftable-backend.c (new)
      +	if (err < 0) {
      +		goto done;
      +	}
     -+	err = reftable_stack_reload(refs->stack);
     ++	err = reftable_stack_reload(stack);
      +	if (err) {
      +		goto done;
      +	}
     -+	err = reftable_stack_add(refs->stack, &write_create_symref_table, &arg);
     ++	err = reftable_stack_add(stack, &write_create_symref_table, &arg);
      +done:
      +	assert(err != REFTABLE_API_ERROR);
      +	return err;
     @@ refs/reftable-backend.c (new)
      +		goto done;
      +	}
      +
     -+	free(ref.ref_name);
     -+	ref.ref_name = strdup(arg->newname);
     ++	free(ref.refname);
     ++	ref.refname = strdup(arg->newname);
      +	reftable_writer_set_limits(writer, ts, ts);
      +	ref.update_index = ts;
      +
      +	{
      +		struct reftable_ref_record todo[2] = { { NULL } };
     -+		todo[0].ref_name = (char *)arg->oldname;
     ++		todo[0].refname = (char *)arg->oldname;
      +		todo[0].update_index = ts;
      +		/* leave todo[0] empty */
      +		todo[1] = ref;
     @@ refs/reftable-backend.c (new)
      +		fill_reftable_log_record(&todo[0]);
      +		fill_reftable_log_record(&todo[1]);
      +
     -+		todo[0].ref_name = (char *)arg->oldname;
     ++		todo[0].refname = (char *)arg->oldname;
      +		todo[0].update_index = ts;
      +		todo[0].message = (char *)arg->logmsg;
      +		todo[0].old_hash = ref.value;
      +		todo[0].new_hash = NULL;
      +
     -+		todo[1].ref_name = (char *)arg->newname;
     ++		todo[1].refname = (char *)arg->newname;
      +		todo[1].update_index = ts;
      +		todo[1].old_hash = NULL;
      +		todo[1].new_hash = ref.value;
     @@ refs/reftable-backend.c (new)
      +	return err;
      +}
      +
     -+static int reftable_rename_ref(struct ref_store *ref_store,
     -+			       const char *oldrefname, const char *newrefname,
     -+			       const char *logmsg)
     ++static int git_reftable_rename_ref(struct ref_store *ref_store,
     ++				   const char *oldrefname,
     ++				   const char *newrefname, const char *logmsg)
      +{
      +	struct git_reftable_ref_store *refs =
      +		(struct git_reftable_ref_store *)ref_store;
     ++	struct reftable_stack *stack = stack_for(refs, newrefname);
      +	struct write_rename_arg arg = {
     -+		.stack = refs->stack,
     ++		.stack = stack,
      +		.oldname = oldrefname,
      +		.newname = newrefname,
      +		.logmsg = logmsg,
     @@ refs/reftable-backend.c (new)
      +	if (err < 0) {
      +		goto done;
      +	}
     -+	err = reftable_stack_reload(refs->stack);
     ++	err = reftable_stack_reload(stack);
      +	if (err) {
      +		goto done;
      +	}
      +
     -+	err = reftable_stack_add(refs->stack, &write_rename_table, &arg);
     ++	err = reftable_stack_add(stack, &write_rename_table, &arg);
      +done:
      +	assert(err != REFTABLE_API_ERROR);
      +	return err;
      +}
      +
     -+static int reftable_copy_ref(struct ref_store *ref_store,
     -+			     const char *oldrefname, const char *newrefname,
     -+			     const char *logmsg)
     ++static int git_reftable_copy_ref(struct ref_store *ref_store,
     ++				 const char *oldrefname, const char *newrefname,
     ++				 const char *logmsg)
      +{
      +	BUG("reftable reference store does not support copying references");
      +}
      +
     -+struct reftable_reflog_ref_iterator {
     ++struct git_reftable_reflog_ref_iterator {
      +	struct ref_iterator base;
      +	struct reftable_iterator iter;
      +	struct reftable_log_record log;
      +	struct object_id oid;
     ++
     ++	/* Used when iterating over worktree & main */
     ++	struct reftable_merged_table *merged;
      +	char *last_name;
      +};
      +
      +static int
     -+reftable_reflog_ref_iterator_advance(struct ref_iterator *ref_iterator)
     ++git_reftable_reflog_ref_iterator_advance(struct ref_iterator *ref_iterator)
      +{
     -+	struct reftable_reflog_ref_iterator *ri =
     -+		(struct reftable_reflog_ref_iterator *)ref_iterator;
     ++	struct git_reftable_reflog_ref_iterator *ri =
     ++		(struct git_reftable_reflog_ref_iterator *)ref_iterator;
      +
      +	while (1) {
      +		int err = reftable_iterator_next_log(&ri->iter, &ri->log);
     @@ refs/reftable-backend.c (new)
      +			return ITER_ERROR;
      +		}
      +
     -+		ri->base.refname = ri->log.ref_name;
     ++		ri->base.refname = ri->log.refname;
      +		if (ri->last_name != NULL &&
     -+		    !strcmp(ri->log.ref_name, ri->last_name)) {
     ++		    !strcmp(ri->log.refname, ri->last_name)) {
      +			/* we want the refnames that we have reflogs for, so we
      +			 * skip if we've already produced this name. This could
      +			 * be faster by seeking directly to
     @@ refs/reftable-backend.c (new)
      +		}
      +
      +		free(ri->last_name);
     -+		ri->last_name = xstrdup(ri->log.ref_name);
     ++		ri->last_name = xstrdup(ri->log.refname);
      +		hashcpy(ri->oid.hash, ri->log.new_hash);
      +		return ITER_OK;
      +	}
      +}
      +
     -+static int reftable_reflog_ref_iterator_peel(struct ref_iterator *ref_iterator,
     -+					     struct object_id *peeled)
     ++static int
     ++git_reftable_reflog_ref_iterator_peel(struct ref_iterator *ref_iterator,
     ++				      struct object_id *peeled)
      +{
      +	BUG("not supported.");
      +	return -1;
      +}
      +
     -+static int reftable_reflog_ref_iterator_abort(struct ref_iterator *ref_iterator)
     ++static int
     ++git_reftable_reflog_ref_iterator_abort(struct ref_iterator *ref_iterator)
      +{
     -+	struct reftable_reflog_ref_iterator *ri =
     -+		(struct reftable_reflog_ref_iterator *)ref_iterator;
     ++	struct git_reftable_reflog_ref_iterator *ri =
     ++		(struct git_reftable_reflog_ref_iterator *)ref_iterator;
      +	reftable_log_record_clear(&ri->log);
      +	reftable_iterator_destroy(&ri->iter);
     ++	if (ri->merged)
     ++		reftable_merged_table_free(ri->merged);
      +	return 0;
      +}
      +
     -+static struct ref_iterator_vtable reftable_reflog_ref_iterator_vtable = {
     -+	reftable_reflog_ref_iterator_advance, reftable_reflog_ref_iterator_peel,
     -+	reftable_reflog_ref_iterator_abort
     ++static struct ref_iterator_vtable git_reftable_reflog_ref_iterator_vtable = {
     ++	git_reftable_reflog_ref_iterator_advance,
     ++	git_reftable_reflog_ref_iterator_peel,
     ++	git_reftable_reflog_ref_iterator_abort
      +};
      +
      +static struct ref_iterator *
     -+reftable_reflog_iterator_begin(struct ref_store *ref_store)
     ++git_reftable_reflog_iterator_begin(struct ref_store *ref_store)
      +{
     -+	struct reftable_reflog_ref_iterator *ri = xcalloc(sizeof(*ri), 1);
     ++	struct git_reftable_reflog_ref_iterator *ri = xcalloc(sizeof(*ri), 1);
      +	struct git_reftable_ref_store *refs =
      +		(struct git_reftable_ref_store *)ref_store;
      +
     -+	struct reftable_merged_table *mt =
     -+		reftable_stack_merged_table(refs->stack);
     -+	int err = reftable_merged_table_seek_log(mt, &ri->iter, "");
     -+	if (err < 0) {
     -+		free(ri);
     -+		return NULL;
     ++	if (refs->worktree_stack == NULL) {
     ++		struct reftable_stack *stack = refs->main_stack;
     ++		struct reftable_merged_table *mt =
     ++			reftable_stack_merged_table(stack);
     ++		int err = reftable_merged_table_seek_log(mt, &ri->iter, "");
     ++		if (err < 0) {
     ++			free(ri);
     ++			/* XXX is this allowed? */
     ++			return NULL;
     ++		}
     ++	} else {
     ++		struct reftable_merged_table *mt1 =
     ++			reftable_stack_merged_table(refs->main_stack);
     ++		struct reftable_merged_table *mt2 =
     ++			reftable_stack_merged_table(refs->worktree_stack);
     ++		struct reftable_table *tabs =
     ++			xcalloc(2, sizeof(struct reftable_table));
     ++		int err = 0;
     ++		reftable_table_from_merged_table(&tabs[0], mt1);
     ++		reftable_table_from_merged_table(&tabs[1], mt2);
     ++		err = reftable_new_merged_table(&ri->merged, tabs, 2,
     ++						the_hash_algo->format_id);
     ++		if (err < 0) {
     ++			free(tabs);
     ++			/* XXX see above */
     ++			return NULL;
     ++		}
     ++		err = reftable_merged_table_seek_ref(ri->merged, &ri->iter, "");
     ++		if (err < 0) {
     ++			return NULL;
     ++		}
      +	}
     -+
     -+	base_ref_iterator_init(&ri->base, &reftable_reflog_ref_iterator_vtable,
     -+			       1);
     ++	base_ref_iterator_init(&ri->base,
     ++			       &git_reftable_reflog_ref_iterator_vtable, 1);
      +	ri->base.oid = &ri->oid;
      +
      +	return (struct ref_iterator *)ri;
      +}
      +
     -+static int
     -+reftable_for_each_reflog_ent_newest_first(struct ref_store *ref_store,
     -+					  const char *refname,
     -+					  each_reflog_ent_fn fn, void *cb_data)
     ++static int git_reftable_for_each_reflog_ent_newest_first(
     ++	struct ref_store *ref_store, const char *refname, each_reflog_ent_fn fn,
     ++	void *cb_data)
      +{
      +	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 = NULL;
      +	int err = 0;
      +	struct reftable_log_record log = { NULL };
     @@ refs/reftable-backend.c (new)
      +		return refs->err;
      +	}
      +
     -+	mt = reftable_stack_merged_table(refs->stack);
     ++	mt = reftable_stack_merged_table(stack);
      +	err = reftable_merged_table_seek_log(mt, &it, refname);
      +	while (err == 0) {
      +		struct object_id old_oid;
     @@ refs/reftable-backend.c (new)
      +			break;
      +		}
      +
     -+		if (strcmp(log.ref_name, refname)) {
     ++		if (strcmp(log.refname, refname)) {
      +			break;
      +		}
      +
     @@ refs/reftable-backend.c (new)
      +	return err;
      +}
      +
     -+static int
     -+reftable_for_each_reflog_ent_oldest_first(struct ref_store *ref_store,
     -+					  const char *refname,
     -+					  each_reflog_ent_fn fn, void *cb_data)
     ++static int git_reftable_for_each_reflog_ent_oldest_first(
     ++	struct ref_store *ref_store, const char *refname, each_reflog_ent_fn fn,
     ++	void *cb_data)
      +{
      +	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 = NULL;
      +	struct reftable_log_record *logs = NULL;
      +	int cap = 0;
     @@ refs/reftable-backend.c (new)
      +	if (refs->err < 0) {
      +		return refs->err;
      +	}
     -+	mt = reftable_stack_merged_table(refs->stack);
     ++	mt = reftable_stack_merged_table(stack);
      +	err = reftable_merged_table_seek_log(mt, &it, refname);
      +
      +	while (err == 0) {
     @@ refs/reftable-backend.c (new)
      +			break;
      +		}
      +
     -+		if (strcmp(log.ref_name, refname)) {
     ++		if (strcmp(log.refname, refname)) {
      +			break;
      +		}
      +
     @@ refs/reftable-backend.c (new)
      +	return err;
      +}
      +
     -+static int reftable_reflog_exists(struct ref_store *ref_store,
     -+				  const char *refname)
     ++static int git_reftable_reflog_exists(struct ref_store *ref_store,
     ++				      const char *refname)
      +{
      +	/* always exists. */
      +	return 1;
      +}
      +
     -+static int reftable_create_reflog(struct ref_store *ref_store,
     -+				  const char *refname, int force_create,
     -+				  struct strbuf *err)
     ++static int git_reftable_create_reflog(struct ref_store *ref_store,
     ++				      const char *refname, int force_create,
     ++				      struct strbuf *err)
      +{
      +	return 0;
      +}
      +
     -+static int reftable_delete_reflog(struct ref_store *ref_store,
     -+				  const char *refname)
     ++static int git_reftable_delete_reflog(struct ref_store *ref_store,
     ++				      const char *refname)
      +{
      +	return 0;
      +}
      +
      +struct reflog_expiry_arg {
      +	struct git_reftable_ref_store *refs;
     ++	struct reftable_stack *stack;
      +	struct reftable_log_record *tombstones;
      +	int len;
      +	int cap;
     @@ refs/reftable-backend.c (new)
      +			      const char *refname, uint64_t ts)
      +{
      +	struct reftable_log_record tombstone = {
     -+		.ref_name = xstrdup(refname),
     ++		.refname = xstrdup(refname),
      +		.update_index = ts,
      +	};
      +	if (arg->len == arg->cap) {
     @@ refs/reftable-backend.c (new)
      +static int write_reflog_expiry_table(struct reftable_writer *writer, void *argv)
      +{
      +	struct reflog_expiry_arg *arg = (struct reflog_expiry_arg *)argv;
     -+	uint64_t ts = reftable_stack_next_update_index(arg->refs->stack);
     ++	uint64_t ts = reftable_stack_next_update_index(arg->stack);
      +	int i = 0;
      +	reftable_writer_set_limits(writer, ts, ts);
      +	for (i = 0; i < arg->len; i++) {
     @@ refs/reftable-backend.c (new)
      +	return 0;
      +}
      +
     -+static int reftable_reflog_expire(struct ref_store *ref_store,
     -+				  const char *refname,
     -+				  const struct object_id *oid,
     -+				  unsigned int flags,
     -+				  reflog_expiry_prepare_fn prepare_fn,
     -+				  reflog_expiry_should_prune_fn should_prune_fn,
     -+				  reflog_expiry_cleanup_fn cleanup_fn,
     -+				  void *policy_cb_data)
     ++static int
     ++git_reftable_reflog_expire(struct ref_store *ref_store, const char *refname,
     ++			   const struct object_id *oid, unsigned int flags,
     ++			   reflog_expiry_prepare_fn prepare_fn,
     ++			   reflog_expiry_should_prune_fn should_prune_fn,
     ++			   reflog_expiry_cleanup_fn cleanup_fn,
     ++			   void *policy_cb_data)
      +{
      +	/*
      +	  For log expiry, we write tombstones in place of the expired entries,
     @@ refs/reftable-backend.c (new)
      +	  stack, and expiring entries paradoxically takes extra memory.
      +
      +	  This memory is only reclaimed when some operation issues a
     -+	  reftable_pack_refs(), which will compact the entire stack and get rid
     -+	  of deletion entries.
     ++	  git_reftable_pack_refs(), which will compact the entire stack and get
     ++	  rid of deletion entries.
      +
      +	  It would be better if the refs backend supported an API that sets a
      +	  criterion for all refs, passing the criterion to pack_refs().
      +	*/
      +	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 = NULL;
      +	struct reflog_expiry_arg arg = {
     ++		.stack = stack,
      +		.refs = refs,
      +	};
      +	struct reftable_log_record log = { NULL };
     @@ refs/reftable-backend.c (new)
      +	if (refs->err < 0) {
      +		return refs->err;
      +	}
     -+	err = reftable_stack_reload(refs->stack);
     ++	err = reftable_stack_reload(stack);
      +	if (err) {
      +		goto done;
      +	}
      +
     -+	mt = reftable_stack_merged_table(refs->stack);
     ++	mt = reftable_stack_merged_table(stack);
      +	err = reftable_merged_table_seek_log(mt, &it, refname);
      +	if (err < 0) {
      +		goto done;
     @@ refs/reftable-backend.c (new)
      +			goto done;
      +		}
      +
     -+		if (err > 0 || strcmp(log.ref_name, refname)) {
     ++		if (err > 0 || strcmp(log.refname, refname)) {
      +			break;
      +		}
      +		hashcpy(ooid.hash, log.old_hash);
     @@ refs/reftable-backend.c (new)
      +			add_log_tombstone(&arg, refname, log.update_index);
      +		}
      +	}
     -+	err = reftable_stack_add(refs->stack, &write_reflog_expiry_table, &arg);
     ++	err = reftable_stack_add(stack, &write_reflog_expiry_table, &arg);
      +
      +done:
      +	assert(err != REFTABLE_API_ERROR);
     @@ refs/reftable-backend.c (new)
      +	return err;
      +}
      +
     -+static int reftable_read_raw_ref(struct ref_store *ref_store,
     -+				 const char *refname, struct object_id *oid,
     -+				 struct strbuf *referent, unsigned int *type)
     ++static int git_reftable_read_raw_ref(struct ref_store *ref_store,
     ++				     const char *refname, struct object_id *oid,
     ++				     struct strbuf *referent,
     ++				     unsigned int *type)
      +{
      +	struct git_reftable_ref_store *refs =
      +		(struct git_reftable_ref_store *)ref_store;
     ++	struct reftable_stack *stack = stack_for(refs, refname);
     ++
      +	struct reftable_ref_record ref = { NULL };
      +	int err = 0;
      +	if (refs->err < 0) {
     @@ refs/reftable-backend.c (new)
      +	/* This is usually not needed, but Git doesn't signal to ref backend if
      +	   a subprocess updated the ref DB.  So we always check.
      +	*/
     -+	err = reftable_stack_reload(refs->stack);
     ++	err = reftable_stack_reload(stack);
      +	if (err) {
      +		goto done;
      +	}
      +
     -+	err = reftable_stack_read_ref(refs->stack, refname, &ref);
     ++	err = reftable_stack_read_ref(stack, refname, &ref);
      +	if (err > 0) {
      +		errno = ENOENT;
      +		err = -1;
     @@ refs/reftable-backend.c (new)
      +	&refs_be_files,
      +	"reftable",
      +	git_reftable_ref_store_create,
     -+	reftable_init_db,
     -+	reftable_transaction_prepare,
     -+	reftable_transaction_finish,
     -+	reftable_transaction_abort,
     -+	reftable_transaction_initial_commit,
     -+
     -+	reftable_pack_refs,
     -+	reftable_create_symref,
     -+	reftable_delete_refs,
     -+	reftable_rename_ref,
     -+	reftable_copy_ref,
     -+
     -+	reftable_write_pseudoref,
     ++	git_reftable_init_db,
     ++	git_reftable_transaction_prepare,
     ++	git_reftable_transaction_finish,
     ++	git_reftable_transaction_abort,
     ++	git_reftable_transaction_initial_commit,
     ++
     ++	git_reftable_pack_refs,
     ++	git_reftable_create_symref,
     ++	git_reftable_delete_refs,
     ++	git_reftable_rename_ref,
     ++	git_reftable_copy_ref,
     ++
     ++	git_reftable_write_pseudoref,
      +	reftable_delete_pseudoref,
      +
     -+	reftable_ref_iterator_begin,
     -+	reftable_read_raw_ref,
     ++	git_reftable_ref_iterator_begin,
     ++	git_reftable_read_raw_ref,
      +
     -+	reftable_reflog_iterator_begin,
     -+	reftable_for_each_reflog_ent_oldest_first,
     -+	reftable_for_each_reflog_ent_newest_first,
     -+	reftable_reflog_exists,
     -+	reftable_create_reflog,
     -+	reftable_delete_reflog,
     -+	reftable_reflog_expire,
     ++	git_reftable_reflog_iterator_begin,
     ++	git_reftable_for_each_reflog_ent_oldest_first,
     ++	git_reftable_for_each_reflog_ent_newest_first,
     ++	git_reftable_reflog_exists,
     ++	git_reftable_create_reflog,
     ++	git_reftable_delete_reflog,
     ++	git_reftable_reflog_expire,
      +};
      
       ## reftable/update.sh ##
     @@ t/t0031-reftable.sh (new)
      +	test -f file2
      +'
      +
     ++test_expect_success 'worktrees' '
     ++	git init --ref-storage=reftable start &&
     ++	(cd start && test_commit file1 && git checkout -b branch1 &&
     ++	git checkout -b branch2 &&
     ++	git worktree add  ../wt
     ++	) &&
     ++	cd wt &&
     ++	git checkout branch1 &&
     ++	git branch
     ++'
     ++
     ++test_expect_success 'worktrees 2' '
     ++	initialize &&
     ++	test_commit file1 &&
     ++	mkdir existing_empty &&
     ++	git worktree add --detach existing_empty master
     ++'
     ++
      +test_done
      +
 14:  eafd8eeefc = 15:  04c86e7395 Hookup unittests for the reftable library.
 15:  46af142f33 ! 16:  c751265705 Add GIT_DEBUG_REFS debugging mechanism
     @@ Makefile: LIB_OBJS += rebase.o
       LIB_OBJS += refs/reftable-backend.o
       LIB_OBJS += refs/iterator.o
      
     + ## builtin/worktree.c ##
     +@@ builtin/worktree.c: 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) {
     ++
     ++	/* 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) {
     + 		/* 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: 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->refs_private);
     ++		r->refs_private = debug_wrap(r->gitdir, r->refs_private);
      +	}
       	return r->refs_private;
       }
     @@ refs/debug.c (new)
      +};
      +
      +extern struct ref_storage_be refs_be_debug;
     -+struct ref_store *debug_wrap(struct ref_store *store);
     ++struct ref_store *debug_wrap(const char *gitdir, struct ref_store *store);
      +
     -+struct ref_store *debug_wrap(struct ref_store *store)
     ++struct ref_store *debug_wrap(const char *gitdir, struct ref_store *store)
      +{
      +	struct debug_ref_store *res = malloc(sizeof(struct debug_ref_store));
     ++	fprintf(stderr, "ref_store for %s\n", gitdir);
      +	res->refs = store;
      +	base_ref_store_init((struct ref_store *)res, &refs_be_debug);
      +	return (struct ref_store *)res;
     @@ refs/debug.c (new)
      +	struct debug_ref_iterator *diter =
      +		(struct debug_ref_iterator *)ref_iterator;
      +	int res = diter->iter->vtable->advance(diter->iter);
     -+	fprintf(stderr, "iterator_advance: %s: %d\n", diter->iter->refname,
     -+		res);
     ++	if (res)
     ++		fprintf(stderr, "iterator_advance: %d\n", res);
     ++	else
     ++		fprintf(stderr, "iterator_advance before: %s\n",
     ++			diter->iter->refname);
     ++
      +	diter->base.ordered = diter->iter->ordered;
      +	diter->base.refname = diter->iter->refname;
      +	diter->base.oid = diter->iter->oid;
     @@ refs/refs-internal.h: struct ref_store {
      + * Print out ref operations as they occur. Useful for debugging alternate ref
      + * backends.
      + */
     -+struct ref_store *debug_wrap(struct ref_store *store);
     ++struct ref_store *debug_wrap(const char *gitdir, struct ref_store *store);
      +
       #endif /* REFS_REFS_INTERNAL_H */
      
 16:  5211c64310 = 17:  ef0dd45f07 vcxproj: adjust for the reftable changes
 17:  9724854088 = 18:  d4dc1deae5 git-prompt: prepare for reftable refs backend
 18:  ece1fa1f62 = 19:  5a85abf9c4 Add reftable testing infrastructure
 19:  991abf9e1b = 20:  0ebf7beb95 Add "test-tool dump-reftable" command.

-- 
gitgitgadget