#define USE_THE_REPOSITORY_VARIABLE
#include "git-compat-util.h"
+#include "abspath.h"
#include "advice.h"
#include "config.h"
#include "environment.h"
if (!be)
BUG("reference backend is unknown");
- refs = be->init(repo, gitdir, flags);
+ refs = be->init(repo, NULL, gitdir, flags);
return refs;
}
return "unknown failure";
}
}
+
+void refs_compute_filesystem_location(const char *gitdir, const char *payload,
+ bool *is_worktree, struct strbuf *refdir,
+ struct strbuf *ref_common_dir)
+{
+ struct strbuf sb = STRBUF_INIT;
+
+ *is_worktree = get_common_dir_noenv(ref_common_dir, gitdir);
+
+ if (!payload) {
+ /*
+ * We can use the 'gitdir' as the 'refdir' without appending the
+ * worktree path, as the 'gitdir' here is already the worktree
+ * path and is different from 'commondir' denoted by 'ref_common_dir'.
+ */
+ strbuf_addstr(refdir, gitdir);
+ return;
+ }
+
+ if (!is_absolute_path(payload)) {
+ strbuf_addf(&sb, "%s/%s", ref_common_dir->buf, payload);
+ strbuf_realpath(ref_common_dir, sb.buf, 1);
+ } else {
+ strbuf_realpath(ref_common_dir, payload, 1);
+ }
+
+ strbuf_addbuf(refdir, ref_common_dir);
+
+ if (*is_worktree) {
+ const char *wt_id = strrchr(gitdir, '/');
+ if (!wt_id)
+ BUG("worktree path does not contain slash");
+ strbuf_addf(refdir, "/worktrees/%s", wt_id + 1);
+ }
+
+ strbuf_release(&sb);
+}
* set of caches.
*/
static struct ref_store *files_ref_store_init(struct repository *repo,
+ const char *payload,
const char *gitdir,
unsigned int flags)
{
struct files_ref_store *refs = xcalloc(1, sizeof(*refs));
struct ref_store *ref_store = (struct ref_store *)refs;
- struct strbuf sb = STRBUF_INIT;
+ struct strbuf ref_common_dir = STRBUF_INIT;
+ struct strbuf refdir = STRBUF_INIT;
+ bool is_worktree;
+
+ refs_compute_filesystem_location(gitdir, payload, &is_worktree, &refdir,
+ &ref_common_dir);
- base_ref_store_init(ref_store, repo, gitdir, &refs_be_files);
+ base_ref_store_init(ref_store, repo, refdir.buf, &refs_be_files);
refs->store_flags = flags;
- get_common_dir_noenv(&sb, gitdir);
- refs->gitcommondir = strbuf_detach(&sb, NULL);
+ refs->gitcommondir = strbuf_detach(&ref_common_dir, NULL);
refs->packed_ref_store =
- packed_ref_store_init(repo, refs->gitcommondir, flags);
+ packed_ref_store_init(repo, NULL, refs->gitcommondir, flags);
refs->log_all_ref_updates = repo_settings_get_log_all_ref_updates(repo);
repo_config_get_bool(repo, "core.prefersymlinkrefs", &refs->prefer_symlink_refs);
chdir_notify_reparent("files-backend $GIT_COMMONDIR",
&refs->gitcommondir);
+ strbuf_release(&refdir);
+
return ref_store;
}
return snapshot->refs->base.repo->hash_algo->hexsz;
}
+/*
+ * Since packed-refs is only stored in the common dir, don't parse the
+ * payload and rely on the files-backend to set 'gitdir' correctly.
+ */
struct ref_store *packed_ref_store_init(struct repository *repo,
+ const char *payload UNUSED,
const char *gitdir,
unsigned int store_flags)
{
*/
struct ref_store *packed_ref_store_init(struct repository *repo,
+ const char *payload,
const char *gitdir,
unsigned int store_flags);
* the ref_store and to record the ref_store for later lookup.
*/
typedef struct ref_store *ref_store_init_fn(struct repository *repo,
+ const char *payload,
const char *gitdir,
unsigned int flags);
/*
unsigned int initial_transaction,
struct strbuf *err);
+/*
+ * Given a gitdir and the reference storage payload provided, retrieve the
+ * 'refdir' and 'ref_common_dir'. The former is where references should be
+ * stored for the current worktree, the latter is the common reference
+ * directory if working with a linked worktree. If working with the main
+ * worktree, both values will be the same.
+ *
+ * This is used by backends that store references in the repository directly.
+ */
+void refs_compute_filesystem_location(const char *gitdir, const char *payload,
+ bool *is_worktree, struct strbuf *refdir,
+ struct strbuf *ref_common_dir);
+
#endif /* REFS_REFS_INTERNAL_H */
}
static struct ref_store *reftable_be_init(struct repository *repo,
+ const char *payload,
const char *gitdir,
unsigned int store_flags)
{
struct reftable_ref_store *refs = xcalloc(1, sizeof(*refs));
+ struct strbuf ref_common_dir = STRBUF_INIT;
+ struct strbuf refdir = STRBUF_INIT;
struct strbuf path = STRBUF_INIT;
- int is_worktree;
+ bool is_worktree;
mode_t mask;
mask = umask(0);
umask(mask);
- base_ref_store_init(&refs->base, repo, gitdir, &refs_be_reftable);
+ refs_compute_filesystem_location(gitdir, payload, &is_worktree, &refdir,
+ &ref_common_dir);
+
+ base_ref_store_init(&refs->base, repo, refdir.buf, &refs_be_reftable);
strmap_init(&refs->worktree_backends);
refs->store_flags = store_flags;
refs->log_all_ref_updates = repo_settings_get_log_all_ref_updates(repo);
/*
* Set up the main reftable stack that is hosted in GIT_COMMON_DIR.
* This stack contains both the shared and the main worktree refs.
- *
- * Note that we don't try to resolve the path in case we have a
- * worktree because `get_common_dir_noenv()` already does it for us.
*/
- is_worktree = get_common_dir_noenv(&path, gitdir);
+ strbuf_addbuf(&path, &ref_common_dir);
if (!is_worktree) {
strbuf_reset(&path);
- strbuf_realpath(&path, gitdir, 0);
+ strbuf_realpath(&path, ref_common_dir.buf, 0);
}
strbuf_addstr(&path, "/reftable");
refs->err = reftable_backend_init(&refs->main_backend, path.buf,
* do it efficiently.
*/
if (is_worktree) {
- strbuf_reset(&path);
- strbuf_addf(&path, "%s/reftable", gitdir);
+ strbuf_addstr(&refdir, "/reftable");
- refs->err = reftable_backend_init(&refs->worktree_backend, path.buf,
+ refs->err = reftable_backend_init(&refs->worktree_backend, refdir.buf,
&refs->write_options);
if (refs->err)
goto done;
done:
assert(refs->err != REFTABLE_API_ERROR);
+ strbuf_release(&ref_common_dir);
+ strbuf_release(&refdir);
strbuf_release(&path);
return &refs->base;
}