git@vger.kernel.org mailing list mirror (one of many)
 help / color / mirror / code / Atom feed
From: "Nguyễn Thái Ngọc Duy" <pclouds@gmail.com>
To: git@vger.kernel.org
Cc: "Junio C Hamano" <gitster@pobox.com>,
	"Michael Haggerty" <mhagger@alum.mit.edu>,
	"Nguyễn Thái Ngọc Duy" <pclouds@gmail.com>
Subject: [PATCH 2/2] worktree.c: use submodule interface to access refs from another worktree
Date: Wed,  8 Feb 2017 18:31:44 +0700	[thread overview]
Message-ID: <20170208113144.8201-3-pclouds@gmail.com> (raw)
In-Reply-To: <20170208113144.8201-1-pclouds@gmail.com>

The patch itself is relatively simple: manual parsing code is replaced
with a call to resolve_ref_submodule(). The manual parsing code must die
because only refs/files-backend.c should do that. Why submodule here is
a more interesting question.

From an outside look, any .git/worktrees/foo is seen as a "normal"
repository. You can set GIT_DIR to it and have access to everything,
even shared things that are not literally inside that directory, like
object db or shared refs.

On top of that, linked worktrees point to those directories with ".git"
files. These two make a linked worktree's path "X" a "submodule" (*) (**)
because X/.git is a file that points to a repository somewhere.

As such, we can just linked worktree's path as a submodule. We just need
to make sure they are unique because they are used to lookup submodule
refs store.

Main worktree is a a bit trickier. If we stand at a linked worktree, we
may still need to peek into main worktree's HEAD, for example. We can
treat main worktree's path as submodule as well since git_path_submodule()
can tolerate ".git" dirs, in addition to ".git" files.

The constraint is, if main worktree is X, then the git repo must be at
X/.git. If the user separates .git repo far away and tell git to point
to it via GIT_DIR or something else, then the "main worktree as submodule"
trick fails. Within multiple worktree context, I think we can limit
support to "standard" layout, at least for now.

(*) The differences in sharing object database and refs between
submodules and linked worktrees don't really matter in this context.

(**) At this point, we may want to rename refs *_submodule API to
something more neutral, maybe s/_submodule/_remote/

Signed-off-by: Nguyễn Thái Ngọc Duy <pclouds@gmail.com>
---
 branch.c   |  3 +-
 worktree.c | 99 +++++++++++++++-----------------------------------------------
 worktree.h |  2 +-
 3 files changed, 27 insertions(+), 77 deletions(-)

