From: "Han-Wen Nienhuys via GitGitGadget" <gitgitgadget@gmail.com>
To: git@vger.kernel.org
Cc: Han-Wen Nienhuys <hanwenn@gmail.com>
Subject: [PATCH v3 0/6] Reftable support git-core
Date: Tue, 04 Feb 2020 20:27:34 +0000 [thread overview]
Message-ID: <pull.539.v3.git.1580848060.gitgitgadget@gmail.com> (raw)
In-Reply-To: <pull.539.v2.git.1580134944.gitgitgadget@gmail.com>
This adds the reftable library, and hooks it up as a ref backend.
At this point, I am mainly interested in feedback on the spots marked with
XXX in the Git source code, in particular, how to handle reflog expiry in
this backend.
v2
* address Jun's nits.
* address Dscho's portability comments
* more background in commit messages.
Han-Wen Nienhuys (6):
refs.h: clarify reflog iteration order
setup.c: enable repo detection for reftable
create .git/refs in files-backend.c
refs: document how ref_iterator_advance_fn should handle symrefs
Add reftable library
Reftable support for git-core
Makefile | 24 +-
builtin/init-db.c | 42 +-
cache.h | 2 +
refs.c | 22 +-
refs.h | 5 +-
refs/files-backend.c | 5 +
refs/refs-internal.h | 6 +
refs/reftable-backend.c | 880 +++++++++++++++++++++++++++++++
reftable/LICENSE | 31 ++
reftable/README.md | 19 +
reftable/VERSION | 5 +
reftable/basics.c | 196 +++++++
reftable/basics.h | 37 ++
reftable/block.c | 401 ++++++++++++++
reftable/block.h | 71 +++
reftable/blocksource.h | 20 +
reftable/bytes.c | 0
reftable/config.h | 1 +
reftable/constants.h | 27 +
reftable/dump.c | 97 ++++
reftable/file.c | 97 ++++
reftable/iter.c | 229 ++++++++
reftable/iter.h | 56 ++
reftable/merged.c | 286 ++++++++++
reftable/merged.h | 34 ++
reftable/pq.c | 114 ++++
reftable/pq.h | 34 ++
reftable/reader.c | 708 +++++++++++++++++++++++++
reftable/reader.h | 52 ++
reftable/record.c | 1107 +++++++++++++++++++++++++++++++++++++++
reftable/record.h | 79 +++
reftable/reftable.h | 399 ++++++++++++++
reftable/slice.c | 199 +++++++
reftable/slice.h | 39 ++
reftable/stack.c | 983 ++++++++++++++++++++++++++++++++++
reftable/stack.h | 40 ++
reftable/system.h | 57 ++
reftable/tree.c | 66 +++
reftable/tree.h | 24 +
reftable/writer.c | 622 ++++++++++++++++++++++
reftable/writer.h | 46 ++
reftable/zlib-compat.c | 92 ++++
repository.c | 4 +
repository.h | 3 +
setup.c | 27 +-
45 files changed, 7255 insertions(+), 33 deletions(-)
create mode 100644 refs/reftable-backend.c
create mode 100644 reftable/LICENSE
create mode 100644 reftable/README.md
create mode 100644 reftable/VERSION
create mode 100644 reftable/basics.c
create mode 100644 reftable/basics.h
create mode 100644 reftable/block.c
create mode 100644 reftable/block.h
create mode 100644 reftable/blocksource.h
create mode 100644 reftable/bytes.c
create mode 100644 reftable/config.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/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/reftable.h
create mode 100644 reftable/slice.c
create mode 100644 reftable/slice.h
create mode 100644 reftable/stack.c
create mode 100644 reftable/stack.h
create mode 100644 reftable/system.h
create mode 100644 reftable/tree.c
create mode 100644 reftable/tree.h
create mode 100644 reftable/writer.c
create mode 100644 reftable/writer.h
create mode 100644 reftable/zlib-compat.c
base-commit: 5b0ca878e008e82f91300091e793427205ce3544
Published-As: https://github.com/gitgitgadget/git/releases/tag/pr-539%2Fhanwen%2Freftable-v3
Fetch-It-Via: git fetch https://github.com/gitgitgadget/git pr-539/hanwen/reftable-v3
Pull-Request: https://github.com/gitgitgadget/git/pull/539
Range-diff vs v2:
-: ---------- > 1: c00403c94d refs.h: clarify reflog iteration order
1: 174b98f6db ! 2: 57c7342319 setup.c: enable repo detection for reftable
@@ -10,7 +10,6 @@
* allow missing HEAD if there is a reftable/
- Change-Id: I5d22317a15a84c8529aa503ae357a4afba247fe9
Signed-off-by: Han-Wen Nienhuys <hanwen@google.com>
diff --git a/setup.c b/setup.c
2: d7d642dcf6 ! 3: 5b7060cb2f create .git/refs in files-backend.c
@@ -2,11 +2,10 @@
create .git/refs in files-backend.c
- This prepares for supporting the reftable format, which creates a file
- in that place.
+ This prepares for supporting the reftable format, which will want
+ create its own file system layout in .git
Signed-off-by: Han-Wen Nienhuys <hanwen@google.com>
- Change-Id: I2fc47c89f5ec605734007ceff90321c02474aa92
diff --git a/builtin/init-db.c b/builtin/init-db.c
--- a/builtin/init-db.c
@@ -30,7 +29,8 @@
+ files_ref_path(refs, &sb, "refs");
+ safe_create_dir(sb.buf, 1);
-+ // XXX adjust_shared_perm ?
++ /* adjust permissions even if directory already exists. */
++ adjust_shared_perm(sb.buf);
+
/*
* Create .git/refs/{heads,tags}
3: 9cf185b51f ! 4: 1b01c735a9 Document how ref iterators and symrefs interact
@@ -1,20 +1,21 @@
Author: Han-Wen Nienhuys <hanwen@google.com>
- Document how ref iterators and symrefs interact
+ refs: document how ref_iterator_advance_fn should handle symrefs
- Change-Id: Ie3ee63c52254c000ef712986246ca28f312b4301
Signed-off-by: Han-Wen Nienhuys <hanwen@google.com>
diff --git a/refs/refs-internal.h b/refs/refs-internal.h
--- a/refs/refs-internal.h
+++ b/refs/refs-internal.h
@@
- * to the next entry, ref_iterator_advance() aborts the iteration,
- * frees the ref_iterator, and returns ITER_ERROR.
- *
-+ * Ref iterators cannot return symref targets, so symbolic refs must be
-+ * dereferenced during the iteration.
-+ *
- * The reference currently being looked at can be peeled by calling
- * ref_iterator_peel(). This function is often faster than peel_ref(),
- * so it should be preferred when iterating over references.
+
+ /* Virtual function declarations for ref_iterators: */
+
++/*
++ * backend-specific implementation of ref_iterator_advance.
++ * For symrefs, the function should set REF_ISSYMREF, and it should also dereference
++ * the symref to provide the OID referent.
++ */
+ typedef int ref_iterator_advance_fn(struct ref_iterator *ref_iterator);
+
+ typedef int ref_iterator_peel_fn(struct ref_iterator *ref_iterator,
4: 2106ff286b ! 5: eb0df10068 Add reftable library
@@ -30,7 +30,6 @@
* go-git support issue: https://github.com/src-d/go-git/issues/1059
Signed-off-by: Han-Wen Nienhuys <hanwen@google.com>
- Change-Id: Id396ff42be8b42b9e11f194a32e2f95b8250c109
diff --git a/reftable/LICENSE b/reftable/LICENSE
new file mode 100644
@@ -88,6 +87,8 @@
+ git --git-dir reftable-repo/.git show --no-patch origin/master \
+ > reftable/VERSION && \
+ echo '/* empty */' > reftable/config.h
++ rm reftable/*_test.c reftable/test_framework.*
++ git add reftable/*.[ch]
+
+Bugfixes should be accompanied by a test and applied to upstream project at
+https://github.com/google/reftable.
@@ -97,11 +98,11 @@
--- /dev/null
+++ b/reftable/VERSION
@@
-+commit c616d53b88657c3a5fe4d2e7243a48effc34c626
++commit e54326f73d95bfe8b17f264c400f4c365dbd5e5e
+Author: Han-Wen Nienhuys <hanwen@google.com>
-+Date: Mon Jan 27 15:05:43 2020 +0100
++Date: Tue Feb 4 19:48:17 2020 +0100
+
-+ C: ban // comments
++ C: PRI?MAX use; clang-format.
diff --git a/reftable/basics.c b/reftable/basics.c
new file mode 100644
@@ -327,7 +328,6 @@
+
+#define true 1
+#define false 0
-+#define ARRAYSIZE(a) sizeof(a) / sizeof(a[0])
+
+void put_u24(byte *out, uint32_t i);
+uint32_t get_u24(byte *in);
@@ -528,9 +528,10 @@
+ slice_resize(&uncompressed, sz);
+ memcpy(uncompressed.buf, block->data, block_header_skip);
+
-+ if (Z_OK !=
-+ uncompress2(uncompressed.buf + block_header_skip, &dst_len,
-+ block->data + block_header_skip, &src_len)) {
++ if (Z_OK != uncompress_return_consumed(
++ uncompressed.buf + block_header_skip,
++ &dst_len, block->data + block_header_skip,
++ &src_len)) {
+ free(slice_yield(&uncompressed));
+ return ZLIB_ERROR;
+ }
@@ -545,8 +546,8 @@
+ } else if (sz < full_block_size && sz < block->len &&
+ block->data[sz] != 0) {
+ /* If the block is smaller than the full block size, it is
-+ padded (data followed by '\0') or the next block is
-+ unaligned. */
++ padded (data followed by '\0') or the next block is
++ unaligned. */
+ full_block_size = sz;
+ }
+
@@ -750,8 +751,7 @@
+
+void block_writer_clear(struct block_writer *bw)
+{
-+ free(bw->restarts);
-+ bw->restarts = NULL;
++ FREE_AND_NULL(bw->restarts);
+ free(slice_yield(&bw->last_key));
+ /* the block is not owned. */
+}
@@ -833,163 +833,6 @@
+
+#endif
- diff --git a/reftable/block_test.c b/reftable/block_test.c
- new file mode 100644
- --- /dev/null
- +++ b/reftable/block_test.c
-@@
-+/*
-+Copyright 2020 Google LLC
-+
-+Use of this source code is governed by a BSD-style
-+license that can be found in the LICENSE file or at
-+https://developers.google.com/open-source/licenses/bsd
-+*/
-+
-+#include "block.h"
-+
-+#include "system.h"
-+
-+#include "basics.h"
-+#include "constants.h"
-+#include "record.h"
-+#include "reftable.h"
-+#include "test_framework.h"
-+
-+struct binsearch_args {
-+ int key;
-+ int *arr;
-+};
-+
-+static int binsearch_func(int i, void *void_args)
-+{
-+ struct binsearch_args *args = (struct binsearch_args *)void_args;
-+
-+ return args->key < args->arr[i];
-+}
-+
-+void test_binsearch()
-+{
-+ int arr[] = { 2, 4, 6, 8, 10 };
-+ int sz = ARRAYSIZE(arr);
-+ struct binsearch_args args = {
-+ .arr = arr,
-+ };
-+
-+ int i = 0;
-+ for (i = 1; i < 11; i++) {
-+ args.key = i;
-+ int res = binsearch(sz, &binsearch_func, &args);
-+
-+ if (res < sz) {
-+ assert(args.key < arr[res]);
-+ if (res > 0) {
-+ assert(args.key >= arr[res - 1]);
-+ }
-+ } else {
-+ assert(args.key == 10 || args.key == 11);
-+ }
-+ }
-+}
-+
-+void test_block_read_write()
-+{
-+ const int header_off = 21; /* random */
-+ const int N = 30;
-+ char *names[N];
-+ const int block_size = 1024;
-+ struct block block = {};
-+ block.data = calloc(block_size, 1);
-+ block.len = block_size;
-+
-+ struct block_writer bw = {};
-+ block_writer_init(&bw, BLOCK_TYPE_REF, block.data, block_size,
-+ header_off, SHA1_SIZE);
-+ struct ref_record ref = {};
-+ struct record rec = {};
-+ record_from_ref(&rec, &ref);
-+
-+ int i = 0;
-+ for (i = 0; i < N; i++) {
-+ char name[100];
-+ snprintf(name, sizeof(name), "branch%02d", i);
-+
-+ byte hash[SHA1_SIZE];
-+ memset(hash, i, sizeof(hash));
-+
-+ ref.ref_name = name;
-+ ref.value = hash;
-+ names[i] = strdup(name);
-+ int n = block_writer_add(&bw, rec);
-+ ref.ref_name = NULL;
-+ ref.value = NULL;
-+ assert(n == 0);
-+ }
-+
-+ int n = block_writer_finish(&bw);
-+ assert(n > 0);
-+
-+ block_writer_clear(&bw);
-+
-+ struct block_reader br = {};
-+ block_reader_init(&br, &block, header_off, block_size, SHA1_SIZE);
-+
-+ struct block_iter it = {};
-+ block_reader_start(&br, &it);
-+
-+ int j = 0;
-+ while (true) {
-+ int r = block_iter_next(&it, rec);
-+ assert(r >= 0);
-+ if (r > 0) {
-+ break;
-+ }
-+ assert_streq(names[j], ref.ref_name);
-+ j++;
-+ }
-+
-+ record_clear(rec);
-+ block_iter_close(&it);
-+
-+ struct slice want = {};
-+ for (i = 0; i < N; i++) {
-+ slice_set_string(&want, names[i]);
-+
-+ struct block_iter it = {};
-+ int n = block_reader_seek(&br, &it, want);
-+ assert(n == 0);
-+
-+ n = block_iter_next(&it, rec);
-+ assert(n == 0);
-+
-+ assert_streq(names[i], ref.ref_name);
-+
-+ want.len--;
-+ n = block_reader_seek(&br, &it, want);
-+ assert(n == 0);
-+
-+ n = block_iter_next(&it, rec);
-+ assert(n == 0);
-+ assert_streq(names[10 * (i / 10)], ref.ref_name);
-+
-+ block_iter_close(&it);
-+ }
-+
-+ record_clear(rec);
-+ free(block.data);
-+ free(slice_yield(&want));
-+ for (i = 0; i < N; i++) {
-+ free(names[i]);
-+ }
-+}
-+
-+int main()
-+{
-+ add_test_case("binsearch", &test_binsearch);
-+ add_test_case("block_read_write", &test_block_read_write);
-+ test_main();
-+}
-
diff --git a/reftable/blocksource.h b/reftable/blocksource.h
new file mode 100644
--- /dev/null
@@ -1324,8 +1167,7 @@
+ }
+ it->ops->close(it->iter_arg);
+ it->ops = NULL;
-+ free(it->iter_arg);
-+ it->iter_arg = NULL;
++ FREE_AND_NULL(it->iter_arg);
+}
+
+int iterator_next_ref(struct iterator it, struct ref_record *ref)
@@ -1751,16 +1593,14 @@
+ for (i = 0; i < mt->stack_len; i++) {
+ reader_free(mt->stack[i]);
+ }
-+ free(mt->stack);
-+ mt->stack = NULL;
++ FREE_AND_NULL(mt->stack);
+ mt->stack_len = 0;
+}
+
+/* clears the list of subtable, without affecting the readers themselves. */
+void merged_table_clear(struct merged_table *mt)
+{
-+ free(mt->stack);
-+ mt->stack = NULL;
++ FREE_AND_NULL(mt->stack);
+ mt->stack_len = 0;
+}
+
@@ -1897,270 +1737,6 @@
+
+#endif
- diff --git a/reftable/merged_test.c b/reftable/merged_test.c
- new file mode 100644
- --- /dev/null
- +++ b/reftable/merged_test.c
-@@
-+/*
-+Copyright 2020 Google LLC
-+
-+Use of this source code is governed by a BSD-style
-+license that can be found in the LICENSE file or at
-+https://developers.google.com/open-source/licenses/bsd
-+*/
-+
-+#include "merged.h"
-+
-+#include "system.h"
-+
-+#include "basics.h"
-+#include "block.h"
-+#include "constants.h"
-+#include "pq.h"
-+#include "reader.h"
-+#include "record.h"
-+#include "reftable.h"
-+#include "test_framework.h"
-+
-+void test_pq(void)
-+{
-+ char *names[54] = {};
-+ int N = ARRAYSIZE(names) - 1;
-+
-+ int i = 0;
-+ for (i = 0; i < N; i++) {
-+ char name[100];
-+ snprintf(name, sizeof(name), "%02d", i);
-+ names[i] = strdup(name);
-+ }
-+
-+ struct merged_iter_pqueue pq = {};
-+
-+ i = 1;
-+ do {
-+ struct record rec = new_record(BLOCK_TYPE_REF);
-+ record_as_ref(rec)->ref_name = names[i];
-+
-+ struct pq_entry e = {
-+ .rec = rec,
-+ };
-+ merged_iter_pqueue_add(&pq, e);
-+ merged_iter_pqueue_check(pq);
-+ i = (i * 7) % N;
-+ } while (i != 1);
-+
-+ const char *last = NULL;
-+ while (!merged_iter_pqueue_is_empty(pq)) {
-+ struct pq_entry e = merged_iter_pqueue_remove(&pq);
-+ merged_iter_pqueue_check(pq);
-+ struct ref_record *ref = record_as_ref(e.rec);
-+
-+ if (last != NULL) {
-+ assert(strcmp(last, ref->ref_name) < 0);
-+ }
-+ last = ref->ref_name;
-+ ref->ref_name = NULL;
-+ free(ref);
-+ }
-+
-+ for (i = 0; i < N; i++) {
-+ free(names[i]);
-+ }
-+
-+ merged_iter_pqueue_clear(&pq);
-+}
-+
-+void write_test_table(struct slice *buf, struct ref_record refs[], int n)
-+{
-+ int min = 0xffffffff;
-+ int max = 0;
-+ int i = 0;
-+ for (i = 0; i < n; i++) {
-+ uint64_t ui = refs[i].update_index;
-+ if (ui > max) {
-+ max = ui;
-+ }
-+ if (ui < min) {
-+ min = ui;
-+ }
-+ }
-+
-+ struct write_options opts = {
-+ .block_size = 256,
-+ };
-+
-+ struct writer *w = new_writer(&slice_write_void, buf, &opts);
-+ writer_set_limits(w, min, max);
-+
-+ for (i = 0; i < n; i++) {
-+ uint64_t before = refs[i].update_index;
-+ int n = writer_add_ref(w, &refs[i]);
-+ assert(n == 0);
-+ assert(before == refs[i].update_index);
-+ }
-+
-+ int err = writer_close(w);
-+ assert(err == 0);
-+
-+ writer_free(w);
-+ w = NULL;
-+}
-+
-+static struct merged_table *merged_table_from_records(struct ref_record **refs,
-+ int *sizes,
-+ struct slice *buf, int n)
-+{
-+ struct block_source *source = calloc(n, sizeof(*source));
-+ struct reader **rd = calloc(n, sizeof(*rd));
-+ int i = 0;
-+ for (i = 0; i < n; i++) {
-+ write_test_table(&buf[i], refs[i], sizes[i]);
-+ block_source_from_slice(&source[i], &buf[i]);
-+
-+ int err = new_reader(&rd[i], source[i], "name");
-+ assert(err == 0);
-+ }
-+
-+ struct merged_table *mt = NULL;
-+ int err = new_merged_table(&mt, rd, n);
-+ assert(err == 0);
-+ return mt;
-+}
-+
-+void test_merged_between(void)
-+{
-+ byte hash1[SHA1_SIZE];
-+ byte hash2[SHA1_SIZE];
-+
-+ set_test_hash(hash1, 1);
-+ set_test_hash(hash2, 2);
-+ struct ref_record r1[] = { {
-+ .ref_name = "b",
-+ .update_index = 1,
-+ .value = hash1,
-+ } };
-+ struct ref_record r2[] = { {
-+ .ref_name = "a",
-+ .update_index = 2,
-+ } };
-+
-+ struct ref_record *refs[] = { r1, r2 };
-+ int sizes[] = { 1, 1 };
-+ struct slice bufs[2] = {};
-+ struct merged_table *mt =
-+ merged_table_from_records(refs, sizes, bufs, 2);
-+
-+ struct iterator it = {};
-+ int err = merged_table_seek_ref(mt, &it, "a");
-+ assert(err == 0);
-+
-+ struct ref_record ref = {};
-+ err = iterator_next_ref(it, &ref);
-+ assert_err(err);
-+ assert(ref.update_index == 2);
-+}
-+
-+void test_merged(void)
-+{
-+ byte hash1[SHA1_SIZE];
-+ byte hash2[SHA1_SIZE];
-+
-+ set_test_hash(hash1, 1);
-+ set_test_hash(hash2, 2);
-+ struct ref_record r1[] = { {
-+ .ref_name = "a",
-+ .update_index = 1,
-+ .value = hash1,
-+ },
-+ {
-+ .ref_name = "b",
-+ .update_index = 1,
-+ .value = hash1,
-+ },
-+ {
-+ .ref_name = "c",
-+ .update_index = 1,
-+ .value = hash1,
-+ } };
-+ struct ref_record r2[] = { {
-+ .ref_name = "a",
-+ .update_index = 2,
-+ } };
-+ struct ref_record r3[] = {
-+ {
-+ .ref_name = "c",
-+ .update_index = 3,
-+ .value = hash2,
-+ },
-+ {
-+ .ref_name = "d",
-+ .update_index = 3,
-+ .value = hash1,
-+ },
-+ };
-+
-+ struct ref_record *refs[] = { r1, r2, r3 };
-+ int sizes[3] = { 3, 1, 2 };
-+ struct slice bufs[3] = {};
-+
-+ struct merged_table *mt =
-+ merged_table_from_records(refs, sizes, bufs, 3);
-+
-+ struct iterator it = {};
-+ int err = merged_table_seek_ref(mt, &it, "a");
-+ assert(err == 0);
-+
-+ struct ref_record *out = NULL;
-+ int len = 0;
-+ int cap = 0;
-+ while (len < 100) { /* cap loops/recursion. */
-+ struct ref_record ref = {};
-+ int err = iterator_next_ref(it, &ref);
-+ if (err > 0) {
-+ break;
-+ }
-+ if (len == cap) {
-+ cap = 2 * cap + 1;
-+ out = realloc(out, sizeof(struct ref_record) * cap);
-+ }
-+ out[len++] = ref;
-+ }
-+ iterator_destroy(&it);
-+
-+ struct ref_record want[] = {
-+ r2[0],
-+ r1[1],
-+ r3[0],
-+ r3[1],
-+ };
-+ assert(ARRAYSIZE(want) == len);
-+ int i = 0;
-+ for (i = 0; i < len; i++) {
-+ assert(ref_record_equal(&want[i], &out[i], SHA1_SIZE));
-+ }
-+ for (i = 0; i < len; i++) {
-+ ref_record_clear(&out[i]);
-+ }
-+ free(out);
-+
-+ for (i = 0; i < 3; i++) {
-+ free(slice_yield(&bufs[i]));
-+ }
-+ merged_table_close(mt);
-+ merged_table_free(mt);
-+}
-+
-+/* XXX test refs_for(oid) */
-+
-+int main()
-+{
-+ add_test_case("test_merged_between", &test_merged_between);
-+ add_test_case("test_pq", &test_pq);
-+ add_test_case("test_merged", &test_merged);
-+ test_main();
-+}
-
diff --git a/reftable/pq.c b/reftable/pq.c
new file mode 100644
--- /dev/null
@@ -2241,12 +1817,7 @@
+ break;
+ }
+
-+ {
-+ struct pq_entry tmp = pq->heap[min];
-+ pq->heap[min] = pq->heap[i];
-+ pq->heap[i] = tmp;
-+ }
-+
++ SWAP(pq->heap[i], pq->heap[min]);
+ i = min;
+ }
+
@@ -2269,11 +1840,7 @@
+ break;
+ }
+
-+ {
-+ struct pq_entry tmp = pq->heap[j];
-+ pq->heap[j] = pq->heap[i];
-+ pq->heap[i] = tmp;
-+ }
++ SWAP(pq->heap[j], pq->heap[i]);
+
+ i = j;
+ }
@@ -2286,8 +1853,7 @@
+ record_clear(pq->heap[i].rec);
+ free(record_yield(&pq->heap[i].rec));
+ }
-+ free(pq->heap);
-+ pq->heap = NULL;
++ FREE_AND_NULL(pq->heap);
+ pq->len = pq->cap = 0;
+}
@@ -2561,8 +2127,7 @@
+ return;
+ }
+ reader_return_block(ti->r, &ti->bi.br->block);
-+ free(ti->bi.br);
-+ ti->bi.br = NULL;
++ FREE_AND_NULL(ti->bi.br);
+
+ ti->bi.last_key.len = 0;
+ ti->bi.next_off = 0;
@@ -2934,8 +2499,7 @@
+void reader_close(struct reader *r)
+{
+ block_source_close(&r->source);
-+ free(r->name);
-+ r->name = NULL;
++ FREE_AND_NULL(r->name);
+}
+
+int new_reader(struct reader **p, struct block_source src, char const *name)
@@ -3271,7 +2835,7 @@
+ assert(hash_size > 0);
+
+ /* This is simple and correct, but we could probably reuse the hash
-+ fields. */
++ fields. */
+ ref_record_clear(ref);
+ if (src->ref_name != NULL) {
+ ref->ref_name = strdup(src->ref_name);
@@ -3491,16 +3055,13 @@
+ }
+
+ if (!seen_target && r->target != NULL) {
-+ free(r->target);
-+ r->target = NULL;
++ FREE_AND_NULL(r->target);
+ }
+ if (!seen_target_value && r->target_value != NULL) {
-+ free(r->target_value);
-+ r->target_value = NULL;
++ FREE_AND_NULL(r->target_value);
+ }
+ if (!seen_value && r->value != NULL) {
-+ free(r->value);
-+ r->value = NULL;
++ FREE_AND_NULL(r->value);
+ }
+
+ return start.len - in.len;
@@ -3588,8 +3149,8 @@
+static void obj_record_clear(void *rec)
+{
+ struct obj_record *ref = (struct obj_record *)rec;
-+ free(ref->hash_prefix);
-+ free(ref->offsets);
++ FREE_AND_NULL(ref->hash_prefix);
++ FREE_AND_NULL(ref->offsets);
+ memset(ref, 0, sizeof(struct obj_record));
+}
+
@@ -3713,9 +3274,9 @@
+{
+ char hex[SHA256_SIZE + 1] = {};
+
-+ printf("log{%s(%" PRIdMAX ") %s <%s> %lu %04d\n", log->ref_name,
-+ log->update_index, log->name, log->email, log->time,
-+ log->tz_offset);
++ printf("log{%s(%" PRIdMAX ") %s <%s> %" PRIuMAX " %04d\n",
++ log->ref_name, log->update_index, log->name, log->email,
++ log->time, log->tz_offset);
+ hex_format(hex, log->old_hash, hash_size);
+ printf("%s => ", hex);
+ hex_format(hex, log->new_hash, hash_size);
@@ -4306,10 +3867,10 @@
+
+#endif
- diff --git a/reftable/record_test.c b/reftable/record_test.c
+ diff --git a/reftable/reftable.h b/reftable/reftable.h
new file mode 100644
--- /dev/null
- +++ b/reftable/record_test.c
+ +++ b/reftable/reftable.h
@@
+/*
+Copyright 2020 Google LLC
@@ -4319,402 +3880,64 @@
+https://developers.google.com/open-source/licenses/bsd
+*/
+
-+#include "record.h"
++#ifndef REFTABLE_H
++#define REFTABLE_H
+
+#include "system.h"
+
-+#include "basics.h"
-+#include "constants.h"
-+#include "reftable.h"
-+#include "test_framework.h"
-+
-+void varint_roundtrip()
-+{
-+ uint64_t inputs[] = { 0,
-+ 1,
-+ 27,
-+ 127,
-+ 128,
-+ 257,
-+ 4096,
-+ ((uint64_t)1 << 63),
-+ ((uint64_t)1 << 63) + ((uint64_t)1 << 63) - 1 };
-+ int i = 0;
-+ for (i = 0; i < ARRAYSIZE(inputs); i++) {
-+ byte dest[10];
++typedef uint8_t byte;
++typedef byte bool;
+
-+ struct slice out = { .buf = dest, .len = 10, .cap = 10 };
++/* block_source is a generic wrapper for a seekable readable file.
++ It is generally passed around by value.
++ */
++struct block_source {
++ struct block_source_vtable *ops;
++ void *arg;
++};
+
-+ uint64_t in = inputs[i];
-+ int n = put_var_int(out, in);
-+ assert(n > 0);
-+ out.len = n;
++/* a contiguous segment of bytes. It keeps track of its generating block_source
++ so it can return itself into the pool.
++*/
++struct block {
++ byte *data;
++ int len;
++ struct block_source source;
++};
+
-+ uint64_t got = 0;
-+ n = get_var_int(&got, out);
-+ assert(n > 0);
++/* block_source_vtable are the operations that make up block_source */
++struct block_source_vtable {
++ /* returns the size of a block source */
++ uint64_t (*size)(void *source);
+
-+ assert(got == in);
-+ }
-+}
++ /* reads a segment from the block source. It is an error to read
++ beyond the end of the block */
++ int (*read_block)(void *source, struct block *dest, uint64_t off,
++ uint32_t size);
++ /* mark the block as read; may return the data back to malloc */
++ void (*return_block)(void *source, struct block *blockp);
+
-+void test_common_prefix()
-+{
-+ struct {
-+ const char *a, *b;
-+ int want;
-+ } cases[] = {
-+ { "abc", "ab", 2 },
-+ { "", "abc", 0 },
-+ { "abc", "abd", 2 },
-+ { "abc", "pqr", 0 },
-+ };
++ /* release all resources associated with the block source */
++ void (*close)(void *source);
++};
+
-+ int i = 0;
-+ for (i = 0; i < ARRAYSIZE(cases); i++) {
-+ struct slice a = {};
-+ struct slice b = {};
-+ slice_set_string(&a, cases[i].a);
-+ slice_set_string(&b, cases[i].b);
++/* opens a file on the file system as a block_source */
++int block_source_from_file(struct block_source *block_src, const char *name);
+
-+ int got = common_prefix_size(a, b);
-+ assert(got == cases[i].want);
++/* write_options sets options for writing a single reftable. */
++struct write_options {
++ /* do not pad out blocks to block size. */
++ bool unpadded;
+
-+ free(slice_yield(&a));
-+ free(slice_yield(&b));
-+ }
-+}
++ /* the blocksize. Should be less than 2^24. */
++ uint32_t block_size;
+
-+void set_hash(byte *h, int j)
-+{
-+ int i = 0;
-+ for (i = 0; i < SHA1_SIZE; i++) {
-+ h[i] = (j >> i) & 0xff;
-+ }
-+}
++ /* do not generate a SHA1 => ref index. */
++ bool skip_index_objects;
+
-+void test_ref_record_roundtrip()
-+{
-+ int i = 0;
-+ for (i = 0; i <= 3; i++) {
-+ printf("subtest %d\n", i);
-+ struct ref_record in = {};
-+ switch (i) {
-+ case 0:
-+ break;
-+ case 1:
-+ in.value = malloc(SHA1_SIZE);
-+ set_hash(in.value, 1);
-+ break;
-+ case 2:
-+ in.value = malloc(SHA1_SIZE);
-+ set_hash(in.value, 1);
-+ in.target_value = malloc(SHA1_SIZE);
-+ set_hash(in.target_value, 2);
-+ break;
-+ case 3:
-+ in.target = strdup("target");
-+ break;
-+ }
-+ in.ref_name = strdup("refs/heads/master");
-+
-+ struct record rec = {};
-+ record_from_ref(&rec, &in);
-+ assert(record_val_type(rec) == i);
-+ byte buf[1024];
-+ struct slice key = {};
-+ record_key(rec, &key);
-+ struct slice dest = {
-+ .buf = buf,
-+ .len = sizeof(buf),
-+ };
-+ int n = record_encode(rec, dest, SHA1_SIZE);
-+ assert(n > 0);
-+
-+ struct ref_record out = {};
-+ struct record rec_out = {};
-+ record_from_ref(&rec_out, &out);
-+ int m = record_decode(rec_out, key, i, dest, SHA1_SIZE);
-+ assert(n == m);
-+
-+ assert((out.value != NULL) == (in.value != NULL));
-+ assert((out.target_value != NULL) == (in.target_value != NULL));
-+ assert((out.target != NULL) == (in.target != NULL));
-+ free(slice_yield(&key));
-+ record_clear(rec_out);
-+ ref_record_clear(&in);
-+ }
-+}
-+
-+void test_log_record_roundtrip()
-+{
-+ struct log_record in = {
-+ .ref_name = strdup("refs/heads/master"),
-+ .old_hash = malloc(SHA1_SIZE),
-+ .new_hash = malloc(SHA1_SIZE),
-+ .name = strdup("han-wen"),
-+ .email = strdup("hanwen@google.com"),
-+ .message = strdup("test"),
-+ .update_index = 42,
-+ .time = 1577123507,
-+ .tz_offset = 100,
-+ };
-+
-+ struct record rec = {};
-+ record_from_log(&rec, &in);
-+
-+ struct slice key = {};
-+ record_key(rec, &key);
-+
-+ byte buf[1024];
-+ struct slice dest = {
-+ .buf = buf,
-+ .len = sizeof(buf),
-+ };
-+
-+ int n = record_encode(rec, dest, SHA1_SIZE);
-+ assert(n > 0);
-+
-+ struct log_record out = {};
-+ struct record rec_out = {};
-+ record_from_log(&rec_out, &out);
-+ int valtype = record_val_type(rec);
-+ int m = record_decode(rec_out, key, valtype, dest, SHA1_SIZE);
-+ assert(n == m);
-+
-+ assert(log_record_equal(&in, &out, SHA1_SIZE));
-+ log_record_clear(&in);
-+ free(slice_yield(&key));
-+ record_clear(rec_out);
-+}
-+
-+void test_u24_roundtrip()
-+{
-+ uint32_t in = 0x112233;
-+ byte dest[3];
-+
-+ put_u24(dest, in);
-+ uint32_t out = get_u24(dest);
-+ assert(in == out);
-+}
-+
-+void test_key_roundtrip()
-+{
-+ struct slice dest = {}, last_key = {}, key = {}, roundtrip = {};
-+
-+ slice_resize(&dest, 1024);
-+ slice_set_string(&last_key, "refs/heads/master");
-+ slice_set_string(&key, "refs/tags/bla");
-+
-+ bool restart;
-+ byte extra = 6;
-+ int n = encode_key(&restart, dest, last_key, key, extra);
-+ assert(!restart);
-+ assert(n > 0);
-+
-+ byte rt_extra;
-+ int m = decode_key(&roundtrip, &rt_extra, last_key, dest);
-+ assert(n == m);
-+ assert(slice_equal(key, roundtrip));
-+ assert(rt_extra == extra);
-+
-+ free(slice_yield(&last_key));
-+ free(slice_yield(&key));
-+ free(slice_yield(&dest));
-+ free(slice_yield(&roundtrip));
-+}
-+
-+void print_bytes(byte *p, int l)
-+{
-+ int i = 0;
-+ for (i = 0; i < l; i++) {
-+ byte c = *p;
-+ if (c < 32) {
-+ c = '.';
-+ }
-+ printf("%02x[%c] ", p[i], c);
-+ }
-+ printf("(%d)\n", l);
-+}
-+
-+void test_obj_record_roundtrip()
-+{
-+ byte testHash1[SHA1_SIZE] = {};
-+ set_hash(testHash1, 1);
-+ uint64_t till9[] = { 1, 2, 3, 4, 500, 600, 700, 800, 9000 };
-+
-+ struct obj_record recs[3] = { {
-+ .hash_prefix = testHash1,
-+ .hash_prefix_len = 5,
-+ .offsets = till9,
-+ .offset_len = 3,
-+ },
-+ {
-+ .hash_prefix = testHash1,
-+ .hash_prefix_len = 5,
-+ .offsets = till9,
-+ .offset_len = 9,
-+ },
-+ {
-+ .hash_prefix = testHash1,
-+ .hash_prefix_len = 5,
-+ }
-+
-+ };
-+ int i = 0;
-+ for (i = 0; i < ARRAYSIZE(recs); i++) {
-+ printf("subtest %d\n", i);
-+ struct obj_record in = recs[i];
-+ byte buf[1024];
-+ struct record rec = {};
-+ record_from_obj(&rec, &in);
-+ struct slice key = {};
-+ record_key(rec, &key);
-+ struct slice dest = {
-+ .buf = buf,
-+ .len = sizeof(buf),
-+ };
-+ int n = record_encode(rec, dest, SHA1_SIZE);
-+ assert(n > 0);
-+ byte extra = record_val_type(rec);
-+ struct obj_record out = {};
-+ struct record rec_out = {};
-+ record_from_obj(&rec_out, &out);
-+ int m = record_decode(rec_out, key, extra, dest, SHA1_SIZE);
-+ assert(n == m);
-+
-+ assert(in.hash_prefix_len == out.hash_prefix_len);
-+ assert(in.offset_len == out.offset_len);
-+
-+ assert(!memcmp(in.hash_prefix, out.hash_prefix,
-+ in.hash_prefix_len));
-+ assert(0 == memcmp(in.offsets, out.offsets,
-+ sizeof(uint64_t) * in.offset_len));
-+ free(slice_yield(&key));
-+ record_clear(rec_out);
-+ }
-+}
-+
-+void test_index_record_roundtrip()
-+{
-+ struct index_record in = { .offset = 42 };
-+
-+ slice_set_string(&in.last_key, "refs/heads/master");
-+
-+ struct slice key = {};
-+ struct record rec = {};
-+ record_from_index(&rec, &in);
-+ record_key(rec, &key);
-+
-+ assert(0 == slice_compare(key, in.last_key));
-+
-+ byte buf[1024];
-+ struct slice dest = {
-+ .buf = buf,
-+ .len = sizeof(buf),
-+ };
-+ int n = record_encode(rec, dest, SHA1_SIZE);
-+ assert(n > 0);
-+
-+ byte extra = record_val_type(rec);
-+ struct index_record out = {};
-+ struct record out_rec;
-+ record_from_index(&out_rec, &out);
-+ int m = record_decode(out_rec, key, extra, dest, SHA1_SIZE);
-+ assert(m == n);
-+
-+ assert(in.offset == out.offset);
-+
-+ record_clear(out_rec);
-+ free(slice_yield(&key));
-+ free(slice_yield(&in.last_key));
-+}
-+
-+int main()
-+{
-+ add_test_case("test_log_record_roundtrip", &test_log_record_roundtrip);
-+ add_test_case("test_ref_record_roundtrip", &test_ref_record_roundtrip);
-+ add_test_case("varint_roundtrip", &varint_roundtrip);
-+ add_test_case("test_key_roundtrip", &test_key_roundtrip);
-+ add_test_case("test_common_prefix", &test_common_prefix);
-+ add_test_case("test_obj_record_roundtrip", &test_obj_record_roundtrip);
-+ add_test_case("test_index_record_roundtrip",
-+ &test_index_record_roundtrip);
-+ add_test_case("test_u24_roundtrip", &test_u24_roundtrip);
-+ test_main();
-+}
-
- diff --git a/reftable/reftable.h b/reftable/reftable.h
- new file mode 100644
- --- /dev/null
- +++ b/reftable/reftable.h
-@@
-+/*
-+Copyright 2020 Google LLC
-+
-+Use of this source code is governed by a BSD-style
-+license that can be found in the LICENSE file or at
-+https://developers.google.com/open-source/licenses/bsd
-+*/
-+
-+#ifndef REFTABLE_H
-+#define REFTABLE_H
-+
-+#include "system.h"
-+
-+typedef uint8_t byte;
-+typedef byte bool;
-+
-+/* block_source is a generic wrapper for a seekable readable file.
-+ It is generally passed around by value.
-+ */
-+struct block_source {
-+ struct block_source_vtable *ops;
-+ void *arg;
-+};
-+
-+/* a contiguous segment of bytes. It keeps track of its generating block_source
-+ so it can return itself into the pool.
-+*/
-+struct block {
-+ byte *data;
-+ int len;
-+ struct block_source source;
-+};
-+
-+/* block_source_vtable are the operations that make up block_source */
-+struct block_source_vtable {
-+ /* returns the size of a block source */
-+ uint64_t (*size)(void *source);
-+
-+ /* reads a segment from the block source. It is an error to read
-+ beyond the end of the block */
-+ int (*read_block)(void *source, struct block *dest, uint64_t off,
-+ uint32_t size);
-+ /* mark the block as read; may return the data back to malloc */
-+ void (*return_block)(void *source, struct block *blockp);
-+
-+ /* release all resources associated with the block source */
-+ void (*close)(void *source);
-+};
-+
-+/* opens a file on the file system as a block_source */
-+int block_source_from_file(struct block_source *block_src, const char *name);
-+
-+/* write_options sets options for writing a single reftable. */
-+struct write_options {
-+ /* do not pad out blocks to block size. */
-+ bool unpadded;
-+
-+ /* the blocksize. Should be less than 2^24. */
-+ uint32_t block_size;
-+
-+ /* do not generate a SHA1 => ref index. */
-+ bool skip_index_objects;
-+
-+ /* how often to write complete keys in each block. */
-+ int restart_interval;
-+};
++ /* how often to write complete keys in each block. */
++ int restart_interval;
++};
+
+/* ref_record holds a ref database entry target_value */
+struct ref_record {
@@ -5049,493 +4272,6 @@
+
+#endif
- diff --git a/reftable/reftable_test.c b/reftable/reftable_test.c
- new file mode 100644
- --- /dev/null
- +++ b/reftable/reftable_test.c
-@@
-+/*
-+Copyright 2020 Google LLC
-+
-+Use of this source code is governed by a BSD-style
-+license that can be found in the LICENSE file or at
-+https://developers.google.com/open-source/licenses/bsd
-+*/
-+
-+#include "reftable.h"
-+
-+#include "system.h"
-+
-+#include "basics.h"
-+#include "block.h"
-+#include "constants.h"
-+#include "reader.h"
-+#include "record.h"
-+#include "test_framework.h"
-+
-+static const int update_index = 5;
-+
-+void test_buffer(void)
-+{
-+ struct slice buf = {};
-+
-+ byte in[] = "hello";
-+ slice_write(&buf, in, sizeof(in));
-+ struct block_source source;
-+ block_source_from_slice(&source, &buf);
-+ assert(block_source_size(source) == 6);
-+ struct block out = {};
-+ int n = block_source_read_block(source, &out, 0, sizeof(in));
-+ assert(n == sizeof(in));
-+ assert(!memcmp(in, out.data, n));
-+ block_source_return_block(source, &out);
-+
-+ n = block_source_read_block(source, &out, 1, 2);
-+ assert(n == 2);
-+ assert(!memcmp(out.data, "el", 2));
-+
-+ block_source_return_block(source, &out);
-+ block_source_close(&source);
-+ free(slice_yield(&buf));
-+}
-+
-+void write_table(char ***names, struct slice *buf, int N, int block_size)
-+{
-+ *names = calloc(sizeof(char *), N + 1);
-+
-+ struct write_options opts = {
-+ .block_size = block_size,
-+ };
-+
-+ struct writer *w = new_writer(&slice_write_void, buf, &opts);
-+
-+ writer_set_limits(w, update_index, update_index);
-+ {
-+ struct ref_record ref = {};
-+ int i = 0;
-+ for (i = 0; i < N; i++) {
-+ byte hash[SHA1_SIZE];
-+ set_test_hash(hash, i);
-+
-+ char name[100];
-+ snprintf(name, sizeof(name), "refs/heads/branch%02d",
-+ i);
-+
-+ ref.ref_name = name;
-+ ref.value = hash;
-+ ref.update_index = update_index;
-+ (*names)[i] = strdup(name);
-+
-+ int n = writer_add_ref(w, &ref);
-+ assert(n == 0);
-+ }
-+ }
-+ {
-+ struct log_record log = {};
-+ int i = 0;
-+ for (i = 0; i < N; i++) {
-+ byte hash[SHA1_SIZE];
-+ set_test_hash(hash, i);
-+
-+ char name[100];
-+ snprintf(name, sizeof(name), "refs/heads/branch%02d",
-+ i);
-+
-+ log.ref_name = name;
-+ log.new_hash = hash;
-+ log.update_index = update_index;
-+ log.message = "message";
-+
-+ int n = writer_add_log(w, &log);
-+ assert(n == 0);
-+ }
-+ }
-+
-+ int n = writer_close(w);
-+ assert(n == 0);
-+
-+ struct stats *stats = writer_stats(w);
-+ int i = 0;
-+ for (i = 0; i < stats->ref_stats.blocks; i++) {
-+ int off = i * opts.block_size;
-+ if (off == 0) {
-+ off = HEADER_SIZE;
-+ }
-+ assert(buf->buf[off] == 'r');
-+ }
-+
-+ writer_free(w);
-+ w = NULL;
-+}
-+
-+void test_log_write_read(void)
-+{
-+ int N = 2;
-+ char **names = calloc(sizeof(char *), N + 1);
-+
-+ struct write_options opts = {
-+ .block_size = 256,
-+ };
-+
-+ struct slice buf = {};
-+ struct writer *w = new_writer(&slice_write_void, &buf, &opts);
-+
-+ writer_set_limits(w, 0, N);
-+ {
-+ struct ref_record ref = {};
-+ int i = 0;
-+ for (i = 0; i < N; i++) {
-+ char name[256];
-+ snprintf(name, sizeof(name), "b%02d%0*d", i, 130, 7);
-+ names[i] = strdup(name);
-+ puts(name);
-+ ref.ref_name = name;
-+ ref.update_index = i;
-+
-+ int err = writer_add_ref(w, &ref);
-+ assert_err(err);
-+ }
-+ }
-+
-+ {
-+ struct log_record log = {};
-+ int i = 0;
-+ for (i = 0; i < N; i++) {
-+ byte hash1[SHA1_SIZE], hash2[SHA1_SIZE];
-+ set_test_hash(hash1, i);
-+ set_test_hash(hash2, i + 1);
-+
-+ log.ref_name = names[i];
-+ log.update_index = i;
-+ log.old_hash = hash1;
-+ log.new_hash = hash2;
-+
-+ int err = writer_add_log(w, &log);
-+ assert_err(err);
-+ }
-+ }
-+
-+ int n = writer_close(w);
-+ assert(n == 0);
-+
-+ struct stats *stats = writer_stats(w);
-+ assert(stats->log_stats.blocks > 0);
-+ writer_free(w);
-+ w = NULL;
-+
-+ struct block_source source = {};
-+ block_source_from_slice(&source, &buf);
-+
-+ struct reader rd = {};
-+ int err = init_reader(&rd, source, "file.log");
-+ assert(err == 0);
-+
-+ {
-+ struct iterator it = {};
-+ err = reader_seek_ref(&rd, &it, names[N - 1]);
-+ assert(err == 0);
-+
-+ struct ref_record ref = {};
-+ err = iterator_next_ref(it, &ref);
-+ assert_err(err);
-+
-+ /* end of iteration. */
-+ err = iterator_next_ref(it, &ref);
-+ assert(0 < err);
-+
-+ iterator_destroy(&it);
-+ ref_record_clear(&ref);
-+ }
-+
-+ {
-+ struct iterator it = {};
-+ err = reader_seek_log(&rd, &it, "");
-+ assert(err == 0);
-+
-+ struct log_record log = {};
-+ int i = 0;
-+ while (true) {
-+ int err = iterator_next_log(it, &log);
-+ if (err > 0) {
-+ break;
-+ }
-+
-+ assert_err(err);
-+ assert_streq(names[i], log.ref_name);
-+ assert(i == log.update_index);
-+ i++;
-+ }
-+
-+ assert(i == N);
-+ iterator_destroy(&it);
-+ }
-+
-+ /* cleanup. */
-+ free(slice_yield(&buf));
-+ free_names(names);
-+ reader_close(&rd);
-+}
-+
-+void test_table_read_write_sequential(void)
-+{
-+ char **names;
-+ struct slice buf = {};
-+ int N = 50;
-+ write_table(&names, &buf, N, 256);
-+
-+ struct block_source source = {};
-+ block_source_from_slice(&source, &buf);
-+
-+ struct reader rd = {};
-+ int err = init_reader(&rd, source, "file.ref");
-+ assert(err == 0);
-+
-+ struct iterator it = {};
-+ err = reader_seek_ref(&rd, &it, "");
-+ assert(err == 0);
-+
-+ int j = 0;
-+ while (true) {
-+ struct ref_record ref = {};
-+ int r = iterator_next_ref(it, &ref);
-+ assert(r >= 0);
-+ if (r > 0) {
-+ break;
-+ }
-+ assert(0 == strcmp(names[j], ref.ref_name));
-+ assert(update_index == ref.update_index);
-+
-+ j++;
-+ ref_record_clear(&ref);
-+ }
-+ assert(j == N);
-+ iterator_destroy(&it);
-+ free(slice_yield(&buf));
-+ free_names(names);
-+
-+ reader_close(&rd);
-+}
-+
-+void test_table_write_small_table(void)
-+{
-+ char **names;
-+ struct slice buf = {};
-+ int N = 1;
-+ write_table(&names, &buf, N, 4096);
-+ assert(buf.len < 200);
-+ free(slice_yield(&buf));
-+ free_names(names);
-+}
-+
-+void test_table_read_api(void)
-+{
-+ char **names;
-+ struct slice buf = {};
-+ int N = 50;
-+ write_table(&names, &buf, N, 256);
-+
-+ struct reader rd = {};
-+ struct block_source source = {};
-+ block_source_from_slice(&source, &buf);
-+
-+ int err = init_reader(&rd, source, "file.ref");
-+ assert(err == 0);
-+
-+ struct iterator it = {};
-+ err = reader_seek_ref(&rd, &it, names[0]);
-+ assert(err == 0);
-+
-+ struct log_record log = {};
-+ err = iterator_next_log(it, &log);
-+ assert(err == API_ERROR);
-+
-+ free(slice_yield(&buf));
-+ int i = 0;
-+ for (i = 0; i < N; i++) {
-+ free(names[i]);
-+ }
-+ free(names);
-+ reader_close(&rd);
-+}
-+
-+void test_table_read_write_seek(bool index)
-+{
-+ char **names;
-+ struct slice buf = {};
-+ int N = 50;
-+ write_table(&names, &buf, N, 256);
-+
-+ struct reader rd = {};
-+ struct block_source source = {};
-+ block_source_from_slice(&source, &buf);
-+
-+ int err = init_reader(&rd, source, "file.ref");
-+ assert(err == 0);
-+
-+ if (!index) {
-+ rd.ref_offsets.index_offset = 0;
-+ }
-+
-+ int i = 0;
-+ for (i = 1; i < N; i++) {
-+ struct iterator it = {};
-+ int err = reader_seek_ref(&rd, &it, names[i]);
-+ assert(err == 0);
-+ struct ref_record ref = {};
-+ err = iterator_next_ref(it, &ref);
-+ assert(err == 0);
-+ assert(0 == strcmp(names[i], ref.ref_name));
-+ assert(i == ref.value[0]);
-+
-+ ref_record_clear(&ref);
-+ iterator_destroy(&it);
-+ }
-+
-+ free(slice_yield(&buf));
-+ for (i = 0; i < N; i++) {
-+ free(names[i]);
-+ }
-+ free(names);
-+ reader_close(&rd);
-+}
-+
-+void test_table_read_write_seek_linear(void)
-+{
-+ test_table_read_write_seek(false);
-+}
-+
-+void test_table_read_write_seek_index(void)
-+{
-+ test_table_read_write_seek(true);
-+}
-+
-+void test_table_refs_for(bool indexed)
-+{
-+ int N = 50;
-+
-+ char **want_names = calloc(sizeof(char *), N + 1);
-+
-+ int want_names_len = 0;
-+ byte want_hash[SHA1_SIZE];
-+ set_test_hash(want_hash, 4);
-+
-+ struct write_options opts = {
-+ .block_size = 256,
-+ };
-+
-+ struct slice buf = {};
-+ struct writer *w = new_writer(&slice_write_void, &buf, &opts);
-+ {
-+ struct ref_record ref = {};
-+ int i = 0;
-+ for (i = 0; i < N; i++) {
-+ byte hash[SHA1_SIZE];
-+ memset(hash, i, sizeof(hash));
-+ char fill[51] = {};
-+ memset(fill, 'x', 50);
-+ char name[100];
-+ /* Put the variable part in the start */
-+ snprintf(name, sizeof(name), "br%02d%s", i, fill);
-+ name[40] = 0;
-+ ref.ref_name = name;
-+
-+ byte hash1[SHA1_SIZE];
-+ byte hash2[SHA1_SIZE];
-+
-+ set_test_hash(hash1, i / 4);
-+ set_test_hash(hash2, 3 + i / 4);
-+ ref.value = hash1;
-+ ref.target_value = hash2;
-+
-+ /* 80 bytes / entry, so 3 entries per block. Yields 17 */
-+ /* blocks. */
-+ int n = writer_add_ref(w, &ref);
-+ assert(n == 0);
-+
-+ if (!memcmp(hash1, want_hash, SHA1_SIZE) ||
-+ !memcmp(hash2, want_hash, SHA1_SIZE)) {
-+ want_names[want_names_len++] = strdup(name);
-+ }
-+ }
-+ }
-+
-+ int n = writer_close(w);
-+ assert(n == 0);
-+
-+ writer_free(w);
-+ w = NULL;
-+
-+ struct reader rd;
-+ struct block_source source = {};
-+ block_source_from_slice(&source, &buf);
-+
-+ int err = init_reader(&rd, source, "file.ref");
-+ assert(err == 0);
-+ if (!indexed) {
-+ rd.obj_offsets.present = 0;
-+ }
-+
-+ struct iterator it = {};
-+ err = reader_seek_ref(&rd, &it, "");
-+ assert(err == 0);
-+ iterator_destroy(&it);
-+
-+ err = reader_refs_for(&rd, &it, want_hash, SHA1_SIZE);
-+ assert(err == 0);
-+
-+ struct ref_record ref = {};
-+
-+ int j = 0;
-+ while (true) {
-+ int err = iterator_next_ref(it, &ref);
-+ assert(err >= 0);
-+ if (err > 0) {
-+ break;
-+ }
-+
-+ assert(j < want_names_len);
-+ assert(0 == strcmp(ref.ref_name, want_names[j]));
-+ j++;
-+ ref_record_clear(&ref);
-+ }
-+ assert(j == want_names_len);
-+
-+ free(slice_yield(&buf));
-+ free_names(want_names);
-+ iterator_destroy(&it);
-+ reader_close(&rd);
-+}
-+
-+void test_table_refs_for_no_index(void)
-+{
-+ test_table_refs_for(false);
-+}
-+
-+void test_table_refs_for_obj_index(void)
-+{
-+ test_table_refs_for(true);
-+}
-+
-+int main()
-+{
-+ add_test_case("test_log_write_read", test_log_write_read);
-+ add_test_case("test_table_write_small_table",
-+ &test_table_write_small_table);
-+ add_test_case("test_buffer", &test_buffer);
-+ add_test_case("test_table_read_api", &test_table_read_api);
-+ add_test_case("test_table_read_write_sequential",
-+ &test_table_read_write_sequential);
-+ add_test_case("test_table_read_write_seek_linear",
-+ &test_table_read_write_seek_linear);
-+ add_test_case("test_table_read_write_seek_index",
-+ &test_table_read_write_seek_index);
-+ add_test_case("test_table_read_write_refs_for_no_index",
-+ &test_table_refs_for_no_index);
-+ add_test_case("test_table_read_write_refs_for_obj_index",
-+ &test_table_refs_for_obj_index);
-+ test_main();
-+}
-
diff --git a/reftable/slice.c b/reftable/slice.c
new file mode 100644
--- /dev/null
@@ -5774,61 +4510,17 @@
+byte *slice_yield(struct slice *s);
+void slice_copy(struct slice *dest, struct slice src);
+void slice_resize(struct slice *s, int l);
-+int slice_compare(struct slice a, struct slice b);
-+int slice_write(struct slice *b, byte *data, int sz);
-+int slice_write_void(void *b, byte *data, int sz);
-+void slice_append(struct slice *dest, struct slice add);
-+
-+struct block_source;
-+void block_source_from_slice(struct block_source *bs, struct slice *buf);
-+
-+struct block_source malloc_block_source(void);
-+
-+#endif
-
- diff --git a/reftable/slice_test.c b/reftable/slice_test.c
- new file mode 100644
- --- /dev/null
- +++ b/reftable/slice_test.c
-@@
-+/*
-+Copyright 2020 Google LLC
-+
-+Use of this source code is governed by a BSD-style
-+license that can be found in the LICENSE file or at
-+https://developers.google.com/open-source/licenses/bsd
-+*/
-+
-+#include "slice.h"
-+
-+#include "system.h"
-+
-+#include "basics.h"
-+#include "record.h"
-+#include "reftable.h"
-+#include "test_framework.h"
-+
-+void test_slice(void)
-+{
-+ struct slice s = {};
-+ slice_set_string(&s, "abc");
-+ assert(0 == strcmp("abc", slice_as_string(&s)));
-+
-+ struct slice t = {};
-+ slice_set_string(&t, "pqr");
++int slice_compare(struct slice a, struct slice b);
++int slice_write(struct slice *b, byte *data, int sz);
++int slice_write_void(void *b, byte *data, int sz);
++void slice_append(struct slice *dest, struct slice add);
+
-+ slice_append(&s, t);
-+ assert(0 == strcmp("abcpqr", slice_as_string(&s)));
++struct block_source;
++void block_source_from_slice(struct block_source *bs, struct slice *buf);
+
-+ free(slice_yield(&s));
-+ free(slice_yield(&t));
-+}
++struct block_source malloc_block_source(void);
+
-+int main()
-+{
-+ add_test_case("test_slice", &test_slice);
-+ test_main();
-+}
++#endif
diff --git a/reftable/stack.c b/reftable/stack.c
new file mode 100644
@@ -5936,10 +4628,8 @@
+ merged_table_free(st->merged);
+ st->merged = NULL;
+
-+ free(st->list_file);
-+ st->list_file = NULL;
-+ free(st->reftable_dir);
-+ st->reftable_dir = NULL;
++ FREE_AND_NULL(st->list_file);
++ FREE_AND_NULL(st->reftable_dir);
+ free(st);
+}
+
@@ -6170,7 +4860,7 @@
+static void format_name(struct slice *dest, uint64_t min, uint64_t max)
+{
+ char buf[100];
-+ snprintf(buf, sizeof(buf), "%012lx-%012lx", min, max);
++ snprintf(buf, sizeof(buf), "%012" PRIxMAX "-%012" PRIxMAX, min, max);
+ slice_set_string(dest, buf);
+}
+
@@ -6867,293 +5557,6 @@
+
+#endif
- diff --git a/reftable/stack_test.c b/reftable/stack_test.c
- new file mode 100644
- --- /dev/null
- +++ b/reftable/stack_test.c
-@@
-+/*
-+Copyright 2020 Google LLC
-+
-+Use of this source code is governed by a BSD-style
-+license that can be found in the LICENSE file or at
-+https://developers.google.com/open-source/licenses/bsd
-+*/
-+
-+#include "stack.h"
-+
-+#include "system.h"
-+
-+#include "basics.h"
-+#include "constants.h"
-+#include "record.h"
-+#include "reftable.h"
-+#include "test_framework.h"
-+
-+void test_read_file(void)
-+{
-+ char fn[256] = "/tmp/stack.test_read_file.XXXXXX";
-+ int fd = mkstemp(fn);
-+ assert(fd > 0);
-+
-+ char out[1024] = "line1\n\nline2\nline3";
-+
-+ int n = write(fd, out, strlen(out));
-+ assert(n == strlen(out));
-+ int err = close(fd);
-+ assert(err >= 0);
-+
-+ char **names = NULL;
-+ err = read_lines(fn, &names);
-+ assert_err(err);
-+
-+ char *want[] = { "line1", "line2", "line3" };
-+ int i = 0;
-+ for (i = 0; names[i] != NULL; i++) {
-+ assert(0 == strcmp(want[i], names[i]));
-+ }
-+ free_names(names);
-+ remove(fn);
-+}
-+
-+void test_parse_names(void)
-+{
-+ char buf[] = "line\n";
-+ char **names = NULL;
-+ parse_names(buf, strlen(buf), &names);
-+
-+ assert(NULL != names[0]);
-+ assert(0 == strcmp(names[0], "line"));
-+ assert(NULL == names[1]);
-+ free_names(names);
-+}
-+
-+void test_names_equal(void)
-+{
-+ char *a[] = { "a", "b", "c", NULL };
-+ char *b[] = { "a", "b", "d", NULL };
-+ char *c[] = { "a", "b", NULL };
-+
-+ assert(names_equal(a, a));
-+ assert(!names_equal(a, b));
-+ assert(!names_equal(a, c));
-+}
-+
-+int write_test_ref(struct writer *wr, void *arg)
-+{
-+ struct ref_record *ref = arg;
-+
-+ writer_set_limits(wr, ref->update_index, ref->update_index);
-+ int err = writer_add_ref(wr, ref);
-+
-+ return err;
-+}
-+
-+int write_test_log(struct writer *wr, void *arg)
-+{
-+ struct log_record *log = arg;
-+
-+ writer_set_limits(wr, log->update_index, log->update_index);
-+ int err = writer_add_log(wr, log);
-+
-+ return err;
-+}
-+
-+void test_stack_add(void)
-+{
-+ int i = 0;
-+ char dir[256] = "/tmp/stack.test_stack_add.XXXXXX";
-+ assert(mkdtemp(dir));
-+ printf("%s\n", dir);
-+ char fn[256] = "";
-+ strcat(fn, dir);
-+ strcat(fn, "/refs");
-+
-+ struct write_options cfg = {};
-+ struct stack *st = NULL;
-+ int err = new_stack(&st, dir, fn, cfg);
-+ assert_err(err);
-+
-+ struct ref_record refs[2] = {};
-+ struct log_record logs[2] = {};
-+ int N = ARRAYSIZE(refs);
-+ for (i = 0; i < N; i++) {
-+ char buf[256];
-+ snprintf(buf, sizeof(buf), "branch%02d", i);
-+ refs[i].ref_name = strdup(buf);
-+ refs[i].value = malloc(SHA1_SIZE);
-+ refs[i].update_index = i + 1;
-+ set_test_hash(refs[i].value, i);
-+
-+ logs[i].ref_name = strdup(buf);
-+ logs[i].update_index = N + i + 1;
-+ logs[i].new_hash = malloc(SHA1_SIZE);
-+ logs[i].email = strdup("identity@invalid");
-+ set_test_hash(logs[i].new_hash, i);
-+ }
-+
-+ for (i = 0; i < N; i++) {
-+ int err = stack_add(st, &write_test_ref, &refs[i]);
-+ assert_err(err);
-+ }
-+
-+ for (i = 0; i < N; i++) {
-+ int err = stack_add(st, &write_test_log, &logs[i]);
-+ assert_err(err);
-+ }
-+
-+ err = stack_compact_all(st, NULL);
-+ assert_err(err);
-+
-+ for (i = 0; i < N; i++) {
-+ struct ref_record dest = {};
-+ int err = stack_read_ref(st, refs[i].ref_name, &dest);
-+ assert_err(err);
-+ assert(ref_record_equal(&dest, refs + i, SHA1_SIZE));
-+ ref_record_clear(&dest);
-+ }
-+
-+ for (i = 0; i < N; i++) {
-+ struct log_record dest = {};
-+ int err = stack_read_log(st, refs[i].ref_name, &dest);
-+ assert_err(err);
-+ assert(log_record_equal(&dest, logs + i, SHA1_SIZE));
-+ log_record_clear(&dest);
-+ }
-+
-+ /* cleanup */
-+ stack_destroy(st);
-+ for (i = 0; i < N; i++) {
-+ ref_record_clear(&refs[i]);
-+ log_record_clear(&logs[i]);
-+ }
-+}
-+
-+void test_log2(void)
-+{
-+ assert(1 == fastlog2(3));
-+ assert(2 == fastlog2(4));
-+ assert(2 == fastlog2(5));
-+}
-+
-+void test_sizes_to_segments(void)
-+{
-+ uint64_t sizes[] = { 2, 3, 4, 5, 7, 9 };
-+ /* .................0 1 2 3 4 5 */
-+
-+ int seglen = 0;
-+ struct segment *segs =
-+ sizes_to_segments(&seglen, sizes, ARRAYSIZE(sizes));
-+ assert(segs[2].log == 3);
-+ assert(segs[2].start == 5);
-+ assert(segs[2].end == 6);
-+
-+ assert(segs[1].log == 2);
-+ assert(segs[1].start == 2);
-+ assert(segs[1].end == 5);
-+ free(segs);
-+}
-+
-+void test_suggest_compaction_segment(void)
-+{
-+ {
-+ uint64_t sizes[] = { 128, 64, 17, 16, 9, 9, 9, 16, 16 };
-+ /* .................0 1 2 3 4 5 6 */
-+ struct segment min =
-+ suggest_compaction_segment(sizes, ARRAYSIZE(sizes));
-+ assert(min.start == 2);
-+ assert(min.end == 7);
-+ }
-+
-+ {
-+ uint64_t sizes[] = { 64, 32, 16, 8, 4, 2 };
-+ struct segment result =
-+ suggest_compaction_segment(sizes, ARRAYSIZE(sizes));
-+ assert(result.start == result.end);
-+ }
-+}
-+
-+void test_reflog_expire(void)
-+{
-+ char dir[256] = "/tmp/stack.test_reflog_expire.XXXXXX";
-+ assert(mkdtemp(dir));
-+ printf("%s\n", dir);
-+ char fn[256] = "";
-+ strcat(fn, dir);
-+ strcat(fn, "/refs");
-+
-+ struct write_options cfg = {};
-+ struct stack *st = NULL;
-+ int err = new_stack(&st, dir, fn, cfg);
-+ assert_err(err);
-+
-+ struct log_record logs[20] = {};
-+ int N = ARRAYSIZE(logs) - 1;
-+ int i = 0;
-+ for (i = 1; i <= N; i++) {
-+ char buf[256];
-+ snprintf(buf, sizeof(buf), "branch%02d", i);
-+
-+ logs[i].ref_name = strdup(buf);
-+ logs[i].update_index = i;
-+ logs[i].time = i;
-+ logs[i].new_hash = malloc(SHA1_SIZE);
-+ logs[i].email = strdup("identity@invalid");
-+ set_test_hash(logs[i].new_hash, i);
-+ }
-+
-+ for (i = 1; i <= N; i++) {
-+ int err = stack_add(st, &write_test_log, &logs[i]);
-+ assert_err(err);
-+ }
-+
-+ err = stack_compact_all(st, NULL);
-+ assert_err(err);
-+
-+ struct log_expiry_config expiry = {
-+ .time = 10,
-+ };
-+ err = stack_compact_all(st, &expiry);
-+ assert_err(err);
-+
-+ struct log_record log = {};
-+ err = stack_read_log(st, logs[9].ref_name, &log);
-+ assert(err == 1);
-+
-+ err = stack_read_log(st, logs[11].ref_name, &log);
-+ assert_err(err);
-+
-+ expiry.min_update_index = 15;
-+ err = stack_compact_all(st, &expiry);
-+ assert_err(err);
-+
-+ err = stack_read_log(st, logs[14].ref_name, &log);
-+ assert(err == 1);
-+
-+ err = stack_read_log(st, logs[16].ref_name, &log);
-+ assert_err(err);
-+
-+ /* cleanup */
-+ stack_destroy(st);
-+ for (i = 0; i < N; i++) {
-+ log_record_clear(&logs[i]);
-+ }
-+}
-+
-+int main()
-+{
-+ add_test_case("test_reflog_expire", test_reflog_expire);
-+ add_test_case("test_suggest_compaction_segment",
-+ &test_suggest_compaction_segment);
-+ add_test_case("test_sizes_to_segments", &test_sizes_to_segments);
-+ add_test_case("test_log2", &test_log2);
-+ add_test_case("test_parse_names", &test_parse_names);
-+ add_test_case("test_read_file", &test_read_file);
-+ add_test_case("test_names_equal", &test_names_equal);
-+ add_test_case("test_stack_add", &test_stack_add);
-+ test_main();
-+}
-
diff --git a/reftable/system.h b/reftable/system.h
new file mode 100644
--- /dev/null
@@ -7173,8 +5576,12 @@
+#include "config.h"
+
+#ifndef REFTABLE_STANDALONE
++
+#include "git-compat-util.h"
++#include <zlib.h>
++
+#else
++
+#include <assert.h>
+#include <errno.h>
+#include <fcntl.h>
@@ -7191,151 +5598,25 @@
+#define PRIuMAX "lu"
+#define PRIdMAX "ld"
+#define PRIxMAX "lx"
-+
-+#endif
-+
-+#endif
-
- diff --git a/reftable/test_framework.c b/reftable/test_framework.c
- new file mode 100644
- --- /dev/null
- +++ b/reftable/test_framework.c
-@@
-+/*
-+Copyright 2020 Google LLC
-+
-+Use of this source code is governed by a BSD-style
-+license that can be found in the LICENSE file or at
-+https://developers.google.com/open-source/licenses/bsd
-+*/
-+
-+#include "test_framework.h"
-+
-+#include "system.h"
-+
-+#include "constants.h"
-+
-+struct test_case **test_cases;
-+int test_case_len;
-+int test_case_cap;
-+
-+struct test_case *new_test_case(const char *name, void (*testfunc)())
-+{
-+ struct test_case *tc = malloc(sizeof(struct test_case));
-+ tc->name = name;
-+ tc->testfunc = testfunc;
-+ return tc;
-+}
-+
-+struct test_case *add_test_case(const char *name, void (*testfunc)())
-+{
-+ struct test_case *tc = new_test_case(name, testfunc);
-+ if (test_case_len == test_case_cap) {
-+ test_case_cap = 2 * test_case_cap + 1;
-+ test_cases = realloc(test_cases,
-+ sizeof(struct test_case) * test_case_cap);
-+ }
-+
-+ test_cases[test_case_len++] = tc;
-+ return tc;
-+}
-+
-+void test_main()
-+{
-+ int i = 0;
-+ for (i = 0; i < test_case_len; i++) {
-+ printf("case %s\n", test_cases[i]->name);
-+ test_cases[i]->testfunc();
-+ }
-+}
-+
-+void set_test_hash(byte *p, int i)
-+{
-+ memset(p, (byte)i, SHA1_SIZE);
-+}
-+
-+void print_names(char **a)
-+{
-+ if (a == NULL || *a == NULL) {
-+ puts("[]");
-+ return;
-+ }
-+ puts("[");
-+ char **p = a;
-+ while (*p) {
-+ puts(*p);
-+ p++;
-+ }
-+ puts("]");
-+}
-
- diff --git a/reftable/test_framework.h b/reftable/test_framework.h
- new file mode 100644
- --- /dev/null
- +++ b/reftable/test_framework.h
-@@
-+/*
-+Copyright 2020 Google LLC
-+
-+Use of this source code is governed by a BSD-style
-+license that can be found in the LICENSE file or at
-+https://developers.google.com/open-source/licenses/bsd
-+*/
-+
-+#ifndef TEST_FRAMEWORK_H
-+#define TEST_FRAMEWORK_H
-+
-+#include "system.h"
-+
-+#include "reftable.h"
-+
-+#ifdef NDEBUG
-+#undef NDEBUG
-+#endif
-+
-+#include "system.h"
-+
-+#ifdef assert
-+#undef assert
++#define ARRAY_SIZE(a) sizeof((a)) / sizeof((a)[0])
++#define FREE_AND_NULL(x) \
++ do { \
++ free(x); \
++ (x) = NULL; \
++ } while (0)
++#define QSORT(arr, n, cmp) qsort(arr, n, sizeof(arr[0]), cmp)
++#define SWAP(a, b) \
++ { \
++ char tmp[sizeof(a)]; \
++ assert(sizeof(a)==sizeof(b)); \
++ memcpy(&tmp[0], &a, sizeof(a)); \
++ memcpy(&a, &b, sizeof(a)); \
++ memcpy(&b, &tmp[0], sizeof(a)); \
++ }
+#endif
+
-+#define assert_err(c) \
-+ if (c != 0) { \
-+ fflush(stderr); \
-+ fflush(stdout); \
-+ fprintf(stderr, "%s: %d: error == %d (%s), want 0\n", \
-+ __FILE__, __LINE__, c, error_str(c)); \
-+ abort(); \
-+ }
-+
-+#define assert_streq(a, b) \
-+ if (strcmp(a, b)) { \
-+ fflush(stderr); \
-+ fflush(stdout); \
-+ fprintf(stderr, "%s:%d: %s (%s) != %s (%s)\n", __FILE__, \
-+ __LINE__, #a, a, #b, b); \
-+ abort(); \
-+ }
-+
-+#define assert(c) \
-+ if (!(c)) { \
-+ fflush(stderr); \
-+ fflush(stdout); \
-+ fprintf(stderr, "%s: %d: failed assertion %s\n", __FILE__, \
-+ __LINE__, #c); \
-+ abort(); \
-+ }
-+
-+struct test_case {
-+ const char *name;
-+ void (*testfunc)();
-+};
-+
-+struct test_case *new_test_case(const char *name, void (*testfunc)());
-+struct test_case *add_test_case(const char *name, void (*testfunc)());
-+void test_main();
-+
-+void set_test_hash(byte *p, int i);
++int uncompress_return_consumed(Bytef *dest, uLongf *destLen,
++ const Bytef *source, uLong *sourceLen);
+
+#endif
@@ -7441,73 +5722,6 @@
+
+#endif
- diff --git a/reftable/tree_test.c b/reftable/tree_test.c
- new file mode 100644
- --- /dev/null
- +++ b/reftable/tree_test.c
-@@
-+/*
-+Copyright 2020 Google LLC
-+
-+Use of this source code is governed by a BSD-style
-+license that can be found in the LICENSE file or at
-+https://developers.google.com/open-source/licenses/bsd
-+*/
-+
-+#include "tree.h"
-+
-+#include "basics.h"
-+#include "record.h"
-+#include "reftable.h"
-+#include "test_framework.h"
-+
-+static int test_compare(const void *a, const void *b)
-+{
-+ return a - b;
-+}
-+
-+struct curry {
-+ void *last;
-+};
-+
-+void check_increasing(void *arg, void *key)
-+{
-+ struct curry *c = (struct curry *)arg;
-+ if (c->last != NULL) {
-+ assert(test_compare(c->last, key) < 0);
-+ }
-+ c->last = key;
-+}
-+
-+void test_tree()
-+{
-+ struct tree_node *root = NULL;
-+
-+ void *values[11] = {};
-+ struct tree_node *nodes[11] = {};
-+ int i = 1;
-+ do {
-+ nodes[i] = tree_search(values + i, &root, &test_compare, 1);
-+ i = (i * 7) % 11;
-+ } while (i != 1);
-+
-+ for (i = 1; i < ARRAYSIZE(nodes); i++) {
-+ assert(values + i == nodes[i]->key);
-+ assert(nodes[i] ==
-+ tree_search(values + i, &root, &test_compare, 0));
-+ }
-+
-+ struct curry c = {};
-+ infix_walk(root, check_increasing, &c);
-+ tree_free(root);
-+}
-+
-+int main()
-+{
-+ add_test_case("test_tree", &test_tree);
-+ test_main();
-+}
-
diff --git a/reftable/writer.c b/reftable/writer.c
new file mode 100644
--- /dev/null
@@ -7764,7 +5978,7 @@
+{
+ int err = 0;
+ int i = 0;
-+ qsort(refs, n, sizeof(struct ref_record), ref_record_compare_name);
++ QSORT(refs, n, ref_record_compare_name);
+ for (i = 0; err == 0 && i < n; i++) {
+ err = writer_add_ref(w, &refs[i]);
+ }
@@ -7801,7 +6015,7 @@
+{
+ int err = 0;
+ int i = 0;
-+ qsort(logs, n, sizeof(struct log_record), log_record_compare_key);
++ QSORT(logs, n, log_record_compare_key);
+ for (i = 0; err == 0 && i < n; i++) {
+ err = writer_add_log(w, &logs[i]);
+ }
@@ -7948,8 +6162,7 @@
+{
+ struct obj_index_tree_node *entry = (struct obj_index_tree_node *)key;
+
-+ free(entry->offsets);
-+ entry->offsets = NULL;
++ FREE_AND_NULL(entry->offsets);
+ free(slice_yield(&entry->hash));
+ free(entry);
+}
@@ -8053,8 +6266,7 @@
+ free(slice_yield(&w->index[i].last_key));
+ }
+
-+ free(w->index);
-+ w->index = NULL;
++ FREE_AND_NULL(w->index);
+ w->index_len = 0;
+ w->index_cap = 0;
+}
@@ -8189,3 +6401,101 @@
+int writer_finish_public_section(struct writer *w);
+
+#endif
+
+ diff --git a/reftable/zlib-compat.c b/reftable/zlib-compat.c
+ new file mode 100644
+ --- /dev/null
+ +++ b/reftable/zlib-compat.c
+@@
++/* taken from zlib's uncompr.c
++
++ commit cacf7f1d4e3d44d871b605da3b647f07d718623f
++ Author: Mark Adler <madler@alumni.caltech.edu>
++ Date: Sun Jan 15 09:18:46 2017 -0800
++
++ zlib 1.2.11
++
++*/
++
++/*
++ * Copyright (C) 1995-2003, 2010, 2014, 2016 Jean-loup Gailly, Mark Adler
++ * For conditions of distribution and use, see copyright notice in zlib.h
++ */
++
++#include "system.h"
++
++/* clang-format off */
++
++/* ===========================================================================
++ Decompresses the source buffer into the destination buffer. *sourceLen is
++ the byte length of the source buffer. Upon entry, *destLen is the total size
++ of the destination buffer, which must be large enough to hold the entire
++ uncompressed data. (The size of the uncompressed data must have been saved
++ previously by the compressor and transmitted to the decompressor by some
++ mechanism outside the scope of this compression library.) Upon exit,
++ *destLen is the size of the decompressed data and *sourceLen is the number
++ of source bytes consumed. Upon return, source + *sourceLen points to the
++ first unused input byte.
++
++ uncompress returns Z_OK if success, Z_MEM_ERROR if there was not enough
++ memory, Z_BUF_ERROR if there was not enough room in the output buffer, or
++ Z_DATA_ERROR if the input data was corrupted, including if the input data is
++ an incomplete zlib stream.
++*/
++int ZEXPORT uncompress_return_consumed (
++ Bytef *dest,
++ uLongf *destLen,
++ const Bytef *source,
++ uLong *sourceLen) {
++ z_stream stream;
++ int err;
++ const uInt max = (uInt)-1;
++ uLong len, left;
++ Byte buf[1]; /* for detection of incomplete stream when *destLen == 0 */
++
++ len = *sourceLen;
++ if (*destLen) {
++ left = *destLen;
++ *destLen = 0;
++ }
++ else {
++ left = 1;
++ dest = buf;
++ }
++
++ stream.next_in = (z_const Bytef *)source;
++ stream.avail_in = 0;
++ stream.zalloc = (alloc_func)0;
++ stream.zfree = (free_func)0;
++ stream.opaque = (voidpf)0;
++
++ err = inflateInit(&stream);
++ if (err != Z_OK) return err;
++
++ stream.next_out = dest;
++ stream.avail_out = 0;
++
++ do {
++ if (stream.avail_out == 0) {
++ stream.avail_out = left > (uLong)max ? max : (uInt)left;
++ left -= stream.avail_out;
++ }
++ if (stream.avail_in == 0) {
++ stream.avail_in = len > (uLong)max ? max : (uInt)len;
++ len -= stream.avail_in;
++ }
++ err = inflate(&stream, Z_NO_FLUSH);
++ } while (err == Z_OK);
++
++ *sourceLen -= len + stream.avail_in;
++ if (dest != buf)
++ *destLen = stream.total_out;
++ else if (stream.total_out && err == Z_BUF_ERROR)
++ left = 1;
++
++ inflateEnd(&stream);
++ return err == Z_STREAM_END ? Z_OK :
++ err == Z_NEED_DICT ? Z_DATA_ERROR :
++ err == Z_BUF_ERROR && left + stream.avail_out ? Z_DATA_ERROR :
++ err;
++}
5: 721201269d ! 6: 0b2a1a81d6 Reftable support for git-core
@@ -6,12 +6,14 @@
TODO:
+ * Make CI on gitgitgadget compile.
+ * Redo interaction between repo config, repo storage version
* Resolve the design problem with reflog expiry.
* Resolve spots marked with XXX
Example use:
- $ ~/vc/git/git init
+ $ ~/vc/git/git init --reftable
warning: templates not found in /usr/local/google/home/hanwen/share/git-core/templates
Initialized empty Git repository in /tmp/qz/.git/
$ echo q > a
@@ -36,7 +38,6 @@
** LOGS **
reftable.LogRecord{RefName:"HEAD", UpdateIndex:0x2, New:[]uint8{0x37, 0x3d, 0x96, 0x97, 0x2f, 0xca, 0x9b, 0x63, 0x59, 0x57, 0x40, 0xbb, 0xa3, 0x89, 0x8a, 0x76, 0x27, 0x78, 0xba, 0x20}, Old:[]uint8{0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0}, Name:"Han-Wen Nienhuys", Email:"hanwen@google.com", Time:0x5e29ef27, TZOffset:100, Message:"commit (initial): x\n"}
- Change-Id: I225ee6317b7911edf9aa95f43299f6c7c4511914
Signed-off-by: Han-Wen Nienhuys <hanwen@google.com>
diff --git a/Makefile b/Makefile
@@ -84,6 +85,7 @@
+REFTABLE_OBJS += reftable/stack.o
+REFTABLE_OBJS += reftable/tree.o
+REFTABLE_OBJS += reftable/writer.o
++REFTABLE_OBJS += reftable/zlib-compat.o
+
+
TEST_OBJS := $(patsubst %$X,%.o,$(TEST_PROGRAMS)) $(patsubst %,t/helper/%,$(TEST_BUILTINS_OBJS))
@@ -106,6 +108,114 @@ $^
Documentation/GIT-EXCLUDED-PROGRAMS: FORCE
+ diff --git a/builtin/init-db.c b/builtin/init-db.c
+ --- a/builtin/init-db.c
+ +++ b/builtin/init-db.c
+@@
+ }
+
+ static int create_default_files(const char *template_path,
+- const char *original_git_dir)
++ const char *original_git_dir, int flags)
+ {
+ struct stat st1;
+ struct strbuf buf = STRBUF_INIT;
+@@
+ * Create the default symlink from ".git/HEAD" to the "master"
+ * branch, if it does not exist yet.
+ */
+- path = git_path_buf(&buf, "HEAD");
+- reinit = (!access(path, R_OK)
+- || readlink(path, junk, sizeof(junk)-1) != -1);
++ if (flags & INIT_DB_REFTABLE) {
++ reinit = 0; /* XXX - how do we recognize a reinit,
++ * and what should we do? */
++ } else {
++ 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);
+ }
+
+ /* This forces creation of new config file */
+- xsnprintf(repo_version_string, sizeof(repo_version_string),
+- "%d", GIT_REPO_VERSION);
++ xsnprintf(repo_version_string, sizeof(repo_version_string), "%d",
++ flags & INIT_DB_REFTABLE ? GIT_REPO_VERSION_READ :
++ GIT_REPO_VERSION);
+ git_config_set("core.repositoryformatversion", repo_version_string);
+
+ /* Check filemode trustability */
+@@
+ */
+ check_repository_format();
+
+- reinit = create_default_files(template_dir, original_git_dir);
++ reinit = create_default_files(template_dir, original_git_dir, flags);
+
+ create_object_directory();
+
+@@
+ git_config_set("receive.denyNonFastforwards", "true");
+ }
+
++ if (flags & INIT_DB_REFTABLE) {
++ git_config_set("extensions.refStorage", "reftable");
++ }
++
+ if (!(flags & INIT_DB_QUIET)) {
+ int len = strlen(git_dir);
+
+@@
+ const char *template_dir = NULL;
+ unsigned int flags = 0;
+ const struct option init_db_options[] = {
+- OPT_STRING(0, "template", &template_dir, N_("template-directory"),
+- N_("directory from which templates will be used")),
++ OPT_STRING(0, "template", &template_dir,
++ N_("template-directory"),
++ N_("directory from which templates will be used")),
+ OPT_SET_INT(0, "bare", &is_bare_repository_cfg,
+- N_("create a bare repository"), 1),
++ N_("create a bare repository"), 1),
+ { OPTION_CALLBACK, 0, "shared", &init_shared_repository,
+- N_("permissions"),
+- N_("specify that the git repository is to be shared amongst several users"),
+- PARSE_OPT_OPTARG | PARSE_OPT_NONEG, shared_callback, 0},
++ N_("permissions"),
++ N_("specify that the git repository is to be shared amongst several users"),
++ PARSE_OPT_OPTARG | PARSE_OPT_NONEG, shared_callback, 0 },
+ OPT_BIT('q', "quiet", &flags, N_("be quiet"), INIT_DB_QUIET),
++ OPT_BIT(0, "reftable", &flags, N_("use reftable"),
++ INIT_DB_REFTABLE),
+ OPT_STRING(0, "separate-git-dir", &real_git_dir, N_("gitdir"),
+ N_("separate git dir from working tree")),
+ OPT_END()
+
+ diff --git a/cache.h b/cache.h
+ --- a/cache.h
+ +++ b/cache.h
+@@
+
+ #define INIT_DB_QUIET 0x0001
+ #define INIT_DB_EXIST_OK 0x0002
++#define INIT_DB_REFTABLE 0x0004
+
+ int init_db(const char *git_dir, const char *real_git_dir,
+ const char *template_dir, unsigned int flags);
+@@
+ int is_bare;
+ int hash_algo;
+ char *work_tree;
++ char *ref_storage;
+ struct string_list unknown_extensions;
+ };
+
+
diff --git a/refs.c b/refs.c
--- a/refs.c
+++ b/refs.c
@@ -119,43 +229,65 @@ $^
static struct ref_storage_be *find_ref_storage_backend(const char *name)
{
@@
- static struct ref_store *ref_store_init(const char *gitdir,
+ * Create, record, and return a ref_store instance for the specified
+ * gitdir.
+ */
+-static struct ref_store *ref_store_init(const char *gitdir,
++static struct ref_store *ref_store_init(const char *gitdir, const char *be_name,
unsigned int flags)
{
- const char *be_name = "files";
- struct ref_storage_be *be = find_ref_storage_backend(be_name);
-+ struct strbuf refs_path = STRBUF_INIT;
-+
-+ /* XXX this should probably come from a git config setting and not
-+ default to reftable. */
-+ const char *be_name = "reftable";
+ struct ref_storage_be *be;
struct ref_store *refs;
-+ strbuf_addstr(&refs_path, gitdir);
-+ strbuf_addstr(&refs_path, "/refs");
-+
-+ if (!is_directory(refs_path.buf)) {
-+ be_name = "reftable";
-+ }
-+ strbuf_release(&refs_path);
+ be = find_ref_storage_backend(be_name);
if (!be)
BUG("reference backend %s is unknown", be_name);
-
- diff --git a/refs.h b/refs.h
- --- a/refs.h
- +++ b/refs.h
@@
- const char *refname,
- each_reflog_ent_fn fn,
- void *cb_data);
-+
-+/* XXX which ordering are these? Newest or oldest first? */
- int for_each_reflog_ent(const char *refname, each_reflog_ent_fn fn, void *cb_data);
- int for_each_reflog_ent_reverse(const char *refname, each_reflog_ent_fn fn, void *cb_data);
+ if (!r->gitdir)
+ BUG("attempting to get main_ref_store outside of repository");
+- r->refs = ref_store_init(r->gitdir, REF_STORE_ALL_CAPS);
++ r->refs = ref_store_init(r->gitdir,
++ /* XXX r->ref_storage_format == NULL. Where
++ * should the config file be parsed out? */
++ r->ref_storage_format ? r->ref_storage_format :
++ "reftable",
++ REF_STORE_ALL_CAPS);
+ return r->refs;
+ }
+
+@@
+ goto done;
+
+ /* assume that add_submodule_odb() has been called */
+- refs = ref_store_init(submodule_sb.buf,
++ refs = ref_store_init(submodule_sb.buf, "files", /* XXX */
+ REF_STORE_READ | REF_STORE_ODB);
+ register_ref_store_map(&submodule_ref_stores, "submodule",
+ refs, submodule);
+@@
+
+ struct ref_store *get_worktree_ref_store(const struct worktree *wt)
+ {
++ const char *format = "files"; /* XXX */
+ struct ref_store *refs;
+ const char *id;
+
+@@
+
+ if (wt->id)
+ refs = ref_store_init(git_common_path("worktrees/%s", wt->id),
+- REF_STORE_ALL_CAPS);
++ format, REF_STORE_ALL_CAPS);
+ else
+- refs = ref_store_init(get_git_common_dir(),
++ refs = ref_store_init(get_git_common_dir(), format,
+ REF_STORE_ALL_CAPS);
+
+ if (refs)
diff --git a/refs/refs-internal.h b/refs/refs-internal.h
--- a/refs/refs-internal.h
@@ -184,6 +316,11 @@ $^
+
+#include "../reftable/reftable.h"
+
++/*
++ The reftable v1 spec only supports 20-byte binary SHA1s. A new format version
++ will be needed to support SHA256.
++ */
++
+extern struct ref_storage_be refs_be_reftable;
+
+struct reftable_ref_store {
@@ -244,16 +381,28 @@ $^
+ base_ref_store_init(ref_store, &refs_be_reftable);
+ refs->store_flags = store_flags;
+
-+ strbuf_addf(&sb, "%s/refs", path);
-+ refs->table_list_file = xstrdup(sb.buf);
-+ strbuf_reset(&sb);
+ strbuf_addf(&sb, "%s/reftable", path);
+ refs->reftable_dir = xstrdup(sb.buf);
-+ strbuf_release(&sb);
++ strbuf_reset(&sb);
++
++ strbuf_addf(&sb, "%s/reftable/tables.list", path);
++ refs->table_list_file = xstrdup(sb.buf);
++ strbuf_reset(&sb);
++
++ strbuf_addf(&sb, "%s/refs", path);
++ safe_create_dir(sb.buf, 1);
++ strbuf_reset(&sb);
++
++ strbuf_addf(&sb, "%s/HEAD", path);
++ write_file(sb.buf, "ref: refs/.invalid");
++ strbuf_reset(&sb);
++
++ strbuf_addf(&sb, "%s/refs/heads", path);
++ write_file(sb.buf, "this repository uses the reftable format");
+
+ refs->err = new_stack(&refs->stack, refs->reftable_dir,
+ refs->table_list_file, cfg);
-+
++ strbuf_release(&sb);
+ return ref_store;
+}
+
@@ -261,13 +410,13 @@ $^
+{
+ struct reftable_ref_store *refs =
+ (struct reftable_ref_store *)ref_store;
++
++ safe_create_dir(refs->reftable_dir, 1);
+ FILE *f = fopen(refs->table_list_file, "a");
+ if (f == NULL) {
+ return -1;
+ }
+ fclose(f);
-+
-+ safe_create_dir(refs->reftable_dir, 1);
+ return 0;
+}
+
@@ -277,31 +426,33 @@ $^
+ struct ref_record ref;
+ struct object_id oid;
+ struct ref_store *ref_store;
++ unsigned int flags;
++ int err;
+ char *prefix;
+};
+
+static int reftable_ref_iterator_advance(struct ref_iterator *ref_iterator)
+{
-+ while (1) {
-+ struct reftable_iterator *ri =
-+ (struct reftable_iterator *)ref_iterator;
-+ int err = iterator_next_ref(ri->iter, &ri->ref);
-+ if (err > 0) {
-+ return ITER_DONE;
-+ }
-+ if (err < 0) {
-+ return ITER_ERROR;
++ struct reftable_iterator *ri = (struct reftable_iterator *)ref_iterator;
++ while (ri->err == 0) {
++ ri->err = iterator_next_ref(ri->iter, &ri->ref);
++ if (ri->err) {
++ break;
+ }
+
+ ri->base.refname = ri->ref.ref_name;
+ if (ri->prefix != NULL &&
+ strncmp(ri->prefix, ri->ref.ref_name, strlen(ri->prefix))) {
-+ return ITER_DONE;
++ ri->err = 1;
++ break;
+ }
++ if (ri->flags & DO_FOR_EACH_PER_WORKTREE_ONLY &&
++ ref_type(ri->base.refname) != REF_TYPE_PER_WORKTREE)
++ continue;
+
+ ri->base.flags = 0;
+ if (ri->ref.value != NULL) {
-+ memcpy(ri->oid.hash, ri->ref.value, GIT_SHA1_RAWSZ);
++ hashcpy(ri->oid.hash, ri->ref.value);
+ } else if (ri->ref.target != NULL) {
+ int out_flags = 0;
+ const char *resolved = refs_resolve_ref_unsafe(
@@ -309,14 +460,30 @@ $^
+ RESOLVE_REF_READING, &ri->oid, &out_flags);
+ ri->base.flags = out_flags;
+ if (resolved == NULL &&
-+ !(ri->base.flags & DO_FOR_EACH_INCLUDE_BROKEN) &&
++ !(ri->flags & DO_FOR_EACH_INCLUDE_BROKEN) &&
+ (ri->base.flags & REF_ISBROKEN)) {
+ continue;
+ }
+ }
++
+ ri->base.oid = &ri->oid;
-+ return ITER_OK;
++ if (!(ri->flags & DO_FOR_EACH_INCLUDE_BROKEN) &&
++ !ref_resolves_to_object(ri->base.refname, ri->base.oid,
++ ri->base.flags)) {
++ continue;
++ }
++
++ break;
++ }
++
++ if (ri->err > 0) {
++ return ITER_DONE;
+ }
++ if (ri->err < 0) {
++ return ITER_ERROR;
++ }
++
++ return ITER_OK;
+}
+
+static int reftable_ref_iterator_peel(struct ref_iterator *ref_iterator,
@@ -324,7 +491,7 @@ $^
+{
+ struct reftable_iterator *ri = (struct reftable_iterator *)ref_iterator;
+ if (ri->ref.target_value != NULL) {
-+ memcpy(peeled->hash, ri->ref.target_value, GIT_SHA1_RAWSZ);
++ hashcpy(peeled->hash, ri->ref.target_value);
+ return 0;
+ }
+
@@ -352,20 +519,15 @@ $^
+ (struct reftable_ref_store *)ref_store;
+ struct reftable_iterator *ri = xcalloc(1, sizeof(*ri));
+ struct merged_table *mt = NULL;
-+ int err = 0;
-+ if (refs->err) {
-+ /* how to propagate errors? */
-+ return NULL;
-+ }
+
+ mt = stack_merged_table(refs->stack);
-+
-+ /* XXX something with flags? */
-+ err = merged_table_seek_ref(mt, &ri->iter, prefix);
-+ /* XXX what to do with err? */
-+ assert(err == 0);
++ ri->err = refs->err;
++ if (ri->err == 0) {
++ ri->err = merged_table_seek_ref(mt, &ri->iter, prefix);
++ }
+ base_ref_iterator_init(&ri->base, &reftable_ref_iterator_vtable, 1);
+ ri->base.oid = &ri->oid;
++ ri->flags = flags;
+ ri->ref_store = ref_store;
+ return &ri->base;
+}
@@ -387,12 +549,6 @@ $^
+ return 0;
+}
+
-+static int ref_update_cmp(const void *a, const void *b)
-+{
-+ return strcmp(((struct ref_update *)a)->refname,
-+ ((struct ref_update *)b)->refname);
-+}
-+
+static int reftable_check_old_oid(struct ref_store *refs, const char *refname,
+ struct object_id *want_oid)
+{
@@ -411,6 +567,12 @@ $^
+ return 0;
+}
+
++static int ref_update_cmp(const void *a, const void *b)
++{
++ return strcmp(((struct ref_update *)a)->refname,
++ ((struct ref_update *)b)->refname);
++}
++
+static int write_transaction_table(struct writer *writer, void *arg)
+{
+ struct ref_transaction *transaction = (struct ref_transaction *)arg;
@@ -418,13 +580,14 @@ $^
+ (struct reftable_ref_store *)transaction->ref_store;
+ uint64_t ts = stack_next_update_index(refs->stack);
+ int err = 0;
-+ /* XXX - are we allowed to mutate the input data? */
-+ qsort(transaction->updates, transaction->nr,
-+ sizeof(struct ref_update *), ref_update_cmp);
++ struct ref_update **sorted =
++ malloc(transaction->nr * sizeof(struct ref_update *));
++ COPY_ARRAY(sorted, transaction->updates, transaction->nr);
++ QSORT(sorted, transaction->nr, ref_update_cmp);
+ writer_set_limits(writer, ts, ts);
+
+ for (int i = 0; i < transaction->nr; i++) {
-+ struct ref_update *u = transaction->updates[i];
++ struct ref_update *u = sorted[i];
+ if (u->flags & REF_HAVE_OLD) {
+ err = reftable_check_old_oid(transaction->ref_store,
+ u->refname, &u->old_oid);
@@ -435,11 +598,12 @@ $^
+ }
+
+ for (int i = 0; i < transaction->nr; i++) {
-+ struct ref_update *u = transaction->updates[i];
++ struct ref_update *u = sorted[i];
+ if (u->flags & REF_HAVE_NEW) {
+ struct object_id out_oid = {};
+ int out_flags = 0;
-+ /* XXX who owns the memory here? */
++ /* Memory owned by refs_resolve_ref_unsafe, no need to
++ * free(). */
+ const char *resolved = refs_resolve_ref_unsafe(
+ transaction->ref_store, u->refname, 0, &out_oid,
+ &out_flags);
@@ -456,7 +620,7 @@ $^
+ }
+
+ for (int i = 0; i < transaction->nr; i++) {
-+ struct ref_update *u = transaction->updates[i];
++ struct ref_update *u = sorted[i];
+ struct log_record log = {};
+ fill_log_record(&log);
+
@@ -473,6 +637,7 @@ $^
+ }
+ }
+exit:
++ free(sorted);
+ return err;
+}
+
@@ -527,16 +692,21 @@ $^
+
+ for (int i = 0; i < arg->refnames->nr; i++) {
+ struct log_record log = {};
++ struct ref_record current = {};
+ fill_log_record(&log);
+ log.message = xstrdup(arg->logmsg);
+ log.new_hash = NULL;
-+
-+ /* XXX should lookup old oid. */
+ log.old_hash = NULL;
+ log.update_index = ts;
+ log.ref_name = (char *)arg->refnames->items[i].string;
+
++ if (stack_read_ref(arg->stack, log.ref_name, ¤t) == 0) {
++ log.old_hash = current.value;
++ }
+ err = writer_add_log(writer, &log);
++ log.old_hash = NULL;
++ ref_record_clear(¤t);
++
+ clear_log_record(&log);
+ if (err < 0) {
+ return err;
@@ -564,12 +734,11 @@ $^
+{
+ struct reftable_ref_store *refs =
+ (struct reftable_ref_store *)ref_store;
-+ /* XXX reflog expiry. */
+ return stack_compact_all(refs->stack, NULL);
+}
+
+struct write_create_symref_arg {
-+ struct stack *stack;
++ struct reftable_ref_store *refs;
+ const char *refname;
+ const char *target;
+ const char *logmsg;
@@ -579,7 +748,7 @@ $^
+{
+ struct write_create_symref_arg *create =
+ (struct write_create_symref_arg *)arg;
-+ uint64_t ts = stack_next_update_index(create->stack);
++ uint64_t ts = stack_next_update_index(create->refs->stack);
+ int err = 0;
+
+ struct ref_record ref = {
@@ -593,8 +762,36 @@ $^
+ return err;
+ }
+
-+ /* XXX reflog? */
++ {
++ struct log_record log = {};
++ struct object_id new_oid = {};
++ struct object_id old_oid = {};
++ struct ref_record current = {};
++ stack_read_ref(create->refs->stack, create->refname, ¤t);
++
++ fill_log_record(&log);
++ log.ref_name = current.ref_name;
++ if (refs_resolve_ref_unsafe(
++ (struct ref_store *)create->refs, create->refname,
++ RESOLVE_REF_READING, &old_oid, NULL) != NULL) {
++ log.old_hash = old_oid.hash;
++ }
++
++ /* XXX should the resolution be done relative or absolute? */
++ if (refs_resolve_ref_unsafe((struct ref_store *)create->refs,
++ create->target, RESOLVE_REF_READING,
++ &new_oid, NULL) != NULL) {
++ log.new_hash = new_oid.hash;
++ }
+
++ if (log.old_hash != NULL || log.new_hash != NULL) {
++ writer_add_log(writer, &log);
++ }
++ log.ref_name = NULL;
++ log.old_hash = NULL;
++ log.new_hash = NULL;
++ clear_log_record(&log);
++ }
+ return 0;
+}
+
@@ -604,7 +801,7 @@ $^
+{
+ struct reftable_ref_store *refs =
+ (struct reftable_ref_store *)ref_store;
-+ struct write_create_symref_arg arg = { .stack = refs->stack,
++ struct write_create_symref_arg arg = { .refs = refs,
+ .refname = refname,
+ .target = target,
+ .logmsg = logmsg };
@@ -628,7 +825,11 @@ $^
+ goto exit;
+ }
+
-+ /* XXX should check that dest doesn't exist? */
++ /* XXX do ref renames overwrite the target? */
++ if (stack_read_ref(arg->stack, arg->newname, &ref) == 0) {
++ goto exit;
++ }
++
+ free(ref.ref_name);
+ ref.ref_name = strdup(arg->newname);
+ writer_set_limits(writer, ts, ts);
@@ -638,6 +839,7 @@ $^
+ struct ref_record todo[2] = {};
+ todo[0].ref_name = (char *)arg->oldname;
+ todo[0].update_index = ts;
++ /* leave todo[0] empty */
+ todo[1] = ref;
+ todo[1].update_index = ts;
+
@@ -735,8 +937,7 @@ $^
+
+ free(ri->last_name);
+ ri->last_name = xstrdup(ri->log.ref_name);
-+ /* XXX const? */
-+ memcpy(&ri->oid.hash, ri->log.new_hash, GIT_SHA1_RAWSZ);
++ hashcpy(ri->oid.hash, ri->log.new_hash);
+ return ITER_OK;
+ }
+}
@@ -808,12 +1009,16 @@ $^
+ {
+ struct object_id old_oid = {};
+ struct object_id new_oid = {};
++ const char *full_committer = "";
+
-+ memcpy(&old_oid.hash, log.old_hash, GIT_SHA1_RAWSZ);
-+ memcpy(&new_oid.hash, log.new_hash, GIT_SHA1_RAWSZ);
++ hashcpy(old_oid.hash, log.old_hash);
++ hashcpy(new_oid.hash, log.new_hash);
+
-+ /* XXX committer = email? name? */
-+ if (fn(&old_oid, &new_oid, log.name, log.time,
++ full_committer = fmt_ident(log.name, log.email,
++ WANT_COMMITTER_IDENT,
++ /*date*/ NULL,
++ IDENT_NO_DATE);
++ if (fn(&old_oid, &new_oid, full_committer, log.time,
+ log.tz_offset, log.message, cb_data)) {
+ err = -1;
+ break;
@@ -844,7 +1049,6 @@ $^
+ int cap = 0;
+ int len = 0;
+
-+ printf("oldest first\n");
+ while (err == 0) {
+ struct log_record log = {};
+ err = iterator_next_log(it, &log);
@@ -868,12 +1072,15 @@ $^
+ struct log_record *log = &logs[i];
+ struct object_id old_oid = {};
+ struct object_id new_oid = {};
++ const char *full_committer = "";
+
-+ memcpy(&old_oid.hash, log->old_hash, GIT_SHA1_RAWSZ);
-+ memcpy(&new_oid.hash, log->new_hash, GIT_SHA1_RAWSZ);
++ hashcpy(old_oid.hash, log->old_hash);
++ hashcpy(new_oid.hash, log->new_hash);
+
-+ /* XXX committer = email? name? */
-+ if (!fn(&old_oid, &new_oid, log->name, log->time,
++ full_committer = fmt_ident(log->name, log->email,
++ WANT_COMMITTER_IDENT, NULL,
++ IDENT_NO_DATE);
++ if (!fn(&old_oid, &new_oid, full_committer, log->time,
+ log->tz_offset, log->message, cb_data)) {
+ err = -1;
+ break;
@@ -921,18 +1128,11 @@ $^
+ reflog_expiry_cleanup_fn cleanup_fn,
+ void *policy_cb_data)
+{
++ BUG("per ref reflog expiry is not implemented for reftable backend.");
+ /*
-+ XXX
-+
-+ This doesn't fit with the reftable API. If we are expiring for space
-+ reasons, the expiry should be combined with a compaction, and there
-+ should be a policy that can be called for all refnames, not for a
-+ single ref name.
-+
-+ If this is for cleaning up individual entries, we'll have to write
-+ extra data to create tombstones.
++ TODO: should iterate over the reflog, and write tombstones. The
++ tombstones will be removed on compaction.
+ */
-+ return 0;
+}
+
+static int reftable_read_raw_ref(struct ref_store *ref_store,
@@ -947,13 +1147,13 @@ $^
+ goto exit;
+ }
+ if (ref.target != NULL) {
++ /* XXX recurse? */
+ strbuf_reset(referent);
+ strbuf_addstr(referent, ref.target);
+ *type |= REF_ISSYMREF;
+ } else {
-+ memcpy(oid->hash, ref.value, GIT_SHA1_RAWSZ);
++ hashcpy(oid->hash, ref.value);
+ }
-+
+exit:
+ ref_record_clear(&ref);
+ return err;
@@ -986,3 +1186,58 @@ $^
+ reftable_delete_reflog,
+ reftable_reflog_expire
+};
+
+ diff --git a/repository.c b/repository.c
+ --- a/repository.c
+ +++ b/repository.c
+@@
+ if (worktree)
+ repo_set_worktree(repo, worktree);
+
++ repo->ref_storage_format = format.ref_storage != NULL ?
++ xstrdup(format.ref_storage) :
++ "files"; /* XXX */
++
+ clear_repository_format(&format);
+ return 0;
+
+
+ diff --git a/repository.h b/repository.h
+ --- a/repository.h
+ +++ b/repository.h
+@@
+ /* The store in which the refs are held. */
+ struct ref_store *refs;
+
++ /* The format to use for the ref database. */
++ char *ref_storage_format;
++
+ /*
+ * Contains path to often used file names.
+ */
+
+ diff --git a/setup.c b/setup.c
+ --- a/setup.c
+ +++ b/setup.c
+@@
+ if (!value)
+ return config_error_nonbool(var);
+ data->partial_clone = xstrdup(value);
+- } else if (!strcmp(ext, "worktreeconfig"))
++ } else if (!strcmp(ext, "worktreeconfig")) {
+ data->worktree_config = git_config_bool(var, value);
+- else
++ } else if (!strcmp(ext, "refStorage")) {
++ data->ref_storage = xstrdup(value);
++ } else
+ string_list_append(&data->unknown_extensions, ext);
+ }
+
+@@
+ string_list_clear(&format->unknown_extensions, 0);
+ free(format->work_tree);
+ free(format->partial_clone);
++ free(format->ref_storage);
+ init_repository_format(format);
+ }
+
--
gitgitgadget
next prev parent reply other threads:[~2020-02-04 20:27 UTC|newest]
Thread overview: 409+ messages / expand[flat|nested] mbox.gz Atom feed top
2020-01-23 19:41 [PATCH 0/5] Reftable support git-core Han-Wen Nienhuys via GitGitGadget
2020-01-23 19:41 ` [PATCH 1/5] setup.c: enable repo detection for reftable Han-Wen Nienhuys via GitGitGadget
2020-01-23 19:41 ` [PATCH 2/5] create .git/refs in files-backend.c Han-Wen Nienhuys via GitGitGadget
2020-01-23 19:41 ` [PATCH 3/5] Document how ref iterators and symrefs interact Han-Wen Nienhuys via GitGitGadget
2020-01-23 19:41 ` [PATCH 4/5] Add reftable library Han-Wen Nienhuys via GitGitGadget
2020-01-23 19:41 ` [PATCH 5/5] Reftable support for git-core Han-Wen Nienhuys via GitGitGadget
2020-01-23 21:44 ` [PATCH 0/5] Reftable support git-core Junio C Hamano
2020-01-27 13:52 ` Han-Wen Nienhuys
2020-01-27 13:57 ` Han-Wen Nienhuys
2020-01-23 22:45 ` Stephan Beyer
2020-01-27 13:57 ` Han-Wen Nienhuys
2020-01-27 14:22 ` [PATCH v2 " Han-Wen Nienhuys via GitGitGadget
2020-01-27 14:22 ` [PATCH v2 1/5] setup.c: enable repo detection for reftable Han-Wen Nienhuys via GitGitGadget
2020-01-27 14:22 ` [PATCH v2 2/5] create .git/refs in files-backend.c Han-Wen Nienhuys via GitGitGadget
2020-01-27 22:28 ` Junio C Hamano
2020-01-28 15:58 ` Han-Wen Nienhuys
2020-01-30 4:19 ` Junio C Hamano
2020-01-27 14:22 ` [PATCH v2 3/5] Document how ref iterators and symrefs interact Han-Wen Nienhuys via GitGitGadget
2020-01-27 22:53 ` Junio C Hamano
2020-01-28 16:07 ` Han-Wen Nienhuys
2020-01-28 19:35 ` Junio C Hamano
2020-01-27 14:22 ` [PATCH v2 4/5] Add reftable library Han-Wen Nienhuys via GitGitGadget
2020-01-27 14:22 ` [PATCH v2 5/5] Reftable support for git-core Han-Wen Nienhuys via GitGitGadget
2020-01-28 7:31 ` Jeff King
2020-01-28 15:36 ` Martin Fick
2020-01-29 8:12 ` Jeff King
2020-01-29 16:49 ` Martin Fick
2020-01-29 18:40 ` Han-Wen Nienhuys
2020-01-29 19:47 ` Martin Fick
2020-01-29 19:50 ` Han-Wen Nienhuys
2020-01-30 7:21 ` Jeff King
2020-02-03 16:39 ` Han-Wen Nienhuys
2020-02-03 17:05 ` Jeff King
2020-02-03 17:09 ` Han-Wen Nienhuys
2020-02-04 18:54 ` Han-Wen Nienhuys
2020-02-04 20:06 ` Jeff King
2020-02-04 20:26 ` Han-Wen Nienhuys
2020-01-29 18:34 ` Junio C Hamano
2020-01-28 15:56 ` Han-Wen Nienhuys
2020-01-29 10:47 ` Jeff King
2020-01-29 18:43 ` Junio C Hamano
2020-01-29 18:53 ` Han-Wen Nienhuys
2020-01-30 7:26 ` Jeff King
2020-02-04 19:06 ` Han-Wen Nienhuys
2020-02-04 19:54 ` Jeff King
2020-02-04 20:22 ` Han-Wen Nienhuys
2020-02-04 22:13 ` Jeff King
2020-02-04 20:27 ` Han-Wen Nienhuys via GitGitGadget [this message]
2020-02-04 20:27 ` [PATCH v3 1/6] refs.h: clarify reflog iteration order Han-Wen Nienhuys via GitGitGadget
2020-02-04 20:27 ` [PATCH v3 2/6] setup.c: enable repo detection for reftable Han-Wen Nienhuys via GitGitGadget
2020-02-04 20:31 ` Han-Wen Nienhuys
2020-02-04 20:27 ` [PATCH v3 3/6] create .git/refs in files-backend.c Han-Wen Nienhuys via GitGitGadget
2020-02-04 21:29 ` Junio C Hamano
2020-02-05 11:34 ` Han-Wen Nienhuys
2020-02-05 11:42 ` SZEDER Gábor
2020-02-05 12:24 ` Jeff King
2020-02-04 20:27 ` [PATCH v3 4/6] refs: document how ref_iterator_advance_fn should handle symrefs Han-Wen Nienhuys via GitGitGadget
2020-02-04 20:27 ` [PATCH v3 5/6] Add reftable library Han-Wen Nienhuys via GitGitGadget
2020-02-04 20:27 ` [PATCH v3 6/6] Reftable support for git-core Han-Wen Nienhuys via GitGitGadget
2020-02-06 22:55 ` [PATCH v4 0/5] Reftable support git-core Han-Wen Nienhuys via GitGitGadget
2020-02-06 22:55 ` [PATCH v4 1/5] refs.h: clarify reflog iteration order Han-Wen Nienhuys via GitGitGadget
2020-02-06 22:55 ` [PATCH v4 2/5] create .git/refs in files-backend.c Han-Wen Nienhuys via GitGitGadget
2020-02-06 22:55 ` [PATCH v4 3/5] refs: document how ref_iterator_advance_fn should handle symrefs Han-Wen Nienhuys via GitGitGadget
2020-02-06 22:55 ` [PATCH v4 4/5] Add reftable library Han-Wen Nienhuys via GitGitGadget
2020-02-06 23:07 ` Junio C Hamano
2020-02-07 0:16 ` brian m. carlson
2020-02-10 13:16 ` Han-Wen Nienhuys
2020-02-11 0:05 ` brian m. carlson
2020-02-11 14:20 ` Han-Wen Nienhuys
2020-02-11 16:31 ` Junio C Hamano
2020-02-11 16:40 ` Han-Wen Nienhuys
2020-02-11 23:40 ` brian m. carlson
2020-02-18 9:25 ` Han-Wen Nienhuys
2020-02-11 16:46 ` Han-Wen Nienhuys
2020-02-20 17:20 ` Jonathan Nieder
2020-02-06 22:55 ` [PATCH v4 5/5] Reftable support for git-core Han-Wen Nienhuys via GitGitGadget
2020-02-06 23:49 ` brian m. carlson
2020-02-10 13:18 ` Han-Wen Nienhuys
2020-02-06 23:31 ` [PATCH v4 0/5] Reftable support git-core brian m. carlson
2020-02-10 14:14 ` [PATCH v5 " Han-Wen Nienhuys via GitGitGadget
2020-02-10 14:14 ` [PATCH v5 1/5] refs.h: clarify reflog iteration order Han-Wen Nienhuys via GitGitGadget
2020-02-10 14:14 ` [PATCH v5 2/5] create .git/refs in files-backend.c Han-Wen Nienhuys via GitGitGadget
2020-02-10 14:14 ` [PATCH v5 3/5] refs: document how ref_iterator_advance_fn should handle symrefs Han-Wen Nienhuys via GitGitGadget
2020-02-10 14:14 ` [PATCH v5 4/5] Add reftable library Han-Wen Nienhuys via GitGitGadget
2020-02-10 14:14 ` [PATCH v5 5/5] Reftable support for git-core Han-Wen Nienhuys via GitGitGadget
2020-02-18 8:43 ` [PATCH v6 0/5] Reftable support git-core Han-Wen Nienhuys via GitGitGadget
2020-02-18 8:43 ` [PATCH v6 1/5] refs.h: clarify reflog iteration order Han-Wen Nienhuys via GitGitGadget
2020-02-18 8:43 ` [PATCH v6 2/5] create .git/refs in files-backend.c Han-Wen Nienhuys via GitGitGadget
2020-02-18 8:43 ` [PATCH v6 3/5] refs: document how ref_iterator_advance_fn should handle symrefs Han-Wen Nienhuys via GitGitGadget
2020-02-18 8:43 ` [PATCH v6 4/5] Add reftable library Han-Wen Nienhuys via GitGitGadget
2020-02-18 21:11 ` Junio C Hamano
2020-02-19 6:55 ` Jeff King
2020-02-19 17:00 ` Han-Wen Nienhuys
2020-02-18 8:43 ` [PATCH v6 5/5] Reftable support for git-core Han-Wen Nienhuys via GitGitGadget
2020-02-18 21:05 ` [PATCH v6 0/5] Reftable support git-core Junio C Hamano
2020-02-19 16:59 ` Han-Wen Nienhuys
2020-02-19 17:02 ` Junio C Hamano
2020-02-19 17:21 ` Han-Wen Nienhuys
2020-02-19 18:10 ` Junio C Hamano
2020-02-19 19:14 ` Han-Wen Nienhuys
2020-02-19 20:09 ` Junio C Hamano
2020-02-20 11:19 ` Jeff King
2020-02-21 6:40 ` Jonathan Nieder
2020-02-26 17:16 ` Han-Wen Nienhuys
2020-02-26 20:04 ` Junio C Hamano
2020-02-27 0:01 ` brian m. carlson
[not found] ` <CAFQ2z_NQn9O3kFmHk8Cr31FY66ToU4bUdE=asHUfN++zBG+SPw@mail.gmail.com>
2020-02-26 17:41 ` Jonathan Nieder
2020-02-26 17:54 ` Han-Wen Nienhuys
2020-02-26 8:49 ` [PATCH v7 0/6] " Han-Wen Nienhuys via GitGitGadget
2020-02-26 8:49 ` [PATCH v7 1/6] refs.h: clarify reflog iteration order Han-Wen Nienhuys via GitGitGadget
2020-02-26 8:49 ` [PATCH v7 2/6] create .git/refs in files-backend.c Han-Wen Nienhuys via GitGitGadget
2020-02-26 8:49 ` [PATCH v7 3/6] refs: document how ref_iterator_advance_fn should handle symrefs Han-Wen Nienhuys via GitGitGadget
2020-02-26 8:49 ` [PATCH v7 4/6] reftable: file format documentation Jonathan Nieder via GitGitGadget
2020-02-26 8:49 ` [PATCH v7 5/6] Add reftable library Han-Wen Nienhuys via GitGitGadget
2020-02-26 8:49 ` [PATCH v7 6/6] Reftable support for git-core Han-Wen Nienhuys via GitGitGadget
2020-02-26 18:12 ` Junio C Hamano
2020-02-26 18:59 ` Han-Wen Nienhuys
2020-02-26 19:59 ` Junio C Hamano
2020-02-27 16:03 ` Han-Wen Nienhuys
2020-02-27 16:23 ` Junio C Hamano
2020-02-27 17:56 ` Han-Wen Nienhuys
2020-02-26 21:31 ` Junio C Hamano
2020-02-27 16:01 ` Han-Wen Nienhuys
2020-02-27 16:26 ` Junio C Hamano
2020-02-26 17:35 ` [PATCH v7 0/6] Reftable support git-core Junio C Hamano
2020-03-24 6:06 ` Jonathan Nieder
2020-04-01 11:28 ` [PATCH v8 0/9] " Han-Wen Nienhuys via GitGitGadget
2020-04-01 11:28 ` [PATCH v8 1/9] refs.h: clarify reflog iteration order Han-Wen Nienhuys via GitGitGadget
2020-04-01 11:28 ` [PATCH v8 2/9] create .git/refs in files-backend.c Han-Wen Nienhuys via GitGitGadget
2020-04-01 11:28 ` [PATCH v8 3/9] refs: document how ref_iterator_advance_fn should handle symrefs Han-Wen Nienhuys via GitGitGadget
2020-04-01 11:28 ` [PATCH v8 4/9] Add .gitattributes for the reftable/ directory Han-Wen Nienhuys via GitGitGadget
2020-04-01 11:28 ` [PATCH v8 5/9] reftable: file format documentation Jonathan Nieder via GitGitGadget
2020-04-01 11:28 ` [PATCH v8 6/9] reftable: define version 2 of the spec to accomodate SHA256 Han-Wen Nienhuys via GitGitGadget
2020-04-01 11:28 ` [PATCH v8 7/9] reftable: clarify how empty tables should be written Han-Wen Nienhuys via GitGitGadget
2020-04-01 11:28 ` [PATCH v8 8/9] Add reftable library Han-Wen Nienhuys via GitGitGadget
2020-04-01 11:28 ` [PATCH v8 9/9] Reftable support for git-core Han-Wen Nienhuys via GitGitGadget
2020-04-15 23:29 ` [PATCH v8 0/9] Reftable support git-core Junio C Hamano
2020-04-18 3:22 ` Danh Doan
2020-04-20 21:14 ` [PATCH v9 00/10] " Han-Wen Nienhuys via GitGitGadget
2020-04-20 21:14 ` [PATCH v9 01/10] refs.h: clarify reflog iteration order Han-Wen Nienhuys via GitGitGadget
2020-04-20 21:14 ` [PATCH v9 02/10] Iterate over the "refs/" namespace in for_each_[raw]ref Han-Wen Nienhuys via GitGitGadget
2020-04-20 21:14 ` [PATCH v9 03/10] create .git/refs in files-backend.c Han-Wen Nienhuys via GitGitGadget
2020-04-20 21:14 ` [PATCH v9 04/10] refs: document how ref_iterator_advance_fn should handle symrefs Han-Wen Nienhuys via GitGitGadget
2020-04-20 21:14 ` [PATCH v9 05/10] Add .gitattributes for the reftable/ directory Han-Wen Nienhuys via GitGitGadget
2020-04-20 21:14 ` [PATCH v9 06/10] reftable: file format documentation Jonathan Nieder via GitGitGadget
2020-04-20 21:14 ` [PATCH v9 07/10] reftable: define version 2 of the spec to accomodate SHA256 Han-Wen Nienhuys via GitGitGadget
2020-04-20 21:14 ` [PATCH v9 08/10] reftable: clarify how empty tables should be written Han-Wen Nienhuys via GitGitGadget
2020-04-20 21:14 ` [PATCH v9 09/10] Add reftable library Han-Wen Nienhuys via GitGitGadget
2020-04-20 22:06 ` Junio C Hamano
2020-04-21 19:04 ` Han-Wen Nienhuys
2020-04-22 17:35 ` Johannes Schindelin
2020-04-20 21:14 ` [PATCH v9 10/10] Reftable support for git-core Han-Wen Nienhuys via GitGitGadget
2020-04-21 20:13 ` [PATCH v9 00/10] Reftable support git-core Junio C Hamano
2020-04-23 21:27 ` Han-Wen Nienhuys
2020-04-23 21:43 ` Junio C Hamano
2020-04-23 21:52 ` Junio C Hamano
2020-04-25 13:58 ` Johannes Schindelin
2020-04-27 20:13 ` [PATCH v10 00/12] " Han-Wen Nienhuys via GitGitGadget
2020-04-27 20:13 ` [PATCH v10 01/12] refs.h: clarify reflog iteration order Han-Wen Nienhuys via GitGitGadget
2020-04-27 20:13 ` [PATCH v10 02/12] Iterate over the "refs/" namespace in for_each_[raw]ref Han-Wen Nienhuys via GitGitGadget
2020-04-30 21:17 ` Emily Shaffer
2020-05-04 18:03 ` Han-Wen Nienhuys
2020-05-05 18:26 ` Pseudo ref handling (was Re: [PATCH v10 02/12] Iterate over the "refs/" namespace in for_each_[raw]ref) Han-Wen Nienhuys
2020-04-27 20:13 ` [PATCH v10 03/12] create .git/refs in files-backend.c Han-Wen Nienhuys via GitGitGadget
2020-04-30 21:24 ` Emily Shaffer
2020-04-30 21:49 ` Junio C Hamano
2020-05-04 18:10 ` Han-Wen Nienhuys
2020-04-27 20:13 ` [PATCH v10 04/12] refs: document how ref_iterator_advance_fn should handle symrefs Han-Wen Nienhuys via GitGitGadget
2020-04-27 20:13 ` [PATCH v10 05/12] Add .gitattributes for the reftable/ directory Han-Wen Nienhuys via GitGitGadget
2020-04-27 20:13 ` [PATCH v10 06/12] reftable: file format documentation Jonathan Nieder via GitGitGadget
2020-04-27 20:13 ` [PATCH v10 07/12] reftable: define version 2 of the spec to accomodate SHA256 Han-Wen Nienhuys via GitGitGadget
2020-04-27 20:13 ` [PATCH v10 08/12] reftable: clarify how empty tables should be written Han-Wen Nienhuys via GitGitGadget
2020-04-27 20:13 ` [PATCH v10 09/12] Add reftable library Han-Wen Nienhuys via GitGitGadget
2020-04-28 14:55 ` Danh Doan
2020-04-28 15:29 ` Junio C Hamano
2020-04-28 15:31 ` Junio C Hamano
2020-04-28 20:21 ` Han-Wen Nienhuys
2020-04-28 20:23 ` Han-Wen Nienhuys
2020-04-27 20:13 ` [PATCH v10 10/12] Reftable support for git-core Han-Wen Nienhuys via GitGitGadget
2020-04-27 20:13 ` [PATCH v10 11/12] Add some reftable testing infrastructure Han-Wen Nienhuys via GitGitGadget
2020-04-27 20:13 ` [PATCH v10 12/12] t: use update-ref and show-ref to reading/writing refs Han-Wen Nienhuys via GitGitGadget
2020-05-04 19:03 ` [PATCH v11 00/12] Reftable support git-core Han-Wen Nienhuys via GitGitGadget
2020-05-04 19:03 ` [PATCH v11 01/12] refs.h: clarify reflog iteration order Han-Wen Nienhuys via GitGitGadget
2020-05-04 19:03 ` [PATCH v11 02/12] Iterate over the "refs/" namespace in for_each_[raw]ref Han-Wen Nienhuys via GitGitGadget
2020-05-04 19:03 ` [PATCH v11 03/12] refs: document how ref_iterator_advance_fn should handle symrefs Han-Wen Nienhuys via GitGitGadget
2020-05-04 19:03 ` [PATCH v11 04/12] Add .gitattributes for the reftable/ directory Han-Wen Nienhuys via GitGitGadget
2020-05-04 19:03 ` [PATCH v11 05/12] reftable: file format documentation Jonathan Nieder via GitGitGadget
2020-05-04 19:03 ` [PATCH v11 06/12] reftable: define version 2 of the spec to accomodate SHA256 Han-Wen Nienhuys via GitGitGadget
2020-05-04 19:03 ` [PATCH v11 07/12] reftable: clarify how empty tables should be written Han-Wen Nienhuys via GitGitGadget
2020-05-04 19:03 ` [PATCH v11 08/12] Add reftable library Han-Wen Nienhuys via GitGitGadget
2020-05-04 19:03 ` [PATCH v11 09/12] Reftable support for git-core Han-Wen Nienhuys via GitGitGadget
2020-05-04 19:03 ` [PATCH v11 10/12] vcxproj: adjust for the reftable changes Johannes Schindelin via GitGitGadget
2020-05-04 19:03 ` [PATCH v11 11/12] Add some reftable testing infrastructure Han-Wen Nienhuys via GitGitGadget
2020-05-04 19:03 ` [PATCH v11 12/12] t: use update-ref and show-ref to reading/writing refs Han-Wen Nienhuys via GitGitGadget
2020-05-06 4:29 ` [PATCH v11 00/12] Reftable support git-core Junio C Hamano
2020-05-07 9:59 ` [PATCH v12 " Han-Wen Nienhuys via GitGitGadget
2020-05-07 9:59 ` [PATCH v12 01/12] refs.h: clarify reflog iteration order Han-Wen Nienhuys via GitGitGadget
2020-05-08 18:54 ` Junio C Hamano
2020-05-07 9:59 ` [PATCH v12 02/12] Iterate over the "refs/" namespace in for_each_[raw]ref Han-Wen Nienhuys via GitGitGadget
2020-05-08 18:54 ` Junio C Hamano
2020-05-11 11:41 ` Han-Wen Nienhuys
2020-05-07 9:59 ` [PATCH v12 03/12] refs: document how ref_iterator_advance_fn should handle symrefs Han-Wen Nienhuys via GitGitGadget
2020-05-08 18:58 ` Junio C Hamano
2020-05-11 11:42 ` Han-Wen Nienhuys
2020-05-11 14:49 ` Junio C Hamano
2020-05-11 15:11 ` Han-Wen Nienhuys
2020-05-07 9:59 ` [PATCH v12 04/12] Add .gitattributes for the reftable/ directory Han-Wen Nienhuys via GitGitGadget
2020-05-07 9:59 ` [PATCH v12 05/12] reftable: file format documentation Jonathan Nieder via GitGitGadget
2020-05-07 9:59 ` [PATCH v12 06/12] reftable: define version 2 of the spec to accomodate SHA256 Han-Wen Nienhuys via GitGitGadget
2020-05-08 19:59 ` Junio C Hamano
2020-05-07 9:59 ` [PATCH v12 07/12] reftable: clarify how empty tables should be written Han-Wen Nienhuys via GitGitGadget
2020-05-07 9:59 ` [PATCH v12 08/12] Add reftable library Han-Wen Nienhuys via GitGitGadget
2020-05-07 9:59 ` [PATCH v12 09/12] Reftable support for git-core Han-Wen Nienhuys via GitGitGadget
2020-05-07 9:59 ` [PATCH v12 10/12] vcxproj: adjust for the reftable changes Johannes Schindelin via GitGitGadget
2020-05-07 9:59 ` [PATCH v12 11/12] t: use update-ref and show-ref to reading/writing refs Han-Wen Nienhuys via GitGitGadget
2020-05-07 9:59 ` [PATCH v12 12/12] Add some reftable testing infrastructure Han-Wen Nienhuys via GitGitGadget
2020-05-11 19:46 ` [PATCH v13 00/13] Reftable support git-core Han-Wen Nienhuys via GitGitGadget
2020-05-11 19:46 ` [PATCH v13 01/13] refs.h: clarify reflog iteration order Han-Wen Nienhuys via GitGitGadget
2020-05-18 23:31 ` Junio C Hamano
2020-05-11 19:46 ` [PATCH v13 02/13] t: use update-ref and show-ref to reading/writing refs Han-Wen Nienhuys via GitGitGadget
2020-05-18 23:34 ` Junio C Hamano
2020-05-11 19:46 ` [PATCH v13 03/13] refs: document how ref_iterator_advance_fn should handle symrefs Han-Wen Nienhuys via GitGitGadget
2020-05-18 23:43 ` Junio C Hamano
2020-05-11 19:46 ` [PATCH v13 04/13] reftable: file format documentation Jonathan Nieder via GitGitGadget
2020-05-19 22:00 ` Junio C Hamano
2020-05-20 16:06 ` Han-Wen Nienhuys
2020-05-20 17:20 ` Han-Wen Nienhuys
2020-05-20 17:25 ` Han-Wen Nienhuys
2020-05-20 17:33 ` Junio C Hamano
2020-05-20 18:52 ` Jonathan Nieder
2020-05-11 19:46 ` [PATCH v13 05/13] reftable: clarify how empty tables should be written Han-Wen Nienhuys via GitGitGadget
2020-05-19 22:01 ` Junio C Hamano
2020-05-11 19:46 ` [PATCH v13 06/13] reftable: define version 2 of the spec to accomodate SHA256 Han-Wen Nienhuys via GitGitGadget
2020-05-19 22:32 ` Junio C Hamano
2020-05-20 12:38 ` Han-Wen Nienhuys
2020-05-20 14:40 ` Junio C Hamano
2020-05-11 19:46 ` [PATCH v13 07/13] Write pseudorefs through ref backends Han-Wen Nienhuys via GitGitGadget
2020-05-12 10:22 ` Phillip Wood
2020-05-12 16:48 ` Han-Wen Nienhuys
2020-05-13 10:06 ` Phillip Wood
2020-05-13 18:10 ` Phillip Wood
2020-05-11 19:46 ` [PATCH v13 08/13] Iterate over the "refs/" namespace in for_each_[raw]ref Han-Wen Nienhuys via GitGitGadget
2020-05-11 19:46 ` [PATCH v13 09/13] Add .gitattributes for the reftable/ directory Han-Wen Nienhuys via GitGitGadget
2020-05-11 19:46 ` [PATCH v13 10/13] Add reftable library Han-Wen Nienhuys via GitGitGadget
2020-05-11 19:46 ` [PATCH v13 11/13] Reftable support for git-core Han-Wen Nienhuys via GitGitGadget
2020-05-13 19:55 ` Junio C Hamano
2020-05-11 19:46 ` [PATCH v13 12/13] vcxproj: adjust for the reftable changes Johannes Schindelin via GitGitGadget
2020-05-11 19:46 ` [PATCH v13 13/13] Add some reftable testing infrastructure Han-Wen Nienhuys via GitGitGadget
2020-05-13 19:57 ` Junio C Hamano
2020-05-19 13:54 ` Han-Wen Nienhuys
2020-05-19 15:21 ` Junio C Hamano
2020-05-12 0:41 ` [PATCH v13 00/13] Reftable support git-core Junio C Hamano
2020-05-12 7:49 ` Han-Wen Nienhuys
2020-05-13 21:21 ` Junio C Hamano
2020-05-18 20:31 ` [PATCH v14 0/9] " Han-Wen Nienhuys via GitGitGadget
2020-05-18 20:31 ` [PATCH v14 1/9] Write pseudorefs through ref backends Han-Wen Nienhuys via GitGitGadget
2020-05-18 20:31 ` [PATCH v14 2/9] Move REF_LOG_ONLY to refs-internal.h Han-Wen Nienhuys via GitGitGadget
2020-05-18 20:31 ` [PATCH v14 3/9] Iterate over the "refs/" namespace in for_each_[raw]ref Han-Wen Nienhuys via GitGitGadget
2020-05-18 20:31 ` [PATCH v14 4/9] Add .gitattributes for the reftable/ directory Han-Wen Nienhuys via GitGitGadget
2020-05-18 20:31 ` [PATCH v14 5/9] Add reftable library Han-Wen Nienhuys via GitGitGadget
2020-05-18 20:31 ` [PATCH v14 6/9] Reftable support for git-core Han-Wen Nienhuys via GitGitGadget
2020-05-18 20:31 ` [PATCH v14 7/9] Add GIT_DEBUG_REFS debugging mechanism Han-Wen Nienhuys via GitGitGadget
2020-05-18 20:31 ` [PATCH v14 8/9] vcxproj: adjust for the reftable changes Johannes Schindelin via GitGitGadget
2020-05-18 20:31 ` [PATCH v14 9/9] Add reftable testing infrastructure Han-Wen Nienhuys via GitGitGadget
2020-05-28 19:46 ` [PATCH v15 00/13] Reftable support git-core Han-Wen Nienhuys via GitGitGadget
2020-05-28 19:46 ` [PATCH v15 01/13] Write pseudorefs through ref backends Han-Wen Nienhuys via GitGitGadget
2020-05-28 19:46 ` [PATCH v15 02/13] Make refs_ref_exists public Han-Wen Nienhuys via GitGitGadget
2020-05-28 19:46 ` [PATCH v15 03/13] Treat BISECT_HEAD as a pseudo ref Han-Wen Nienhuys via GitGitGadget
2020-05-28 20:52 ` Junio C Hamano
2020-05-28 19:46 ` [PATCH v15 04/13] Treat CHERRY_PICK_HEAD " Han-Wen Nienhuys via GitGitGadget
2020-05-28 19:46 ` [PATCH v15 05/13] Treat REVERT_HEAD " Han-Wen Nienhuys via GitGitGadget
2020-05-28 19:46 ` [PATCH v15 06/13] Move REF_LOG_ONLY to refs-internal.h Han-Wen Nienhuys via GitGitGadget
2020-05-28 19:46 ` [PATCH v15 07/13] Iterate over the "refs/" namespace in for_each_[raw]ref Han-Wen Nienhuys via GitGitGadget
2020-05-28 19:46 ` [PATCH v15 08/13] Add .gitattributes for the reftable/ directory Han-Wen Nienhuys via GitGitGadget
2020-05-28 19:46 ` [PATCH v15 09/13] Add reftable library Han-Wen Nienhuys via GitGitGadget
2020-05-28 19:46 ` [PATCH v15 10/13] Reftable support for git-core Han-Wen Nienhuys via GitGitGadget
2020-05-28 19:46 ` [PATCH v15 11/13] Add GIT_DEBUG_REFS debugging mechanism Han-Wen Nienhuys via GitGitGadget
2020-05-28 19:46 ` [PATCH v15 12/13] vcxproj: adjust for the reftable changes Johannes Schindelin via GitGitGadget
2020-05-28 19:46 ` [PATCH v15 13/13] Add reftable testing infrastructure Han-Wen Nienhuys via GitGitGadget
2020-05-28 20:15 ` [PATCH v15 00/13] Reftable support git-core Junio C Hamano
2020-05-28 21:21 ` Junio C Hamano
2020-06-05 18:03 ` [PATCH v16 00/14] " Han-Wen Nienhuys via GitGitGadget
2020-06-05 18:03 ` [PATCH v16 01/14] Write pseudorefs through ref backends Han-Wen Nienhuys via GitGitGadget
2020-06-09 10:16 ` Phillip Wood
2020-06-05 18:03 ` [PATCH v16 02/14] Make refs_ref_exists public Han-Wen Nienhuys via GitGitGadget
2020-06-09 10:36 ` Phillip Wood
2020-06-10 18:05 ` Han-Wen Nienhuys
2020-06-11 14:59 ` Phillip Wood
2020-06-12 9:51 ` Phillip Wood
2020-06-15 11:32 ` Han-Wen Nienhuys
2020-06-05 18:03 ` [PATCH v16 03/14] Treat BISECT_HEAD as a pseudo ref Han-Wen Nienhuys via GitGitGadget
2020-06-05 18:03 ` [PATCH v16 04/14] Treat CHERRY_PICK_HEAD " Han-Wen Nienhuys via GitGitGadget
2020-06-05 18:03 ` [PATCH v16 05/14] Treat REVERT_HEAD " Han-Wen Nienhuys via GitGitGadget
2020-06-05 18:03 ` [PATCH v16 06/14] Move REF_LOG_ONLY to refs-internal.h Han-Wen Nienhuys via GitGitGadget
2020-06-05 18:03 ` [PATCH v16 07/14] Iterate over the "refs/" namespace in for_each_[raw]ref Han-Wen Nienhuys via GitGitGadget
2020-06-05 18:03 ` [PATCH v16 08/14] Add .gitattributes for the reftable/ directory Han-Wen Nienhuys via GitGitGadget
2020-06-05 18:03 ` [PATCH v16 09/14] Add reftable library Han-Wen Nienhuys via GitGitGadget
2020-06-05 18:03 ` [PATCH v16 10/14] Reftable support for git-core Han-Wen Nienhuys via GitGitGadget
2020-06-05 18:03 ` [PATCH v16 11/14] Hookup unittests for the reftable library Han-Wen Nienhuys via GitGitGadget
2020-06-08 19:39 ` Junio C Hamano
2020-06-09 17:22 ` [PATCH] Fixup! Add t/helper/test-reftable.c hanwen
2020-06-09 20:45 ` Junio C Hamano
2020-06-05 18:03 ` [PATCH v16 12/14] Add GIT_DEBUG_REFS debugging mechanism Han-Wen Nienhuys via GitGitGadget
2020-06-05 18:03 ` [PATCH v16 13/14] vcxproj: adjust for the reftable changes Johannes Schindelin via GitGitGadget
2020-06-05 18:03 ` [PATCH v16 14/14] Add reftable testing infrastructure Han-Wen Nienhuys via GitGitGadget
2020-06-09 23:14 ` [PATCH v16 00/14] Reftable support git-core Junio C Hamano
2020-06-10 6:56 ` Han-Wen Nienhuys
2020-06-10 17:09 ` Junio C Hamano
2020-06-10 17:38 ` Junio C Hamano
2020-06-10 18:59 ` Johannes Schindelin
2020-06-10 19:04 ` Han-Wen Nienhuys
2020-06-10 19:20 ` Johannes Schindelin
2020-06-10 16:57 ` Han-Wen Nienhuys
2020-06-16 19:20 ` [PATCH v17 00/17] " Han-Wen Nienhuys via GitGitGadget
2020-06-16 19:20 ` [PATCH v17 01/17] lib-t6000.sh: write tag using git-update-ref Han-Wen Nienhuys via GitGitGadget
2020-06-16 19:20 ` [PATCH v17 02/17] checkout: add '\n' to reflog message Han-Wen Nienhuys via GitGitGadget
2020-06-16 19:20 ` [PATCH v17 03/17] Write pseudorefs through ref backends Han-Wen Nienhuys via GitGitGadget
2020-06-16 19:20 ` [PATCH v17 04/17] Make refs_ref_exists public Han-Wen Nienhuys via GitGitGadget
2020-06-16 19:20 ` [PATCH v17 05/17] Treat BISECT_HEAD as a pseudo ref Han-Wen Nienhuys via GitGitGadget
2020-06-16 19:20 ` [PATCH v17 06/17] Treat CHERRY_PICK_HEAD " Han-Wen Nienhuys via GitGitGadget
2020-06-16 19:20 ` [PATCH v17 07/17] Treat REVERT_HEAD " Han-Wen Nienhuys via GitGitGadget
2020-06-16 19:20 ` [PATCH v17 08/17] Move REF_LOG_ONLY to refs-internal.h Han-Wen Nienhuys via GitGitGadget
2020-06-16 19:20 ` [PATCH v17 09/17] Iterate over the "refs/" namespace in for_each_[raw]ref Han-Wen Nienhuys via GitGitGadget
2020-06-16 19:20 ` [PATCH v17 10/17] Add .gitattributes for the reftable/ directory Han-Wen Nienhuys via GitGitGadget
2020-06-16 19:20 ` [PATCH v17 11/17] Add reftable library Han-Wen Nienhuys via GitGitGadget
2020-06-16 19:20 ` [PATCH v17 12/17] Reftable support for git-core Han-Wen Nienhuys via GitGitGadget
2020-06-19 14:24 ` SZEDER Gábor
2020-06-16 19:20 ` [PATCH v17 13/17] Hookup unittests for the reftable library Han-Wen Nienhuys via GitGitGadget
2020-06-16 19:20 ` [PATCH v17 14/17] Add GIT_DEBUG_REFS debugging mechanism Han-Wen Nienhuys via GitGitGadget
2020-06-16 19:20 ` [PATCH v17 15/17] vcxproj: adjust for the reftable changes Johannes Schindelin via GitGitGadget
2020-06-16 19:20 ` [PATCH v17 16/17] Add reftable testing infrastructure Han-Wen Nienhuys via GitGitGadget
2020-06-19 16:03 ` SZEDER Gábor
2020-06-16 19:20 ` [PATCH v17 17/17] Add "test-tool dump-reftable" command Han-Wen Nienhuys via GitGitGadget
2020-06-22 21:55 ` [PATCH v18 00/19] Reftable support git-core Han-Wen Nienhuys via GitGitGadget
2020-06-22 21:55 ` [PATCH v18 01/19] lib-t6000.sh: write tag using git-update-ref Han-Wen Nienhuys via GitGitGadget
2020-06-22 21:55 ` [PATCH v18 02/19] checkout: add '\n' to reflog message Han-Wen Nienhuys via GitGitGadget
2020-06-22 21:55 ` [PATCH v18 03/19] Write pseudorefs through ref backends Han-Wen Nienhuys via GitGitGadget
2020-06-22 21:55 ` [PATCH v18 04/19] Make refs_ref_exists public Han-Wen Nienhuys via GitGitGadget
2020-06-22 21:55 ` [PATCH v18 05/19] Treat BISECT_HEAD as a pseudo ref Han-Wen Nienhuys via GitGitGadget
2020-06-22 21:55 ` [PATCH v18 06/19] Treat CHERRY_PICK_HEAD " Han-Wen Nienhuys via GitGitGadget
2020-06-22 21:55 ` [PATCH v18 07/19] Treat REVERT_HEAD " Han-Wen Nienhuys via GitGitGadget
2020-06-22 21:55 ` [PATCH v18 08/19] Move REF_LOG_ONLY to refs-internal.h Han-Wen Nienhuys via GitGitGadget
2020-06-22 21:55 ` [PATCH v18 09/19] Iterate over the "refs/" namespace in for_each_[raw]ref Han-Wen Nienhuys via GitGitGadget
2020-06-22 21:55 ` [PATCH v18 10/19] Add .gitattributes for the reftable/ directory Han-Wen Nienhuys via GitGitGadget
2020-06-22 21:55 ` [PATCH v18 11/19] Add reftable library Han-Wen Nienhuys via GitGitGadget
2020-06-22 21:55 ` [PATCH v18 12/19] Add standalone build infrastructure for reftable Han-Wen Nienhuys via GitGitGadget
2020-06-22 21:55 ` [PATCH v18 13/19] Reftable support for git-core Han-Wen Nienhuys via GitGitGadget
2020-06-22 21:55 ` [PATCH v18 14/19] Hookup unittests for the reftable library Han-Wen Nienhuys via GitGitGadget
2020-06-22 21:55 ` [PATCH v18 15/19] Add GIT_DEBUG_REFS debugging mechanism Han-Wen Nienhuys via GitGitGadget
2020-06-22 21:55 ` [PATCH v18 16/19] vcxproj: adjust for the reftable changes Johannes Schindelin via GitGitGadget
2020-06-22 21:55 ` [PATCH v18 17/19] git-prompt: prepare for reftable refs backend SZEDER Gábor via GitGitGadget
2020-06-22 21:55 ` [PATCH v18 18/19] Add reftable testing infrastructure Han-Wen Nienhuys via GitGitGadget
2020-06-22 21:55 ` [PATCH v18 19/19] Add "test-tool dump-reftable" command Han-Wen Nienhuys via GitGitGadget
2020-06-29 18:56 ` [PATCH v19 00/20] Reftable support git-core Han-Wen Nienhuys via GitGitGadget
2020-06-29 18:56 ` [PATCH v19 01/20] lib-t6000.sh: write tag using git-update-ref Han-Wen Nienhuys via GitGitGadget
2020-06-29 18:56 ` [PATCH v19 02/20] t3432: use git-reflog to inspect the reflog for HEAD Han-Wen Nienhuys via GitGitGadget
2020-06-30 15:23 ` Denton Liu
2020-06-29 18:56 ` [PATCH v19 03/20] checkout: add '\n' to reflog message Han-Wen Nienhuys via GitGitGadget
2020-06-29 20:07 ` Junio C Hamano
2020-06-30 8:30 ` Han-Wen Nienhuys
2020-06-30 23:58 ` Junio C Hamano
2020-07-01 16:56 ` Han-Wen Nienhuys
2020-07-01 20:22 ` Re* " Junio C Hamano
2020-07-06 15:56 ` Han-Wen Nienhuys
2020-07-06 18:53 ` Junio C Hamano
2020-06-29 18:56 ` [PATCH v19 04/20] Write pseudorefs through ref backends Han-Wen Nienhuys via GitGitGadget
2020-06-29 18:56 ` [PATCH v19 05/20] Make refs_ref_exists public Han-Wen Nienhuys via GitGitGadget
2020-06-29 18:56 ` [PATCH v19 06/20] Treat BISECT_HEAD as a pseudo ref Han-Wen Nienhuys via GitGitGadget
2020-06-29 18:56 ` [PATCH v19 07/20] Treat CHERRY_PICK_HEAD " Han-Wen Nienhuys via GitGitGadget
2020-06-29 18:56 ` [PATCH v19 08/20] Treat REVERT_HEAD " Han-Wen Nienhuys via GitGitGadget
2020-06-29 18:56 ` [PATCH v19 09/20] Move REF_LOG_ONLY to refs-internal.h Han-Wen Nienhuys via GitGitGadget
2020-06-29 18:56 ` [PATCH v19 10/20] Iterate over the "refs/" namespace in for_each_[raw]ref Han-Wen Nienhuys via GitGitGadget
2020-06-29 18:56 ` [PATCH v19 11/20] Add .gitattributes for the reftable/ directory Han-Wen Nienhuys via GitGitGadget
2020-06-29 18:56 ` [PATCH v19 12/20] Add reftable library Han-Wen Nienhuys via GitGitGadget
2020-06-29 18:56 ` [PATCH v19 13/20] Add standalone build infrastructure for reftable Han-Wen Nienhuys via GitGitGadget
2020-06-29 18:56 ` [PATCH v19 14/20] Reftable support for git-core Han-Wen Nienhuys via GitGitGadget
2020-06-29 18:56 ` [PATCH v19 15/20] Hookup unittests for the reftable library Han-Wen Nienhuys via GitGitGadget
2020-06-29 18:56 ` [PATCH v19 16/20] Add GIT_DEBUG_REFS debugging mechanism Han-Wen Nienhuys via GitGitGadget
2020-06-29 18:56 ` [PATCH v19 17/20] vcxproj: adjust for the reftable changes Johannes Schindelin via GitGitGadget
2020-06-29 18:56 ` [PATCH v19 18/20] git-prompt: prepare for reftable refs backend SZEDER Gábor via GitGitGadget
2020-06-29 18:56 ` [PATCH v19 19/20] Add reftable testing infrastructure Han-Wen Nienhuys via GitGitGadget
2020-06-29 18:56 ` [PATCH v19 20/20] Add "test-tool dump-reftable" command Han-Wen Nienhuys via GitGitGadget
2020-06-29 22:54 ` [PATCH v19 00/20] Reftable support git-core Junio C Hamano
2020-06-30 9:28 ` Han-Wen Nienhuys
2020-07-01 0:03 ` Junio C Hamano
2020-07-01 10:16 ` Han-Wen Nienhuys
2020-07-01 20:56 ` Junio C Hamano
2020-07-31 15:26 ` [PATCH v20 00/21] " Han-Wen Nienhuys via GitGitGadget
2020-07-31 15:26 ` [PATCH v20 01/21] refs: add \t to reflog in the files backend Han-Wen Nienhuys via GitGitGadget
2020-07-31 15:26 ` [PATCH v20 02/21] Split off reading loose ref data in separate function Han-Wen Nienhuys via GitGitGadget
2020-07-31 15:26 ` [PATCH v20 03/21] t1400: use git rev-parse for testing PSEUDOREF existence Han-Wen Nienhuys via GitGitGadget
2020-07-31 15:27 ` [PATCH v20 04/21] Modify pseudo refs through ref backend storage Han-Wen Nienhuys via GitGitGadget
2020-07-31 15:27 ` [PATCH v20 05/21] Make HEAD a PSEUDOREF rather than PER_WORKTREE Han-Wen Nienhuys via GitGitGadget
2020-07-31 15:27 ` [PATCH v20 06/21] Make refs_ref_exists public Han-Wen Nienhuys via GitGitGadget
2020-07-31 15:27 ` [PATCH v20 07/21] Treat CHERRY_PICK_HEAD as a pseudo ref Han-Wen Nienhuys via GitGitGadget
2020-07-31 15:27 ` [PATCH v20 08/21] Treat REVERT_HEAD " Han-Wen Nienhuys via GitGitGadget
2020-07-31 15:27 ` [PATCH v20 09/21] Move REF_LOG_ONLY to refs-internal.h Han-Wen Nienhuys via GitGitGadget
2020-07-31 15:27 ` [PATCH v20 10/21] Iteration over entire ref namespace is iterating over "refs/" Han-Wen Nienhuys via GitGitGadget
2020-07-31 15:27 ` [PATCH v20 11/21] Add .gitattributes for the reftable/ directory Han-Wen Nienhuys via GitGitGadget
2020-07-31 15:27 ` [PATCH v20 12/21] Add reftable library Han-Wen Nienhuys via GitGitGadget
2020-07-31 15:27 ` [PATCH v20 13/21] Add standalone build infrastructure for reftable Han-Wen Nienhuys via GitGitGadget
2020-07-31 15:27 ` [PATCH v20 14/21] Reftable support for git-core Han-Wen Nienhuys via GitGitGadget
2020-07-31 15:27 ` [PATCH v20 15/21] Read FETCH_HEAD as loose ref Han-Wen Nienhuys via GitGitGadget
2020-07-31 15:27 ` [PATCH v20 16/21] Hookup unittests for the reftable library Han-Wen Nienhuys via GitGitGadget
2020-07-31 15:27 ` [PATCH v20 17/21] Add GIT_DEBUG_REFS debugging mechanism Han-Wen Nienhuys via GitGitGadget
2020-07-31 15:27 ` [PATCH v20 18/21] vcxproj: adjust for the reftable changes Johannes Schindelin via GitGitGadget
2020-07-31 15:27 ` [PATCH v20 19/21] git-prompt: prepare for reftable refs backend SZEDER Gábor via GitGitGadget
2020-07-31 15:27 ` [PATCH v20 20/21] Add reftable testing infrastructure Han-Wen Nienhuys via GitGitGadget
2020-07-31 15:27 ` [PATCH v20 21/21] Add "test-tool dump-reftable" command Han-Wen Nienhuys via GitGitGadget
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=pull.539.v3.git.1580848060.gitgitgadget@gmail.com \
--to=gitgitgadget@gmail.com \
--cc=git@vger.kernel.org \
--cc=hanwenn@gmail.com \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).