From: Jeff King <peff@peff.net>
To: Duy Nguyen <pclouds@gmail.com>
Cc: Rafael Ascensao <rafa.almas@gmail.com>,
Git Mailing List <git@vger.kernel.org>
Subject: Re: git complains packed-refs is not a directory when used with GIT_DIR and GIT_WORK_TREE envvars.
Date: Tue, 27 Mar 2018 12:47:58 -0400 [thread overview]
Message-ID: <20180327164757.GB24747@sigill.intra.peff.net> (raw)
In-Reply-To: <CACsJy8DP53Og1crS1bLoJf6w8cJhjGKy=ggfbsqzJ6AU4eNhPA@mail.gmail.com>
On Tue, Mar 27, 2018 at 04:56:00PM +0200, Duy Nguyen wrote:
> The way setup_work_tree() does it is just bad to me. When it calls
> set_git_dir() again, the assumption is the new path is exactly the
> same as the old one. The only difference is relative vs absolute. But
> this is super hard to see from set_git_dir implementation. The new
> struct repository design also inherits this (i.e. allowing to call
> set_git_dir multiple times, which really does not make sense), but
> this won't fly long term. When cwd moves, all cached relative paths
> must be adjusted, we need a better mechanism to tell everybody that,
> not just do it for $GIT_DIR and related paths.
Yeah, I agree it's questionable.
> I am planning to fix this. This is part of the "setup cleanup" effort
> to keep repository.c design less messy and hopefully unify how the
> main repo and submodule repo are created/set up. But frankly that may
> take a long while before I could submit anything substantial (I also
> have the "report multiple worktree's HEADs correctly and make fsck
> count all HEADs" task, which is not small and to me have higher
> priority).
>
> So I would not mind papering over it right now (with an understanding
> that absolute path pays some more overhead in path walking, which was
> th reason we tried to avoid it in setup code). A slightly better patch
> is trigger this path absolutization from setup_work_tree(), near
> set_git_dir(). But then you face some ugliness there: how to find out
> all ref stores to update, or just update the main ref store alone.
I don't quite get why f57f37e2 doesn't want to call git_path(). Is it to
avoid the way the path is munged? Or is it to avoid some lazy-setup that
is triggered by calling get_git_dir() at all (which doesn't make much
sense to me, because we'd already have called get_git_dir() much
earlier). Or is it just because we may sometimes fill in refs->git_dir
with something besides get_git_dir() (for a submodule or worktree or
something)?
I.e., can we do one of (depending on which of those answers is "yes"):
1. Stop caching the value of get_git_dir(), and instead call it
on-demand instead of looking at refs->git_dir? (If we just want to
avoid git_path()).
2. If we need to avoid even calling get_git_dir(), can we add a
"light" version of it that avoids whatever side effects we're
trying to skip?
3. If the problem is just that sometimes we need get_git_dir() and
sometimes not, could we perhaps store NULL as a sentinel to mean
"look up get_git_dir() when you need it"?
That would let submodules and worktrees fill in their paths as
necessary (assuming they never change after init), but handle the
case of get_git_dir() changing.
Hmm. Typing that out, it seems like (3) is probably the right path.
Something like the patch below seems to fix it and passes the tests.
diff --git a/refs.c b/refs.c
index 20ba82b434..4094f0e7d4 100644
--- a/refs.c
+++ b/refs.c
@@ -1656,7 +1656,7 @@ struct ref_store *get_main_ref_store(void)
if (main_ref_store)
return main_ref_store;
- main_ref_store = ref_store_init(get_git_dir(), REF_STORE_ALL_CAPS);
+ main_ref_store = ref_store_init(NULL, REF_STORE_ALL_CAPS);
return main_ref_store;
}
diff --git a/refs/files-backend.c b/refs/files-backend.c
index bec8e30e9e..22118b5764 100644
--- a/refs/files-backend.c
+++ b/refs/files-backend.c
@@ -69,6 +69,7 @@ struct files_ref_store {
struct ref_store base;
unsigned int store_flags;
+ /* may be NULL to force lookup of get_git_dir() */
char *gitdir;
char *gitcommondir;
@@ -94,17 +95,23 @@ static struct ref_store *files_ref_store_create(const char *gitdir,
{
struct files_ref_store *refs = xcalloc(1, sizeof(*refs));
struct ref_store *ref_store = (struct ref_store *)refs;
- struct strbuf sb = STRBUF_INIT;
base_ref_store_init(ref_store, &refs_be_files);
refs->store_flags = flags;
- refs->gitdir = xstrdup(gitdir);
- get_common_dir_noenv(&sb, gitdir);
- refs->gitcommondir = strbuf_detach(&sb, NULL);
- strbuf_addf(&sb, "%s/packed-refs", refs->gitcommondir);
- refs->packed_ref_store = packed_ref_store_create(sb.buf, flags);
- strbuf_release(&sb);
+ if (gitdir) {
+ struct strbuf sb = STRBUF_INIT;
+ refs->gitdir = xstrdup(gitdir);
+ get_common_dir_noenv(&sb, gitdir);
+ refs->gitcommondir = strbuf_detach(&sb, NULL);
+ strbuf_addf(&sb, "%s/packed-refs", refs->gitcommondir);
+ refs->packed_ref_store = packed_ref_store_create(sb.buf, flags);
+ strbuf_release(&sb);
+ } else {
+ refs->gitdir = NULL;
+ refs->gitcommondir = NULL;
+ refs->packed_ref_store = packed_ref_store_create(NULL, flags);
+ }
return ref_store;
}
@@ -147,6 +154,16 @@ static struct files_ref_store *files_downcast(struct ref_store *ref_store,
return refs;
}
+static const char *files_gitdir(const struct files_ref_store *refs)
+{
+ return refs->gitdir ? refs->gitdir : get_git_dir();
+}
+
+static const char *files_gitcommondir(const struct files_ref_store *refs)
+{
+ return refs->gitcommondir ? refs->gitcommondir : get_git_common_dir();
+}
+
static void files_reflog_path(struct files_ref_store *refs,
struct strbuf *sb,
const char *refname)
@@ -154,10 +171,10 @@ static void files_reflog_path(struct files_ref_store *refs,
switch (ref_type(refname)) {
case REF_TYPE_PER_WORKTREE:
case REF_TYPE_PSEUDOREF:
- strbuf_addf(sb, "%s/logs/%s", refs->gitdir, refname);
+ strbuf_addf(sb, "%s/logs/%s", files_gitdir(refs), refname);
break;
case REF_TYPE_NORMAL:
- strbuf_addf(sb, "%s/logs/%s", refs->gitcommondir, refname);
+ strbuf_addf(sb, "%s/logs/%s", files_gitcommondir(refs), refname);
break;
default:
die("BUG: unknown ref type %d of ref %s",
@@ -172,10 +189,10 @@ static void files_ref_path(struct files_ref_store *refs,
switch (ref_type(refname)) {
case REF_TYPE_PER_WORKTREE:
case REF_TYPE_PSEUDOREF:
- strbuf_addf(sb, "%s/%s", refs->gitdir, refname);
+ strbuf_addf(sb, "%s/%s", files_gitdir(refs), refname);
break;
case REF_TYPE_NORMAL:
- strbuf_addf(sb, "%s/%s", refs->gitcommondir, refname);
+ strbuf_addf(sb, "%s/%s", files_gitcommondir(refs), refname);
break;
default:
die("BUG: unknown ref type %d of ref %s",
@@ -2151,13 +2168,13 @@ static struct ref_iterator *files_reflog_iterator_begin(struct ref_store *ref_st
files_downcast(ref_store, REF_STORE_READ,
"reflog_iterator_begin");
- if (!strcmp(refs->gitdir, refs->gitcommondir)) {
- return reflog_iterator_begin(ref_store, refs->gitcommondir);
+ if (!strcmp(files_gitdir(refs), files_gitcommondir(refs))) {
+ return reflog_iterator_begin(ref_store, files_gitcommondir(refs));
} else {
return merge_ref_iterator_begin(
0,
- reflog_iterator_begin(ref_store, refs->gitdir),
- reflog_iterator_begin(ref_store, refs->gitcommondir),
+ reflog_iterator_begin(ref_store, files_gitdir(refs)),
+ reflog_iterator_begin(ref_store, files_gitcommondir(refs)),
reflog_iterator_select, refs);
}
}
diff --git a/refs/packed-backend.c b/refs/packed-backend.c
index 65288c6472..e5a5af1285 100644
--- a/refs/packed-backend.c
+++ b/refs/packed-backend.c
@@ -158,6 +158,16 @@ static void acquire_snapshot(struct snapshot *snapshot)
snapshot->referrers++;
}
+static const char *packed_refs_path(const struct packed_ref_store *refs)
+{
+ return refs->path ? refs->path : git_path("packed-refs");
+}
+
+static const char *snapshot_path(const struct snapshot *snapshot)
+{
+ return packed_refs_path(snapshot->refs);
+}
+
/*
* If the buffer in `snapshot` is active, then either munmap the
* memory and close the file, or free the memory. Then set the buffer
@@ -168,7 +178,7 @@ static void clear_snapshot_buffer(struct snapshot *snapshot)
if (snapshot->mmapped) {
if (munmap(snapshot->buf, snapshot->eof - snapshot->buf))
die_errno("error ummapping packed-refs file %s",
- snapshot->refs->path);
+ snapshot_path(snapshot));
snapshot->mmapped = 0;
} else {
free(snapshot->buf);
@@ -201,7 +211,7 @@ struct ref_store *packed_ref_store_create(const char *path,
base_ref_store_init(ref_store, &refs_be_packed);
refs->store_flags = store_flags;
- refs->path = xstrdup(path);
+ refs->path = xstrdup_or_null(path);
return ref_store;
}
@@ -342,7 +352,7 @@ static void sort_snapshot(struct snapshot *snapshot)
/* The safety check should prevent this. */
BUG("unterminated line found in packed-refs");
if (eol - pos < GIT_SHA1_HEXSZ + 2)
- die_invalid_line(snapshot->refs->path,
+ die_invalid_line(snapshot_path(snapshot),
pos, eof - pos);
eol++;
if (eol < eof && *eol == '^') {
@@ -454,7 +464,7 @@ static void verify_buffer_safe(struct snapshot *snapshot)
last_line = find_start_of_record(start, eof - 1);
if (*(eof - 1) != '\n' || eof - last_line < GIT_SHA1_HEXSZ + 2)
- die_invalid_line(snapshot->refs->path,
+ die_invalid_line(snapshot_path(snapshot),
last_line, eof - last_line);
}
@@ -473,7 +483,7 @@ static int load_contents(struct snapshot *snapshot)
size_t size;
ssize_t bytes_read;
- fd = open(snapshot->refs->path, O_RDONLY);
+ fd = open(snapshot_path(snapshot), O_RDONLY);
if (fd < 0) {
if (errno == ENOENT) {
/*
@@ -485,14 +495,14 @@ static int load_contents(struct snapshot *snapshot)
*/
return 0;
} else {
- die_errno("couldn't read %s", snapshot->refs->path);
+ die_errno("couldn't read %s", snapshot_path(snapshot));
}
}
stat_validity_update(&snapshot->validity, fd);
if (fstat(fd, &st) < 0)
- die_errno("couldn't stat %s", snapshot->refs->path);
+ die_errno("couldn't stat %s", snapshot_path(snapshot));
size = xsize_t(st.st_size);
if (!size) {
@@ -501,7 +511,7 @@ static int load_contents(struct snapshot *snapshot)
snapshot->buf = xmalloc(size);
bytes_read = read_in_full(fd, snapshot->buf, size);
if (bytes_read < 0 || bytes_read != size)
- die_errno("couldn't read %s", snapshot->refs->path);
+ die_errno("couldn't read %s", snapshot_path(snapshot));
snapshot->mmapped = 0;
} else {
snapshot->buf = xmmap(NULL, size, PROT_READ, MAP_PRIVATE, fd, 0);
@@ -629,14 +639,14 @@ static struct snapshot *create_snapshot(struct packed_ref_store *refs)
eol = memchr(snapshot->buf, '\n',
snapshot->eof - snapshot->buf);
if (!eol)
- die_unterminated_line(refs->path,
+ die_unterminated_line(packed_refs_path(refs),
snapshot->buf,
snapshot->eof - snapshot->buf);
tmp = xmemdupz(snapshot->buf, eol - snapshot->buf);
if (!skip_prefix(tmp, "# pack-refs with:", (const char **)&p))
- die_invalid_line(refs->path,
+ die_invalid_line(packed_refs_path(refs),
snapshot->buf,
snapshot->eof - snapshot->buf);
@@ -695,7 +705,8 @@ static struct snapshot *create_snapshot(struct packed_ref_store *refs)
static void validate_snapshot(struct packed_ref_store *refs)
{
if (refs->snapshot &&
- !stat_validity_check(&refs->snapshot->validity, refs->path))
+ !stat_validity_check(&refs->snapshot->validity,
+ packed_refs_path(refs)))
clear_snapshot(refs);
}
@@ -739,7 +750,7 @@ static int packed_read_raw_ref(struct ref_store *ref_store,
}
if (get_oid_hex(rec, oid))
- die_invalid_line(refs->path, rec, snapshot->eof - rec);
+ die_invalid_line(packed_refs_path(refs), rec, snapshot->eof - rec);
*type = REF_ISPACKED;
return 0;
@@ -795,12 +806,12 @@ static int next_record(struct packed_ref_iterator *iter)
if (iter->eof - p < GIT_SHA1_HEXSZ + 2 ||
parse_oid_hex(p, &iter->oid, &p) ||
!isspace(*p++))
- die_invalid_line(iter->snapshot->refs->path,
+ die_invalid_line(snapshot_path(iter->snapshot),
iter->pos, iter->eof - iter->pos);
eol = memchr(p, '\n', iter->eof - p);
if (!eol)
- die_unterminated_line(iter->snapshot->refs->path,
+ die_unterminated_line(snapshot_path(iter->snapshot),
iter->pos, iter->eof - iter->pos);
strbuf_add(&iter->refname_buf, p, eol - p);
@@ -825,7 +836,7 @@ static int next_record(struct packed_ref_iterator *iter)
if (iter->eof - p < GIT_SHA1_HEXSZ + 1 ||
parse_oid_hex(p, &iter->peeled, &p) ||
*p++ != '\n')
- die_invalid_line(iter->snapshot->refs->path,
+ die_invalid_line(snapshot_path(iter->snapshot),
iter->pos, iter->eof - iter->pos);
iter->pos = p;
@@ -995,14 +1006,14 @@ int packed_refs_lock(struct ref_store *ref_store, int flags, struct strbuf *err)
*/
if (hold_lock_file_for_update_timeout(
&refs->lock,
- refs->path,
+ packed_refs_path(refs),
flags, timeout_value) < 0) {
- unable_to_lock_message(refs->path, errno, err);
+ unable_to_lock_message(packed_refs_path(refs), errno, err);
return -1;
}
if (close_lock_file_gently(&refs->lock)) {
- strbuf_addf(err, "unable to close %s: %s", refs->path, strerror(errno));
+ strbuf_addf(err, "unable to close %s: %s", packed_refs_path(refs), strerror(errno));
rollback_lock_file(&refs->lock);
return -1;
}
@@ -1471,21 +1482,21 @@ static int packed_transaction_finish(struct ref_store *ref_store,
REF_STORE_READ | REF_STORE_WRITE | REF_STORE_ODB,
"ref_transaction_finish");
int ret = TRANSACTION_GENERIC_ERROR;
- char *packed_refs_path;
+ char *path;
clear_snapshot(refs);
- packed_refs_path = get_locked_file_path(&refs->lock);
- if (rename_tempfile(&refs->tempfile, packed_refs_path)) {
+ path = get_locked_file_path(&refs->lock);
+ if (rename_tempfile(&refs->tempfile, path)) {
strbuf_addf(err, "error replacing %s: %s",
- refs->path, strerror(errno));
+ path, strerror(errno));
goto cleanup;
}
ret = 0;
cleanup:
- free(packed_refs_path);
+ free(path);
packed_transaction_cleanup(refs, transaction);
return ret;
}
next prev parent reply other threads:[~2018-03-27 16:48 UTC|newest]
Thread overview: 54+ messages / expand[flat|nested] mbox.gz Atom feed top
2018-03-26 21:27 git complains packed-refs is not a directory when used with GIT_DIR and GIT_WORK_TREE envvars Rafael Ascensao
2018-03-26 21:44 ` Ævar Arnfjörð Bjarmason
2018-03-27 6:31 ` Jeff King
2018-03-27 14:56 ` Duy Nguyen
2018-03-27 16:47 ` Jeff King [this message]
2018-03-27 17:09 ` Duy Nguyen
2018-03-27 17:30 ` Duy Nguyen
2018-03-28 9:52 ` Jeff King
2018-03-28 10:10 ` Duy Nguyen
2018-03-28 17:36 ` Jeff King
2018-03-28 17:38 ` [PATCH 1/4] set_git_dir: die when setenv() fails Jeff King
2018-03-28 17:40 ` [PATCH 2/4] add chdir-notify API Jeff King
2018-03-28 17:58 ` Eric Sunshine
2018-03-28 18:02 ` Jeff King
2018-03-29 14:53 ` Duy Nguyen
2018-03-29 17:48 ` Jeff King
2018-03-29 18:12 ` Duy Nguyen
2018-03-28 17:42 ` [PATCH 3/4] set_work_tree: use chdir_notify Jeff King
2018-03-29 17:02 ` Duy Nguyen
2018-03-29 17:23 ` Duy Nguyen
2018-03-29 17:50 ` Jeff King
2018-03-29 17:50 ` Jeff King
2018-03-29 18:01 ` Duy Nguyen
2018-03-30 17:23 ` Jeff King
2018-03-28 17:43 ` [PATCH 4/4] refs: use chdir_notify to update cached relative paths Jeff King
2018-03-30 18:34 ` [PATCH v2 0/5] re-parenting relative directories after chdir Jeff King
2018-03-30 18:34 ` [PATCH v2 1/5] set_git_dir: die when setenv() fails Jeff King
2018-03-30 18:34 ` [PATCH v2 2/5] trace.c: export trace_setup_key Jeff King
2018-03-30 19:46 ` Junio C Hamano
2018-03-30 19:47 ` Jeff King
2018-03-30 19:50 ` Junio C Hamano
2018-03-30 19:54 ` Jeff King
2018-03-30 18:35 ` [PATCH v2 3/5] add chdir-notify API Jeff King
2018-03-30 18:35 ` [PATCH v2 4/5] set_work_tree: use chdir_notify Jeff King
2018-03-30 18:35 ` [PATCH v2 5/5] refs: use chdir_notify to update cached relative paths Jeff King
2018-03-30 19:36 ` [PATCH v2 0/5] re-parenting relative directories after chdir Duy Nguyen
2018-03-28 9:47 ` git complains packed-refs is not a directory when used with GIT_DIR and GIT_WORK_TREE envvars Jeff King
2018-03-28 17:55 ` [PATCH 0/8] " Nguyễn Thái Ngọc Duy
2018-03-28 17:55 ` [PATCH 1/8] strbuf.c: add strbuf_ensure_trailing_dr_sep() Nguyễn Thái Ngọc Duy
2018-03-28 17:55 ` [PATCH 2/8] strbuf.c: reintroduce get_pwd_cwd() (with strbuf_ prefix) Nguyễn Thái Ngọc Duy
2018-03-28 18:02 ` Stefan Beller
2018-03-28 18:05 ` Duy Nguyen
2018-03-28 17:55 ` [PATCH 3/8] trace.c: export trace_setup_key Nguyễn Thái Ngọc Duy
2018-03-28 17:55 ` [PATCH 4/8] setup.c: introduce setup_adjust_path() Nguyễn Thái Ngọc Duy
2018-03-28 17:55 ` [PATCH 5/8] setup.c: allow other code to be notified when $CWD moves Nguyễn Thái Ngọc Duy
2018-03-28 17:55 ` [PATCH 6/8] environment.c: adjust env containing relpath when $CWD is moved Nguyễn Thái Ngọc Duy
2018-03-28 18:30 ` Jeff King
2018-03-28 18:45 ` Duy Nguyen
2018-03-28 17:55 ` [PATCH 7/8] repository: adjust repo paths when $CWD moves Nguyễn Thái Ngọc Duy
2018-03-28 17:55 ` [PATCH 8/8] refs: adjust main " Nguyễn Thái Ngọc Duy
2018-03-28 18:19 ` [PATCH 0/8] Re: git complains packed-refs is not a directory when used with GIT_DIR and GIT_WORK_TREE envvars Jeff King
2018-03-29 14:57 ` Duy Nguyen
2018-03-30 17:21 ` Jeff King
2018-03-28 22:24 ` Junio C Hamano
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
List information: http://vger.kernel.org/majordomo-info.html
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=20180327164757.GB24747@sigill.intra.peff.net \
--to=peff@peff.net \
--cc=git@vger.kernel.org \
--cc=pclouds@gmail.com \
--cc=rafa.almas@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.
Code repositories for project(s) associated with this public inbox
https://80x24.org/mirrors/git.git
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 read-only IMAP folder(s) and NNTP newsgroup(s).