diff --git a/branch.c b/branch.c
index b955d4f316..db5843718f 100644
--- a/branch.c
+++ b/branch.c
@@ -354,7 +354,8 @@ int replace_each_worktree_head_symref(const char *oldref, const char *newref)
 	for (i = 0; worktrees[i]; i++) {
 		if (worktrees[i]->is_detached)
 			continue;
-		if (strcmp(oldref, worktrees[i]->head_ref))
+		if (worktrees[i]->head_ref &&
+		    strcmp(oldref, worktrees[i]->head_ref))
 			continue;
 
 		if (set_worktree_head_symref(get_worktree_git_dir(worktrees[i]),
diff --git a/worktree.c b/worktree.c
index d633761575..25e5bc9a3e 100644
--- a/worktree.c
+++ b/worktree.c
@@ -19,54 +19,24 @@ void free_worktrees(struct worktree **worktrees)
 	free (worktrees);
 }
 
-/*
- * read 'path_to_ref' into 'ref'.  Also if is_detached is not NULL,
- * set is_detached to 1 (0) if the ref is detached (is not detached).
- *
- * $GIT_COMMON_DIR/$symref (e.g. HEAD) is practically outside $GIT_DIR so
- * for linked worktrees, `resolve_ref_unsafe()` won't work (it uses
- * git_path). Parse the ref ourselves.
- *
- * return -1 if the ref is not a proper ref, 0 otherwise (success)
- */
-static int parse_ref(char *path_to_ref, struct strbuf *ref, int *is_detached)
-{
-	if (is_detached)
-		*is_detached = 0;
-	if (!strbuf_readlink(ref, path_to_ref, 0)) {
-		/* HEAD is symbolic link */
-		if (!starts_with(ref->buf, "refs/") ||
-				check_refname_format(ref->buf, 0))
-			return -1;
-	} else if (strbuf_read_file(ref, path_to_ref, 0) >= 0) {
-		/* textual symref or detached */
-		if (!starts_with(ref->buf, "ref:")) {
-			if (is_detached)
-				*is_detached = 1;
-		} else {
-			strbuf_remove(ref, 0, strlen("ref:"));
-			strbuf_trim(ref);
-			if (check_refname_format(ref->buf, 0))
-				return -1;
-		}
-	} else
-		return -1;
-	return 0;
-}
-
 /**
- * Add the head_sha1 and head_ref (if not detached) to the given worktree
+ * Update head_sha1, head_ref and is_detached of the given worktree
  */
-static void add_head_info(struct strbuf *head_ref, struct worktree *worktree)
+static void add_head_info(struct worktree *wt)
 {
-	if (head_ref->len) {
-		if (worktree->is_detached) {
-			get_sha1_hex(head_ref->buf, worktree->head_sha1);
-		} else {
-			resolve_ref_unsafe(head_ref->buf, 0, worktree->head_sha1, NULL);
-			worktree->head_ref = strbuf_detach(head_ref, NULL);
-		}
-	}
+	int flags;
+	const char *target;
+
+	target = resolve_ref_submodule(wt->path, "HEAD",
+				       RESOLVE_REF_READING,
+				       wt->head_sha1, &flags);
+	if (!target)
+		return;
+
+	if (flags & REF_ISSYMREF)
+		wt->head_ref = xstrdup(target);
+	else
+		wt->is_detached = 1;
 }
 
 /**
@@ -77,9 +47,7 @@ static struct worktree *get_main_worktree(void)
 	struct worktree *worktree = NULL;
 	struct strbuf path = STRBUF_INIT;
 	struct strbuf worktree_path = STRBUF_INIT;
-	struct strbuf head_ref = STRBUF_INIT;
 	int is_bare = 0;
-	int is_detached = 0;
 
 	strbuf_add_absolute_path(&worktree_path, get_git_common_dir());
 	is_bare = !strbuf_strip_suffix(&worktree_path, "/.git");
@@ -91,13 +59,10 @@ static struct worktree *get_main_worktree(void)
 	worktree = xcalloc(1, sizeof(*worktree));
 	worktree->path = strbuf_detach(&worktree_path, NULL);
 	worktree->is_bare = is_bare;
-	worktree->is_detached = is_detached;
-	if (!parse_ref(path.buf, &head_ref, &is_detached))
-		add_head_info(&head_ref, worktree);
+	add_head_info(worktree);
 
 	strbuf_release(&path);
 	strbuf_release(&worktree_path);
-	strbuf_release(&head_ref);
 	return worktree;
 }
 
@@ -106,8 +71,6 @@ static struct worktree *get_linked_worktree(const char *id)
 	struct worktree *worktree = NULL;
 	struct strbuf path = STRBUF_INIT;
 	struct strbuf worktree_path = STRBUF_INIT;
-	struct strbuf head_ref = STRBUF_INIT;
-	int is_detached = 0;
 
 	if (!id)
 		die("Missing linked worktree name");
@@ -127,19 +90,14 @@ static struct worktree *get_linked_worktree(const char *id)
 	strbuf_reset(&path);
 	strbuf_addf(&path, "%s/worktrees/%s/HEAD", get_git_common_dir(), id);
 
-	if (parse_ref(path.buf, &head_ref, &is_detached) < 0)
-		goto done;
-
 	worktree = xcalloc(1, sizeof(*worktree));
 	worktree->path = strbuf_detach(&worktree_path, NULL);
 	worktree->id = xstrdup(id);
-	worktree->is_detached = is_detached;
-	add_head_info(&head_ref, worktree);
+	add_head_info(worktree);
 
 done:
 	strbuf_release(&path);
 	strbuf_release(&worktree_path);
-	strbuf_release(&head_ref);
 	return worktree;
 }
 
@@ -334,8 +292,6 @@ const struct worktree *find_shared_symref(const char *symref,
 					  const char *target)
 {
 	const struct worktree *existing = NULL;
-	struct strbuf path = STRBUF_INIT;
-	struct strbuf sb = STRBUF_INIT;
 	static struct worktree **worktrees;
 	int i = 0;
 
@@ -345,6 +301,10 @@ const struct worktree *find_shared_symref(const char *symref,
 
 	for (i = 0; worktrees[i]; i++) {
 		struct worktree *wt = worktrees[i];
+		const char *symref_target;
+		unsigned char sha1[20];
+		int flags;
+
 		if (wt->is_bare)
 			continue;
 
@@ -359,25 +319,14 @@ const struct worktree *find_shared_symref(const char *symref,
 			}
 		}
 
-		strbuf_reset(&path);
-		strbuf_reset(&sb);
-		strbuf_addf(&path, "%s/%s",
-			    get_worktree_git_dir(wt),
-			    symref);
-
-		if (parse_ref(path.buf, &sb, NULL)) {
-			continue;
-		}
-
-		if (!strcmp(sb.buf, target)) {
+		symref_target = resolve_ref_submodule(wt->path, symref, 0,
+						      sha1, &flags);
+		if ((flags & REF_ISSYMREF) && !strcmp(symref_target, target)) {
 			existing = wt;
 			break;
 		}
 	}
 
-	strbuf_release(&path);
-	strbuf_release(&sb);
-
 	return existing;
 }
 
diff --git a/worktree.h b/worktree.h
index 6bfb985203..5ea5e503fb 100644
--- a/worktree.h
+++ b/worktree.h
@@ -4,7 +4,7 @@
 struct worktree {
 	char *path;
 	char *id;
-	char *head_ref;
+	char *head_ref;		/* NULL if HEAD is broken or detached */
 	char *lock_reason;	/* internal use */
 	unsigned char head_sha1[20];
 	int is_detached;
-- 
2.11.0.157.gd943d85


  parent reply	other threads:[~2017-02-08 12:35 UTC|newest]

Thread overview: 51+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2017-02-08 11:31 [PATCH RFC 0/2] Kill manual ref parsing code in worktree.c Nguyễn Thái Ngọc Duy
2017-02-08 11:31 ` [PATCH 1/2] refs.c: add resolve_ref_submodule() Nguyễn Thái Ngọc Duy
2017-02-09  5:20   ` Michael Haggerty
2017-02-08 11:31 ` Nguyễn Thái Ngọc Duy [this message]
2017-02-08 19:50   ` [PATCH 2/2] worktree.c: use submodule interface to access refs from another worktree Stefan Beller
2017-02-08 23:19     ` Junio C Hamano
2017-02-08 23:25   ` Junio C Hamano
2017-02-09  6:07   ` Michael Haggerty
2017-02-09  6:55     ` Junio C Hamano
2017-02-09  8:04       ` Michael Haggerty
2017-02-09 11:59     ` Duy Nguyen
2017-02-09 14:03       ` Michael Haggerty
2017-02-08 18:18 ` [PATCH RFC 0/2] Kill manual ref parsing code in worktree.c Junio C Hamano
2017-02-16 12:02 ` [PATCH v2 0/5] " Nguyễn Thái Ngọc Duy
2017-02-16 12:02   ` [PATCH v2 1/5] refs: introduce get_worktree_ref_store() Nguyễn Thái Ngọc Duy
2017-02-16 12:02   ` [PATCH v2 2/5] refs.c: add refs_resolve_ref_unsafe() Nguyễn Thái Ngọc Duy
2017-02-16 12:03   ` [PATCH v2 3/5] worktree.c: kill parse_ref() in favor of refs_resolve_ref_unsafe() Nguyễn Thái Ngọc Duy
2017-02-16 12:03   ` [PATCH v2 4/5] refs: add refs_create_symref() Nguyễn Thái Ngọc Duy
2017-02-16 12:03   ` [PATCH v2 5/5] refs: kill set_worktree_head_symref() Nguyễn Thái Ngọc Duy
2017-03-18 10:02   ` [PATCH v3 0/4] Kill manual ref parsing code in worktree.c Nguyễn Thái Ngọc Duy
2017-03-18 10:02     ` [PATCH v3 1/4] environment.c: fix potential segfault by get_git_common_dir() Nguyễn Thái Ngọc Duy
2017-03-18 17:54       ` Junio C Hamano
2017-03-19  9:34         ` Duy Nguyen
2017-03-18 10:02     ` [PATCH v3 2/4] refs: introduce get_worktree_ref_store() Nguyễn Thái Ngọc Duy
2017-03-20  6:59       ` Michael Haggerty
2017-03-20 12:01         ` Duy Nguyen
2017-03-20 14:25           ` Michael Haggerty
2017-03-26  8:26             ` Duy Nguyen
2017-03-18 10:02     ` [PATCH v3 3/4] worktree.c: kill parse_ref() in favor of refs_resolve_ref_unsafe() Nguyễn Thái Ngọc Duy
2017-03-18 10:02     ` [PATCH v3 4/4] refs: kill set_worktree_head_symref() Nguyễn Thái Ngọc Duy
2017-03-18 17:49     ` [PATCH v3 0/4] Kill manual ref parsing code in worktree.c Junio C Hamano
2017-04-04 10:21     ` [PATCH v4 0/5] " Nguyễn Thái Ngọc Duy
2017-04-04 10:21       ` [PATCH v4 1/5] environment.c: fix potential segfault by get_git_common_dir() Nguyễn Thái Ngọc Duy
2017-04-04 10:21       ` [PATCH v4 2/5] refs.c: make submodule ref store hashmap generic Nguyễn Thái Ngọc Duy
2017-04-04 10:21       ` [PATCH v4 3/5] refs: introduce get_worktree_ref_store() Nguyễn Thái Ngọc Duy
2017-04-22  4:52         ` Michael Haggerty
2017-04-04 10:21       ` [PATCH v4 4/5] worktree.c: kill parse_ref() in favor of refs_resolve_ref_unsafe() Nguyễn Thái Ngọc Duy
2017-04-04 10:21       ` [PATCH v4 5/5] refs: kill set_worktree_head_symref() Nguyễn Thái Ngọc Duy
2017-04-14  1:40       ` [PATCH v4 0/5] Kill manual ref parsing code in worktree.c Junio C Hamano
2017-04-14  2:02         ` Junio C Hamano
2017-04-14 12:45           ` Duy Nguyen
2017-04-17  1:36             ` Junio C Hamano
2017-04-22  5:06         ` Michael Haggerty
2017-04-24 10:01       ` [PATCH v5 0/6] " Nguyễn Thái Ngọc Duy
2017-04-24 10:01         ` [PATCH v5 1/6] environment.c: fix potential segfault by get_git_common_dir() Nguyễn Thái Ngọc Duy
2017-04-24 10:01         ` [PATCH v5 2/6] refs.c: make submodule ref store hashmap generic Nguyễn Thái Ngọc Duy
2017-04-24 10:01         ` [PATCH v5 3/6] refs: add REFS_STORE_ALL_CAPS Nguyễn Thái Ngọc Duy
2017-04-24 10:01         ` [PATCH v5 4/6] refs: introduce get_worktree_ref_store() Nguyễn Thái Ngọc Duy
2017-04-24 10:01         ` [PATCH v5 5/6] worktree.c: kill parse_ref() in favor of refs_resolve_ref_unsafe() Nguyễn Thái Ngọc Duy
2017-04-24 10:01         ` [PATCH v5 6/6] refs: kill set_worktree_head_symref() Nguyễn Thái Ngọc Duy
2017-04-25  4:30         ` [PATCH v5 0/6] Kill manual ref parsing code in worktree.c 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=20170208113144.8201-3-pclouds@gmail.com \
    --to=pclouds@gmail.com \
    --cc=git@vger.kernel.org \
    --cc=gitster@pobox.com \
    --cc=mhagger@alum.mit.edu \
    /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).