possible to checkout same branch in different worktree

classic Classic list List threaded Threaded
117 messages Options
1234 ... 6
Reply | Threaded
Open this post in threaded view
|

possible to checkout same branch in different worktree

Reto Hablützel
Hi,

the checkout command prevents me from checking out a branch in the
current worktree if it is already checked out in another worktree.

However, if I rebase the branch in the current worktree onto the
branch in the other worktree, I end up in a situation where the same
branch is checked out twice in the two worktrees.

- Reto

--

PGP
Key ID = 0x67D30264
Fingerprint = E235 F740 4419 5B4B 29EC 3437 CBF2 2CB7 67D3 0264
--
To unsubscribe from this list: send the line "unsubscribe git" in
the body of a message to [hidden email]
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Reply | Threaded
Open this post in threaded view
|

Re: possible to checkout same branch in different worktree

Junio C Hamano
Reto Hablützel <[hidden email]> writes:

> the checkout command prevents me from checking out a branch in the
> current worktree if it is already checked out in another worktree.
>
> However, if I rebase the branch in the current worktree onto the
> branch in the other worktree, I end up in a situation where the same
> branch is checked out twice in the two worktrees.

I agree that any end-user facing subcommand like "git rebase", even
if it is not "git checkout", should refuse to work on and update a
branch that is checked out elsewhere.  Otherwise it will end up
causing confusion.

Thanks for a report.  The "multiple worktree" feature is still
highly experimental and those who are working on it would appreciate
your reporting issues with it.
--
To unsubscribe from this list: send the line "unsubscribe git" in
the body of a message to [hidden email]
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Reply | Threaded
Open this post in threaded view
|

Re: possible to checkout same branch in different worktree

Duy Nguyen
On Fri, Apr 15, 2016 at 10:36 PM, Junio C Hamano <[hidden email]> wrote:

> Reto Hablützel <[hidden email]> writes:
>
>> the checkout command prevents me from checking out a branch in the
>> current worktree if it is already checked out in another worktree.
>>
>> However, if I rebase the branch in the current worktree onto the
>> branch in the other worktree, I end up in a situation where the same
>> branch is checked out twice in the two worktrees.
>
> I agree that any end-user facing subcommand like "git rebase", even
> if it is not "git checkout", should refuse to work on and update a
> branch that is checked out elsewhere.  Otherwise it will end up
> causing confusion.

I agree. I suppose we need same treatment for git-push? A push can be
rejected if the pushed ref is being checked out. Suppose HEAD is in
the middle of a rebase (or am), it fails to detect ref name (and thus
checkout state) the same way here and we definitely do not want "git
rebase" to simply overwrite whatever is updated by the push request.
--
Duy
--
To unsubscribe from this list: send the line "unsubscribe git" in
the body of a message to [hidden email]
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Reply | Threaded
Open this post in threaded view
|

[PATCH 0/7] fix checking out a being-rebased branch

Duy Nguyen
First cut. I need opinions on 05/07, which converts
wt_status_get_state() to support selecting any worktree. I'm not super
happy with leaving "TODO: not supported yet" comments, even though
strictly speaking this series does not need it.

The reason it's left unsupported is, in order to add
worktree_get_sha1() or similar, resolve_ref() will be touched. But
that function is going under some changes for quite some time now, for
lmdb backend support, and I don't want to create more code conflicts
there, potentially delaying lmdb backend further.

Another option is leave wt_status_get_state() alone, factor out the
rebase-detection code and use that for worktree/checkout. We save a
few syscalls this way too.

Comments?

  [01/07] path.c: add git_common_path() and strbuf_git_common_path()
  [02/07] worktree.c: store "id" instead of "git_dir"
  [03/07] path.c: refactor and add worktree_git_path()
  [04/07] worktree.c: add worktree_git_path_..._head()
  [05/07] wt-status.c: make wt_status_get_state() support worktree
  [06/07] worktree.c: avoid referencing to worktrees[i] multiple times
  [07/07] checkout: prevent checking out a branch being rebased in another worktree

Total 6 files changed, 167 insertions(+), 38 deletions(-)
--
To unsubscribe from this list: send the line "unsubscribe git" in
the body of a message to [hidden email]
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Reply | Threaded
Open this post in threaded view
|

[PATCH 1/7] path.c: add git_common_path() and strbuf_git_common_path()

Duy Nguyen
These are mostly convenient functions to reduce code duplication. Most
of the time, we should be able to get by with git_path() which handles
$GIT_COMMON_DIR internally. However there are a few cases where we need
to construct paths manually, for example some paths from a specific
worktree. These functions will enable that.

Signed-off-by: Nguyễn Thái Ngọc Duy <[hidden email]>
---
 cache.h |  3 +++
 path.c  | 29 +++++++++++++++++++++++++++++
 2 files changed, 32 insertions(+)

diff --git a/cache.h b/cache.h
index 2711048..c04a17f 100644
--- a/cache.h
+++ b/cache.h
@@ -799,11 +799,14 @@ extern void check_repository_format(void);
  */
 extern const char *mkpath(const char *fmt, ...) __attribute__((format (printf, 1, 2)));
 extern const char *git_path(const char *fmt, ...) __attribute__((format (printf, 1, 2)));
+extern const char *git_common_path(const char *fmt, ...) __attribute__((format (printf, 1, 2)));
 
 extern char *mksnpath(char *buf, size_t n, const char *fmt, ...)
  __attribute__((format (printf, 3, 4)));
 extern void strbuf_git_path(struct strbuf *sb, const char *fmt, ...)
  __attribute__((format (printf, 2, 3)));
+extern void strbuf_git_common_path(struct strbuf *sb, const char *fmt, ...)
+ __attribute__((format (printf, 2, 3)));
 extern char *git_path_buf(struct strbuf *buf, const char *fmt, ...)
  __attribute__((format (printf, 2, 3)));
 extern void strbuf_git_path_submodule(struct strbuf *sb, const char *path,
diff --git a/path.c b/path.c
index bbaea5a..2ebb23d 100644
--- a/path.c
+++ b/path.c
@@ -503,6 +503,35 @@ void strbuf_git_path_submodule(struct strbuf *buf, const char *path,
  va_end(args);
 }
 
+static void do_git_common_path(struct strbuf *buf,
+       const char *fmt,
+       va_list args)
+{
+ strbuf_addstr(buf, get_git_common_dir());
+ if (buf->len && !is_dir_sep(buf->buf[buf->len - 1]))
+ strbuf_addch(buf, '/');
+ strbuf_vaddf(buf, fmt, args);
+ strbuf_cleanup_path(buf);
+}
+
+const char *git_common_path(const char *fmt, ...)
+{
+ struct strbuf *pathname = get_pathname();
+ va_list args;
+ va_start(args, fmt);
+ do_git_common_path(pathname, fmt, args);
+ va_end(args);
+ return pathname->buf;
+}
+
+void strbuf_git_common_path(struct strbuf *sb, const char *fmt, ...)
+{
+ va_list args;
+ va_start(args, fmt);
+ do_git_common_path(sb, fmt, args);
+ va_end(args);
+}
+
 int validate_headref(const char *path)
 {
  struct stat st;
--
2.8.0.rc0.210.gd302cd2

--
To unsubscribe from this list: send the line "unsubscribe git" in
the body of a message to [hidden email]
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Reply | Threaded
Open this post in threaded view
|

[PATCH 2/7] worktree.c: store "id" instead of "git_dir"

Duy Nguyen
In reply to this post by Duy Nguyen
We can reconstruct git_dir from id quite easily. It's a bit hackier to
do the reverse.

Signed-off-by: Nguyễn Thái Ngọc Duy <[hidden email]>
---
 worktree.c | 31 ++++++++++++++++++-------------
 worktree.h |  8 +++++++-
 2 files changed, 25 insertions(+), 14 deletions(-)

diff --git a/worktree.c b/worktree.c
index 6181a66..5ae54f0 100644
--- a/worktree.c
+++ b/worktree.c
@@ -9,7 +9,7 @@ void free_worktrees(struct worktree **worktrees)
 
  for (i = 0; worktrees[i]; i++) {
  free(worktrees[i]->path);
- free(worktrees[i]->git_dir);
+ free(worktrees[i]->id);
  free(worktrees[i]->head_ref);
  free(worktrees[i]);
  }
@@ -74,13 +74,11 @@ static struct worktree *get_main_worktree(void)
  struct worktree *worktree = NULL;
  struct strbuf path = STRBUF_INIT;
  struct strbuf worktree_path = STRBUF_INIT;
- struct strbuf gitdir = STRBUF_INIT;
  struct strbuf head_ref = STRBUF_INIT;
  int is_bare = 0;
  int is_detached = 0;
 
- strbuf_addf(&gitdir, "%s", absolute_path(get_git_common_dir()));
- strbuf_addbuf(&worktree_path, &gitdir);
+ strbuf_addstr(&worktree_path, absolute_path(get_git_common_dir()));
  is_bare = !strbuf_strip_suffix(&worktree_path, "/.git");
  if (is_bare)
  strbuf_strip_suffix(&worktree_path, "/.");
@@ -92,7 +90,7 @@ static struct worktree *get_main_worktree(void)
 
  worktree = xmalloc(sizeof(struct worktree));
  worktree->path = strbuf_detach(&worktree_path, NULL);
- worktree->git_dir = strbuf_detach(&gitdir, NULL);
+ worktree->id = NULL;
  worktree->is_bare = is_bare;
  worktree->head_ref = NULL;
  worktree->is_detached = is_detached;
@@ -100,7 +98,6 @@ static struct worktree *get_main_worktree(void)
 
 done:
  strbuf_release(&path);
- strbuf_release(&gitdir);
  strbuf_release(&worktree_path);
  strbuf_release(&head_ref);
  return worktree;
@@ -111,16 +108,13 @@ 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 gitdir = STRBUF_INIT;
  struct strbuf head_ref = STRBUF_INIT;
  int is_detached = 0;
 
  if (!id)
  die("Missing linked worktree name");
 
- strbuf_addf(&gitdir, "%s/worktrees/%s",
- absolute_path(get_git_common_dir()), id);
- strbuf_addf(&path, "%s/gitdir", gitdir.buf);
+ strbuf_git_common_path(&path, "worktrees/%s/gitdir", id);
  if (strbuf_read_file(&worktree_path, path.buf, 0) <= 0)
  /* invalid gitdir file */
  goto done;
@@ -140,7 +134,7 @@ static struct worktree *get_linked_worktree(const char *id)
 
  worktree = xmalloc(sizeof(struct worktree));
  worktree->path = strbuf_detach(&worktree_path, NULL);
- worktree->git_dir = strbuf_detach(&gitdir, NULL);
+ worktree->id = xstrdup(id);
  worktree->is_bare = 0;
  worktree->head_ref = NULL;
  worktree->is_detached = is_detached;
@@ -148,7 +142,6 @@ static struct worktree *get_linked_worktree(const char *id)
 
 done:
  strbuf_release(&path);
- strbuf_release(&gitdir);
  strbuf_release(&worktree_path);
  strbuf_release(&head_ref);
  return worktree;
@@ -188,6 +181,16 @@ struct worktree **get_worktrees(void)
  return list;
 }
 
+const char *get_worktree_git_dir(const struct worktree *wt)
+{
+ if (!wt)
+ return get_git_dir();
+ else if (!wt->id)
+ return get_git_common_dir();
+ else
+ return git_common_path("worktrees/%s", wt->id);
+}
+
 char *find_shared_symref(const char *symref, const char *target)
 {
  char *existing = NULL;
@@ -199,7 +202,9 @@ char *find_shared_symref(const char *symref, const char *target)
  for (i = 0; worktrees[i]; i++) {
  strbuf_reset(&path);
  strbuf_reset(&sb);
- strbuf_addf(&path, "%s/%s", worktrees[i]->git_dir, symref);
+ strbuf_addf(&path, "%s/%s",
+    get_worktree_git_dir(worktrees[i]),
+    symref);
 
  if (parse_ref(path.buf, &sb, NULL)) {
  continue;
diff --git a/worktree.h b/worktree.h
index b4b3dda..3198c8d 100644
--- a/worktree.h
+++ b/worktree.h
@@ -3,7 +3,7 @@
 
 struct worktree {
  char *path;
- char *git_dir;
+ char *id;
  char *head_ref;
  unsigned char head_sha1[20];
  int is_detached;
@@ -23,6 +23,12 @@ struct worktree {
 extern struct worktree **get_worktrees(void);
 
 /*
+ * Return git dir of the worktree. Note that the path may be relative.
+ * If wt is NULL, git dir of current worktree is returned.
+ */
+extern const char *get_worktree_git_dir(const struct worktree *wt);
+
+/*
  * Free up the memory for worktree(s)
  */
 extern void free_worktrees(struct worktree **);
--
2.8.0.rc0.210.gd302cd2

--
To unsubscribe from this list: send the line "unsubscribe git" in
the body of a message to [hidden email]
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Reply | Threaded
Open this post in threaded view
|

[PATCH 3/7] path.c: refactor and add worktree_git_path()

Duy Nguyen
In reply to this post by Duy Nguyen
do_git_path(), which is the common code for all git_path* functions, is
modified to take a worktree struct and can produce paths for any
worktree.

worktree_git_path() is the first function that makes use of this. It can
be used to write code that can examine any worktree. For example,
wt_status_get_state() will be converted using this to take
am/rebase/... state of any worktree.

Signed-off-by: Nguyễn Thái Ngọc Duy <[hidden email]>
---
 path.c     | 34 ++++++++++++++++++++++++++++------
 worktree.h | 11 +++++++++++
 2 files changed, 39 insertions(+), 6 deletions(-)

diff --git a/path.c b/path.c
index 2ebb23d..c421d37 100644
--- a/path.c
+++ b/path.c
@@ -5,6 +5,7 @@
 #include "strbuf.h"
 #include "string-list.h"
 #include "dir.h"
+#include "worktree.h"
 
 static int get_st_mode_bits(const char *path, int *mode)
 {
@@ -383,10 +384,11 @@ static void adjust_git_path(struct strbuf *buf, int git_dir_len)
  update_common_dir(buf, git_dir_len, NULL);
 }
 
-static void do_git_path(struct strbuf *buf, const char *fmt, va_list args)
+static void do_git_path(const struct worktree *wt, struct strbuf *buf,
+ const char *fmt, va_list args)
 {
  int gitdir_len;
- strbuf_addstr(buf, get_git_dir());
+ strbuf_addstr(buf, get_worktree_git_dir(wt));
  if (buf->len && !is_dir_sep(buf->buf[buf->len - 1]))
  strbuf_addch(buf, '/');
  gitdir_len = buf->len;
@@ -400,7 +402,7 @@ char *git_path_buf(struct strbuf *buf, const char *fmt, ...)
  va_list args;
  strbuf_reset(buf);
  va_start(args, fmt);
- do_git_path(buf, fmt, args);
+ do_git_path(NULL, buf, fmt, args);
  va_end(args);
  return buf->buf;
 }
@@ -409,7 +411,7 @@ void strbuf_git_path(struct strbuf *sb, const char *fmt, ...)
 {
  va_list args;
  va_start(args, fmt);
- do_git_path(sb, fmt, args);
+ do_git_path(NULL, sb, fmt, args);
  va_end(args);
 }
 
@@ -418,7 +420,7 @@ const char *git_path(const char *fmt, ...)
  struct strbuf *pathname = get_pathname();
  va_list args;
  va_start(args, fmt);
- do_git_path(pathname, fmt, args);
+ do_git_path(NULL, pathname, fmt, args);
  va_end(args);
  return pathname->buf;
 }
@@ -428,7 +430,7 @@ char *git_pathdup(const char *fmt, ...)
  struct strbuf path = STRBUF_INIT;
  va_list args;
  va_start(args, fmt);
- do_git_path(&path, fmt, args);
+ do_git_path(NULL, &path, fmt, args);
  va_end(args);
  return strbuf_detach(&path, NULL);
 }
@@ -454,6 +456,26 @@ const char *mkpath(const char *fmt, ...)
  return cleanup_path(pathname->buf);
 }
 
+const char *worktree_git_path(const struct worktree *wt, const char *fmt, ...)
+{
+ struct strbuf *pathname = get_pathname();
+ va_list args;
+ va_start(args, fmt);
+ do_git_path(wt, pathname, fmt, args);
+ va_end(args);
+ return pathname->buf;
+}
+
+char *worktree_git_pathdup(const struct worktree *wt, const char *fmt, ...)
+{
+ struct strbuf path = STRBUF_INIT;
+ va_list args;
+ va_start(args, fmt);
+ do_git_path(wt, &path, fmt, args);
+ va_end(args);
+ return strbuf_detach(&path, NULL);
+}
+
 static void do_submodule_path(struct strbuf *buf, const char *path,
       const char *fmt, va_list args)
 {
diff --git a/worktree.h b/worktree.h
index 3198c8d..9ae2028 100644
--- a/worktree.h
+++ b/worktree.h
@@ -41,4 +41,15 @@ extern void free_worktrees(struct worktree **);
  */
 extern char *find_shared_symref(const char *symref, const char *target);
 
+/*
+ * Similar to git_path() and git_pathdup() but can produce paths for a
+ * specified worktree instead of current one
+ */
+extern const char *worktree_git_path(const struct worktree *wt,
+     const char *fmt, ...)
+ __attribute__((format (printf, 2, 3)));
+extern char *worktree_git_pathdup(const struct worktree *wt,
+  const char *fmt, ...)
+ __attribute__((format (printf, 2, 3)));
+
 #endif
--
2.8.0.rc0.210.gd302cd2

--
To unsubscribe from this list: send the line "unsubscribe git" in
the body of a message to [hidden email]
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Reply | Threaded
Open this post in threaded view
|

[PATCH 4/7] worktree.c: add worktree_git_path_..._head()

Duy Nguyen
In reply to this post by Duy Nguyen
These are a variant of git_path_..._head(), defined with GIT_PATH_FUNC
macro but they takes worktree into account. To be used when
wt_status_get_state() is converted to be worktree-aware.

Signed-off-by: Nguyễn Thái Ngọc Duy <[hidden email]>
---
 worktree.c |  4 ++++
 worktree.h | 13 +++++++++++++
 2 files changed, 17 insertions(+)

diff --git a/worktree.c b/worktree.c
index 5ae54f0..c5bf583 100644
--- a/worktree.c
+++ b/worktree.c
@@ -222,3 +222,7 @@ char *find_shared_symref(const char *symref, const char *target)
 
  return existing;
 }
+
+WORKTREE_GIT_PATH_FUNC(merge_head, "MERGE_HEAD")
+WORKTREE_GIT_PATH_FUNC(cherry_pick_head, "CHERRY_PICK_HEAD")
+WORKTREE_GIT_PATH_FUNC(revert_head, "REVERT_HEAD")
diff --git a/worktree.h b/worktree.h
index 9ae2028..b7c5da0 100644
--- a/worktree.h
+++ b/worktree.h
@@ -52,4 +52,17 @@ extern char *worktree_git_pathdup(const struct worktree *wt,
   const char *fmt, ...)
  __attribute__((format (printf, 2, 3)));
 
+#define WORKTREE_GIT_PATH_FUNC(func, filename) \
+ const char *worktree_git_path_ ## func(const struct worktree *wt) \
+ { \
+ static char *ret; \
+ if (!ret) \
+ ret = worktree_git_pathdup(wt, filename); \
+ return ret; \
+ }
+
+const char *worktree_git_path_merge_head(const struct worktree *);
+const char *worktree_git_path_cherry_pick_head(const struct worktree *);
+const char *worktree_git_path_revert_head(const struct worktree *);
+
 #endif
--
2.8.0.rc0.210.gd302cd2

--
To unsubscribe from this list: send the line "unsubscribe git" in
the body of a message to [hidden email]
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Reply | Threaded
Open this post in threaded view
|

[PATCH 5/7] wt-status.c: make wt_status_get_state() support worktree

Duy Nguyen
In reply to this post by Duy Nguyen
The function is to be used to detect if a ref is checked out in another
worktree. In some cases, parsing "HEAD" alone is not enough because the
worktree may be under rebase or bisect.

Note that because get_sha1() cannot take a worktree (and of course will
not, we need something like worktree_get_sha1), cherry-pick and revert
detection will not work when the examined worktree is not the current
one. The same for get_detached_from.

Signed-off-by: Nguyễn Thái Ngọc Duy <[hidden email]>
---
 wt-status.c | 42 +++++++++++++++++++++++++-----------------
 wt-status.h |  3 +++
 2 files changed, 28 insertions(+), 17 deletions(-)

diff --git a/wt-status.c b/wt-status.c
index 1ea2ebe..6cca3a6 100644
--- a/wt-status.c
+++ b/wt-status.c
@@ -15,6 +15,7 @@
 #include "column.h"
 #include "strbuf.h"
 #include "utf8.h"
+#include "worktree.h"
 
 static const char cut_line[] =
 "------------------------ >8 ------------------------\n";
@@ -1262,13 +1263,13 @@ static void show_bisect_in_progress(struct wt_status *s,
 /*
  * Extract branch information from rebase/bisect
  */
-static char *read_and_strip_branch(const char *path)
+static char *read_and_strip_branch(const struct worktree *wt, const char *path)
 {
  struct strbuf sb = STRBUF_INIT;
  unsigned char sha1[20];
  const char *branch_name;
 
- if (strbuf_read_file(&sb, git_path("%s", path), 0) <= 0)
+ if (strbuf_read_file(&sb, worktree_git_path(wt, "%s", path), 0) <= 0)
  goto got_nothing;
 
  while (sb.len && sb.buf[sb.len - 1] == '\n')
@@ -1363,45 +1364,52 @@ static void wt_status_get_detached_from(struct wt_status_state *state)
 void wt_status_get_state(struct wt_status_state *state,
  int get_detached_from)
 {
+ const struct worktree *wt = state->wt;
  struct stat st;
  unsigned char sha1[20];
 
- if (!stat(git_path_merge_head(), &st)) {
+ if (!stat(worktree_git_path_merge_head(wt), &st)) {
  state->merge_in_progress = 1;
- } else if (!stat(git_path("rebase-apply"), &st)) {
- if (!stat(git_path("rebase-apply/applying"), &st)) {
+ } else if (!stat(worktree_git_path(wt, "rebase-apply"), &st)) {
+ if (!stat(worktree_git_path(wt, "rebase-apply/applying"), &st)) {
  state->am_in_progress = 1;
- if (!stat(git_path("rebase-apply/patch"), &st) && !st.st_size)
+ if (!stat(worktree_git_path(wt, "rebase-apply/patch"), &st) && !st.st_size)
  state->am_empty_patch = 1;
  } else {
  state->rebase_in_progress = 1;
- state->branch = read_and_strip_branch("rebase-apply/head-name");
- state->onto = read_and_strip_branch("rebase-apply/onto");
+ state->branch = read_and_strip_branch(wt, "rebase-apply/head-name");
+ state->onto = read_and_strip_branch(wt, "rebase-apply/onto");
  }
- } else if (!stat(git_path("rebase-merge"), &st)) {
- if (!stat(git_path("rebase-merge/interactive"), &st))
+ } else if (!stat(worktree_git_path(wt, "rebase-merge"), &st)) {
+ if (!stat(worktree_git_path(wt, "rebase-merge/interactive"), &st))
  state->rebase_interactive_in_progress = 1;
  else
  state->rebase_in_progress = 1;
- state->branch = read_and_strip_branch("rebase-merge/head-name");
- state->onto = read_and_strip_branch("rebase-merge/onto");
- } else if (!stat(git_path_cherry_pick_head(), &st) &&
+ state->branch = read_and_strip_branch(wt, "rebase-merge/head-name");
+ state->onto = read_and_strip_branch(wt, "rebase-merge/onto");
+ } else if (!wt && /* TODO: get_sha1() cannot select worktree yet */
+   !stat(worktree_git_path_cherry_pick_head(wt), &st) &&
  !get_sha1("CHERRY_PICK_HEAD", sha1)) {
  state->cherry_pick_in_progress = 1;
  hashcpy(state->cherry_pick_head_sha1, sha1);
  }
- if (!stat(git_path("BISECT_LOG"), &st)) {
+ if (!stat(worktree_git_path(wt, "BISECT_LOG"), &st)) {
  state->bisect_in_progress = 1;
- state->branch = read_and_strip_branch("BISECT_START");
+ state->branch = read_and_strip_branch(wt, "BISECT_START");
  }
- if (!stat(git_path_revert_head(), &st) &&
+ if (!wt &&  /* TODO: get_sha1() cannot select worktree yet */
+    !stat(worktree_git_path_revert_head(wt), &st) &&
     !get_sha1("REVERT_HEAD", sha1)) {
  state->revert_in_progress = 1;
  hashcpy(state->revert_head_sha1, sha1);
  }
 
- if (get_detached_from)
+ if (get_detached_from) {
+ if (wt)
+ die("BUG: %s:%d: non-zero get_detached_from is not supported",
+    __FILE__, __LINE__);
  wt_status_get_detached_from(state);
+ }
 }
 
 static void wt_status_print_state(struct wt_status *s,
diff --git a/wt-status.h b/wt-status.h
index c9b3b74..d31db38 100644
--- a/wt-status.h
+++ b/wt-status.h
@@ -6,6 +6,8 @@
 #include "color.h"
 #include "pathspec.h"
 
+struct worktree;
+
 enum color_wt_status {
  WT_STATUS_HEADER = 0,
  WT_STATUS_UPDATED,
@@ -77,6 +79,7 @@ struct wt_status {
 };
 
 struct wt_status_state {
+ struct worktree *wt;
  int merge_in_progress;
  int am_in_progress;
  int am_empty_patch;
--
2.8.0.rc0.210.gd302cd2

--
To unsubscribe from this list: send the line "unsubscribe git" in
the body of a message to [hidden email]
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Reply | Threaded
Open this post in threaded view
|

[PATCH 6/7] worktree.c: avoid referencing to worktrees[i] multiple times

Duy Nguyen
In reply to this post by Duy Nguyen
Signed-off-by: Nguyễn Thái Ngọc Duy <[hidden email]>
---
 worktree.c | 6 ++++--
 1 file changed, 4 insertions(+), 2 deletions(-)

diff --git a/worktree.c b/worktree.c
index c5bf583..3b7c6f2 100644
--- a/worktree.c
+++ b/worktree.c
@@ -200,10 +200,12 @@ char *find_shared_symref(const char *symref, const char *target)
  int i = 0;
 
  for (i = 0; worktrees[i]; i++) {
+ struct worktree *wt = worktrees[i];
+
  strbuf_reset(&path);
  strbuf_reset(&sb);
  strbuf_addf(&path, "%s/%s",
-    get_worktree_git_dir(worktrees[i]),
+    get_worktree_git_dir(wt),
     symref);
 
  if (parse_ref(path.buf, &sb, NULL)) {
@@ -211,7 +213,7 @@ char *find_shared_symref(const char *symref, const char *target)
  }
 
  if (!strcmp(sb.buf, target)) {
- existing = xstrdup(worktrees[i]->path);
+ existing = xstrdup(wt->path);
  break;
  }
  }
--
2.8.0.rc0.210.gd302cd2

--
To unsubscribe from this list: send the line "unsubscribe git" in
the body of a message to [hidden email]
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Reply | Threaded
Open this post in threaded view
|

[PATCH 7/7] checkout: prevent checking out a branch being rebased in another worktree

Duy Nguyen
In reply to this post by Duy Nguyen
We failed to detect this case because the rebase-in-progress worktree
has HEAD in detached state. Some more poking around is needed to
determine if a rebase is in progress.

Note that even though bisect can also put a worktree in detached state
and hide the real branch, we allow to checkout anyway. This is because
unlike rebase, bisect does not update the branch. Yes it's still a bit
confusing when the user doing the bisecting realizes that the branch is
updated elsewhere, but at least we do not lose any valuable ref update.

Signed-off-by: Nguyễn Thái Ngọc Duy <[hidden email]>
---
 worktree.c | 23 +++++++++++++++++++++++
 1 file changed, 23 insertions(+)

diff --git a/worktree.c b/worktree.c
index 3b7c6f2..6dc40c2 100644
--- a/worktree.c
+++ b/worktree.c
@@ -2,6 +2,7 @@
 #include "refs.h"
 #include "strbuf.h"
 #include "worktree.h"
+#include "wt-status.h"
 
 void free_worktrees(struct worktree **worktrees)
 {
@@ -202,6 +203,28 @@ char *find_shared_symref(const char *symref, const char *target)
  for (i = 0; worktrees[i]; i++) {
  struct worktree *wt = worktrees[i];
 
+ if (wt->is_detached) {
+ struct wt_status_state wss;
+ int found;
+
+ memset(&wss, 0, sizeof(wss));
+ wss.wt = wt;
+ wt_status_get_state(&wss, 0);
+ found = (wss.rebase_in_progress ||
+ wss.rebase_interactive_in_progress) &&
+ wss.branch &&
+ starts_with(target, "refs/heads/") &&
+ !strcmp(wss.branch,
+ target + strlen("refs/heads/"));
+ free(wss.branch);
+ free(wss.onto);
+ free(wss.detached_from);
+ if (found) {
+ existing = xstrdup(wt->path);
+ break;
+ }
+ }
+
  strbuf_reset(&path);
  strbuf_reset(&sb);
  strbuf_addf(&path, "%s/%s",
--
2.8.0.rc0.210.gd302cd2

--
To unsubscribe from this list: send the line "unsubscribe git" in
the body of a message to [hidden email]
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Reply | Threaded
Open this post in threaded view
|

Re: [PATCH 0/7] fix checking out a being-rebased branch

Junio C Hamano
In reply to this post by Duy Nguyen
Nguyễn Thái Ngọc Duy  <[hidden email]> writes:

> First cut. I need opinions on 05/07, which converts
> wt_status_get_state() to support selecting any worktree. I'm not super
> happy with leaving "TODO: not supported yet" comments, even though
> strictly speaking this series does not need it.

It is a reasonable idea to hook this to wt_status_get_state(), I
would say.

> Another option is leave wt_status_get_state() alone, factor out the
> rebase-detection code and use that for worktree/checkout. We save a
> few syscalls this way too.
>
> Comments?
>
>   [01/07] path.c: add git_common_path() and strbuf_git_common_path()
>   [02/07] worktree.c: store "id" instead of "git_dir"
>   [03/07] path.c: refactor and add worktree_git_path()
>   [04/07] worktree.c: add worktree_git_path_..._head()

I actually wondered how ky/branch-[dm]-worktree topics to avoid
"branch -d" and "branch -m" from removing or renaming a branch that
is checked out in other worktrees from screwing them up.  There may
be a missed opportunity to clean them up with using these?

>   [05/07] wt-status.c: make wt_status_get_state() support worktree
>   [06/07] worktree.c: avoid referencing to worktrees[i] multiple times
>   [07/07] checkout: prevent checking out a branch being rebased in another worktree
>
> Total 6 files changed, 167 insertions(+), 38 deletions(-)
--
To unsubscribe from this list: send the line "unsubscribe git" in
the body of a message to [hidden email]
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Reply | Threaded
Open this post in threaded view
|

Re: [PATCH 0/7] fix checking out a being-rebased branch

Duy Nguyen
On Tue, Apr 19, 2016 at 12:42 AM, Junio C Hamano <[hidden email]> wrote:

>> Another option is leave wt_status_get_state() alone, factor out the
>> rebase-detection code and use that for worktree/checkout. We save a
>> few syscalls this way too.
>>
>> Comments?
>>
>>   [01/07] path.c: add git_common_path() and strbuf_git_common_path()
>>   [02/07] worktree.c: store "id" instead of "git_dir"
>>   [03/07] path.c: refactor and add worktree_git_path()
>>   [04/07] worktree.c: add worktree_git_path_..._head()
>
> I actually wondered how ky/branch-[dm]-worktree topics to avoid
> "branch -d" and "branch -m" from removing or renaming a branch that
> is checked out in other worktrees from screwing them up.  There may
> be a missed opportunity to clean them up with using these?

branch-m-worktree uses info populated at get_worktrees() phase.
branch-d-worktree uses find_shared_symref() which is modified in this
series in order to detect rebase branch. So both topics have the same
problem when a branch is being rebased and if I do it right, I'll fix
them both without extra code. Actually I may need to check
branch-m-worktree again, renaming a branch under rebase might cause
problems, I need to have a closer look at git-rebase*.sh.
--
Duy
--
To unsubscribe from this list: send the line "unsubscribe git" in
the body of a message to [hidden email]
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Reply | Threaded
Open this post in threaded view
|

Re: [PATCH 0/7] fix checking out a being-rebased branch

Junio C Hamano
Duy Nguyen <[hidden email]> writes:

> On Tue, Apr 19, 2016 at 12:42 AM, Junio C Hamano <[hidden email]> wrote:
>>> Another option is leave wt_status_get_state() alone, factor out the
>>> rebase-detection code and use that for worktree/checkout. We save a
>>> few syscalls this way too.
>>>
>>> Comments?
>>>
>>>   [01/07] path.c: add git_common_path() and strbuf_git_common_path()
>>>   [02/07] worktree.c: store "id" instead of "git_dir"
>>>   [03/07] path.c: refactor and add worktree_git_path()
>>>   [04/07] worktree.c: add worktree_git_path_..._head()
>>
>> I actually wondered how ky/branch-[dm]-worktree topics to avoid
>> "branch -d" and "branch -m" from removing or renaming a branch that
>> is checked out in other worktrees from screwing them up.  There may
>> be a missed opportunity to clean them up with using these?
>
> branch-m-worktree uses info populated at get_worktrees() phase.
> branch-d-worktree uses find_shared_symref() which is modified in this
> series in order to detect rebase branch. So both topics have the same
> problem when a branch is being rebased and if I do it right, I'll fix
> them both without extra code.

Yup, that was exactly why I brought it up.

> Actually I may need to check branch-m-worktree again, renaming a
> branch under rebase might cause problems, I need to have a closer
> look at git-rebase*.sh.

Thanks.
--
To unsubscribe from this list: send the line "unsubscribe git" in
the body of a message to [hidden email]
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Reply | Threaded
Open this post in threaded view
|

[PATCH v2 00/12] fix checking out a being-rebased branch

Duy Nguyen
In reply to this post by Duy Nguyen
Much happier with this version. This makes

 - git checkout refuse if a branch is under rebase or bisect
   elsewhere

 - git worktree add refuse if a branch is under rebase or bisect

 - git branch -D refuse if a branch is under rebase or bisect.
   This applies for single worktree case as well.

 - git branch -M refuse if a branch is under rebase or bisect
   (single worktree case as well)

  [01/12] path.c: add git_common_path() and strbuf_git_common_path()
  [02/12] worktree.c: store "id" instead of "git_dir"
  [03/12] worktree.c: make find_shared_symref() return struct worktree *
  [04/12] worktree.c: mark current worktree
  [05/12] path.c: refactor and add worktree_git_path()
  [06/12] wt-status.c: split rebase detection out of wt_status_get_state()
  [07/12] wt-status.c: make wt_status_check_rebase() work on any worktree
  [08/12] worktree.c: avoid referencing to worktrees[i] multiple times
  [09/12] worktree.c: test if branch being rebased in another worktree
  [10/12] wt-status.c: split bisect detection out of wt_status_get_state()
  [11/12] worktree.c: test if branch being bisected in another worktree
  [12/12] branch: do not rename a branch under bisect or rebase

Total 13 files changed, 335 insertions(+), 67 deletions(-)
--
To unsubscribe from this list: send the line "unsubscribe git" in
the body of a message to [hidden email]
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Reply | Threaded
Open this post in threaded view
|

[PATCH v2 01/12] path.c: add git_common_path() and strbuf_git_common_path()

Duy Nguyen
These are mostly convenient functions to reduce code duplication. Most
of the time, we should be able to get by with git_path() which handles
$GIT_COMMON_DIR internally. However there are a few cases where we need
to construct paths manually, for example some paths from a specific
worktree. These functions will enable that.

Signed-off-by: Nguyễn Thái Ngọc Duy <[hidden email]>
---
 cache.h |  3 +++
 path.c  | 29 +++++++++++++++++++++++++++++
 2 files changed, 32 insertions(+)

diff --git a/cache.h b/cache.h
index 2711048..c04a17f 100644
--- a/cache.h
+++ b/cache.h
@@ -799,11 +799,14 @@ extern void check_repository_format(void);
  */
 extern const char *mkpath(const char *fmt, ...) __attribute__((format (printf, 1, 2)));
 extern const char *git_path(const char *fmt, ...) __attribute__((format (printf, 1, 2)));
+extern const char *git_common_path(const char *fmt, ...) __attribute__((format (printf, 1, 2)));
 
 extern char *mksnpath(char *buf, size_t n, const char *fmt, ...)
  __attribute__((format (printf, 3, 4)));
 extern void strbuf_git_path(struct strbuf *sb, const char *fmt, ...)
  __attribute__((format (printf, 2, 3)));
+extern void strbuf_git_common_path(struct strbuf *sb, const char *fmt, ...)
+ __attribute__((format (printf, 2, 3)));
 extern char *git_path_buf(struct strbuf *buf, const char *fmt, ...)
  __attribute__((format (printf, 2, 3)));
 extern void strbuf_git_path_submodule(struct strbuf *sb, const char *path,
diff --git a/path.c b/path.c
index bbaea5a..2ebb23d 100644
--- a/path.c
+++ b/path.c
@@ -503,6 +503,35 @@ void strbuf_git_path_submodule(struct strbuf *buf, const char *path,
  va_end(args);
 }
 
+static void do_git_common_path(struct strbuf *buf,
+       const char *fmt,
+       va_list args)
+{
+ strbuf_addstr(buf, get_git_common_dir());
+ if (buf->len && !is_dir_sep(buf->buf[buf->len - 1]))
+ strbuf_addch(buf, '/');
+ strbuf_vaddf(buf, fmt, args);
+ strbuf_cleanup_path(buf);
+}
+
+const char *git_common_path(const char *fmt, ...)
+{
+ struct strbuf *pathname = get_pathname();
+ va_list args;
+ va_start(args, fmt);
+ do_git_common_path(pathname, fmt, args);
+ va_end(args);
+ return pathname->buf;
+}
+
+void strbuf_git_common_path(struct strbuf *sb, const char *fmt, ...)
+{
+ va_list args;
+ va_start(args, fmt);
+ do_git_common_path(sb, fmt, args);
+ va_end(args);
+}
+
 int validate_headref(const char *path)
 {
  struct stat st;
--
2.8.0.rc0.210.gd302cd2

--
To unsubscribe from this list: send the line "unsubscribe git" in
the body of a message to [hidden email]
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Reply | Threaded
Open this post in threaded view
|

[PATCH v2 02/12] worktree.c: store "id" instead of "git_dir"

Duy Nguyen
In reply to this post by Duy Nguyen
We can reconstruct git_dir from id quite easily. It's a bit hackier to
do the reverse.

Signed-off-by: Nguyễn Thái Ngọc Duy <[hidden email]>
---
 branch.c   |  3 ++-
 worktree.c | 31 ++++++++++++++++++-------------
 worktree.h |  8 +++++++-
 3 files changed, 27 insertions(+), 15 deletions(-)

diff --git a/branch.c b/branch.c
index 4162443..0674a99 100644
--- a/branch.c
+++ b/branch.c
@@ -357,7 +357,8 @@ int replace_each_worktree_head_symref(const char *oldref, const char *newref)
  if (strcmp(oldref, worktrees[i]->head_ref))
  continue;
 
- if (set_worktree_head_symref(worktrees[i]->git_dir, newref)) {
+ if (set_worktree_head_symref(get_worktree_git_dir(worktrees[i]),
+     newref)) {
  ret = -1;
  error(_("HEAD of working tree %s is not updated"),
       worktrees[i]->path);
diff --git a/worktree.c b/worktree.c
index 6181a66..5ae54f0 100644
--- a/worktree.c
+++ b/worktree.c
@@ -9,7 +9,7 @@ void free_worktrees(struct worktree **worktrees)
 
  for (i = 0; worktrees[i]; i++) {
  free(worktrees[i]->path);
- free(worktrees[i]->git_dir);
+ free(worktrees[i]->id);
  free(worktrees[i]->head_ref);
  free(worktrees[i]);
  }
@@ -74,13 +74,11 @@ static struct worktree *get_main_worktree(void)
  struct worktree *worktree = NULL;
  struct strbuf path = STRBUF_INIT;
  struct strbuf worktree_path = STRBUF_INIT;
- struct strbuf gitdir = STRBUF_INIT;
  struct strbuf head_ref = STRBUF_INIT;
  int is_bare = 0;
  int is_detached = 0;
 
- strbuf_addf(&gitdir, "%s", absolute_path(get_git_common_dir()));
- strbuf_addbuf(&worktree_path, &gitdir);
+ strbuf_addstr(&worktree_path, absolute_path(get_git_common_dir()));
  is_bare = !strbuf_strip_suffix(&worktree_path, "/.git");
  if (is_bare)
  strbuf_strip_suffix(&worktree_path, "/.");
@@ -92,7 +90,7 @@ static struct worktree *get_main_worktree(void)
 
  worktree = xmalloc(sizeof(struct worktree));
  worktree->path = strbuf_detach(&worktree_path, NULL);
- worktree->git_dir = strbuf_detach(&gitdir, NULL);
+ worktree->id = NULL;
  worktree->is_bare = is_bare;
  worktree->head_ref = NULL;
  worktree->is_detached = is_detached;
@@ -100,7 +98,6 @@ static struct worktree *get_main_worktree(void)
 
 done:
  strbuf_release(&path);
- strbuf_release(&gitdir);
  strbuf_release(&worktree_path);
  strbuf_release(&head_ref);
  return worktree;
@@ -111,16 +108,13 @@ 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 gitdir = STRBUF_INIT;
  struct strbuf head_ref = STRBUF_INIT;
  int is_detached = 0;
 
  if (!id)
  die("Missing linked worktree name");
 
- strbuf_addf(&gitdir, "%s/worktrees/%s",
- absolute_path(get_git_common_dir()), id);
- strbuf_addf(&path, "%s/gitdir", gitdir.buf);
+ strbuf_git_common_path(&path, "worktrees/%s/gitdir", id);
  if (strbuf_read_file(&worktree_path, path.buf, 0) <= 0)
  /* invalid gitdir file */
  goto done;
@@ -140,7 +134,7 @@ static struct worktree *get_linked_worktree(const char *id)
 
  worktree = xmalloc(sizeof(struct worktree));
  worktree->path = strbuf_detach(&worktree_path, NULL);
- worktree->git_dir = strbuf_detach(&gitdir, NULL);
+ worktree->id = xstrdup(id);
  worktree->is_bare = 0;
  worktree->head_ref = NULL;
  worktree->is_detached = is_detached;
@@ -148,7 +142,6 @@ static struct worktree *get_linked_worktree(const char *id)
 
 done:
  strbuf_release(&path);
- strbuf_release(&gitdir);
  strbuf_release(&worktree_path);
  strbuf_release(&head_ref);
  return worktree;
@@ -188,6 +181,16 @@ struct worktree **get_worktrees(void)
  return list;
 }
 
+const char *get_worktree_git_dir(const struct worktree *wt)
+{
+ if (!wt)
+ return get_git_dir();
+ else if (!wt->id)
+ return get_git_common_dir();
+ else
+ return git_common_path("worktrees/%s", wt->id);
+}
+
 char *find_shared_symref(const char *symref, const char *target)
 {
  char *existing = NULL;
@@ -199,7 +202,9 @@ char *find_shared_symref(const char *symref, const char *target)
  for (i = 0; worktrees[i]; i++) {
  strbuf_reset(&path);
  strbuf_reset(&sb);
- strbuf_addf(&path, "%s/%s", worktrees[i]->git_dir, symref);
+ strbuf_addf(&path, "%s/%s",
+    get_worktree_git_dir(worktrees[i]),
+    symref);
 
  if (parse_ref(path.buf, &sb, NULL)) {
  continue;
diff --git a/worktree.h b/worktree.h
index b4b3dda..3198c8d 100644
--- a/worktree.h
+++ b/worktree.h
@@ -3,7 +3,7 @@
 
 struct worktree {
  char *path;
- char *git_dir;
+ char *id;
  char *head_ref;
  unsigned char head_sha1[20];
  int is_detached;
@@ -23,6 +23,12 @@ struct worktree {
 extern struct worktree **get_worktrees(void);
 
 /*
+ * Return git dir of the worktree. Note that the path may be relative.
+ * If wt is NULL, git dir of current worktree is returned.
+ */
+extern const char *get_worktree_git_dir(const struct worktree *wt);
+
+/*
  * Free up the memory for worktree(s)
  */
 extern void free_worktrees(struct worktree **);
--
2.8.0.rc0.210.gd302cd2

--
To unsubscribe from this list: send the line "unsubscribe git" in
the body of a message to [hidden email]
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Reply | Threaded
Open this post in threaded view
|

[PATCH v2 03/12] worktree.c: make find_shared_symref() return struct worktree *

Duy Nguyen
In reply to this post by Duy Nguyen
This gives the caller more information and they can answer things like,
"is it the main worktree" or "is it the current worktree". The latter
question is needed for the "checkout a rebase branch" case later.

Signed-off-by: Nguyễn Thái Ngọc Duy <[hidden email]>
---
 branch.c         |  9 +++++----
 builtin/branch.c |  8 ++++----
 builtin/notes.c  |  8 ++++----
 worktree.c       | 14 +++++++++-----
 worktree.h       |  7 ++++---
 5 files changed, 26 insertions(+), 20 deletions(-)

diff --git a/branch.c b/branch.c
index 0674a99..a84fb2c 100644
--- a/branch.c
+++ b/branch.c
@@ -336,12 +336,13 @@ void remove_branch_state(void)
 
 void die_if_checked_out(const char *branch)
 {
- char *existing;
+ const struct worktree *wt;
 
- existing = find_shared_symref("HEAD", branch);
- if (existing) {
+ wt = find_shared_symref("HEAD", branch);
+ if (wt) {
  skip_prefix(branch, "refs/heads/", &branch);
- die(_("'%s' is already checked out at '%s'"), branch, existing);
+ die(_("'%s' is already checked out at '%s'"),
+    branch, wt->path);
  }
 }
 
diff --git a/builtin/branch.c b/builtin/branch.c
index 0adba62..bcde87d 100644
--- a/builtin/branch.c
+++ b/builtin/branch.c
@@ -220,12 +220,12 @@ static int delete_branches(int argc, const char **argv, int force, int kinds,
  name = mkpathdup(fmt, bname.buf);
 
  if (kinds == FILTER_REFS_BRANCHES) {
- char *worktree = find_shared_symref("HEAD", name);
- if (worktree) {
+ const struct worktree *wt =
+ find_shared_symref("HEAD", name);
+ if (wt) {
  error(_("Cannot delete branch '%s' "
  "checked out at '%s'"),
-      bname.buf, worktree);
- free(worktree);
+      bname.buf, wt->path);
  ret = 1;
  continue;
  }
diff --git a/builtin/notes.c b/builtin/notes.c
index 6fd058d..c65b59a 100644
--- a/builtin/notes.c
+++ b/builtin/notes.c
@@ -847,15 +847,15 @@ static int merge(int argc, const char **argv, const char *prefix)
  update_ref(msg.buf, default_notes_ref(), result_sha1, NULL,
    0, UPDATE_REFS_DIE_ON_ERR);
  else { /* Merge has unresolved conflicts */
- char *existing;
+ const struct worktree *wt;
  /* Update .git/NOTES_MERGE_PARTIAL with partial merge result */
  update_ref(msg.buf, "NOTES_MERGE_PARTIAL", result_sha1, NULL,
    0, UPDATE_REFS_DIE_ON_ERR);
  /* Store ref-to-be-updated into .git/NOTES_MERGE_REF */
- existing = find_shared_symref("NOTES_MERGE_REF", default_notes_ref());
- if (existing)
+ wt = find_shared_symref("NOTES_MERGE_REF", default_notes_ref());
+ if (wt)
  die(_("A notes merge into %s is already in-progress at %s"),
-    default_notes_ref(), existing);
+    default_notes_ref(), wt->path);
  if (create_symref("NOTES_MERGE_REF", default_notes_ref(), NULL))
  die("Failed to store link to current notes ref (%s)",
     default_notes_ref());
diff --git a/worktree.c b/worktree.c
index 5ae54f0..360ba41 100644
--- a/worktree.c
+++ b/worktree.c
@@ -191,14 +191,19 @@ const char *get_worktree_git_dir(const struct worktree *wt)
  return git_common_path("worktrees/%s", wt->id);
 }
 
-char *find_shared_symref(const char *symref, const char *target)
+const struct worktree *find_shared_symref(const char *symref,
+  const char *target)
 {
- char *existing = NULL;
+ const struct worktree *existing = NULL;
  struct strbuf path = STRBUF_INIT;
  struct strbuf sb = STRBUF_INIT;
- struct worktree **worktrees = get_worktrees();
+ static struct worktree **worktrees;
  int i = 0;
 
+ if (worktrees)
+ free_worktrees(worktrees);
+ worktrees = get_worktrees();
+
  for (i = 0; worktrees[i]; i++) {
  strbuf_reset(&path);
  strbuf_reset(&sb);
@@ -211,14 +216,13 @@ char *find_shared_symref(const char *symref, const char *target)
  }
 
  if (!strcmp(sb.buf, target)) {
- existing = xstrdup(worktrees[i]->path);
+ existing = worktrees[i];
  break;
  }
  }
 
  strbuf_release(&path);
  strbuf_release(&sb);
- free_worktrees(worktrees);
 
  return existing;
 }
diff --git a/worktree.h b/worktree.h
index 3198c8d..d71d7ec 100644
--- a/worktree.h
+++ b/worktree.h
@@ -36,9 +36,10 @@ extern void free_worktrees(struct worktree **);
 /*
  * Check if a per-worktree symref points to a ref in the main worktree
  * or any linked worktree, and return the path to the exising worktree
- * if it is.  Returns NULL if there is no existing ref.  The caller is
- * responsible for freeing the returned path.
+ * if it is. Returns NULL if there is no existing ref. The result
+ * may be destroyed by the next call.
  */
-extern char *find_shared_symref(const char *symref, const char *target);
+extern const struct worktree *find_shared_symref(const char *symref,
+ const char *target);
 
 #endif
--
2.8.0.rc0.210.gd302cd2

--
To unsubscribe from this list: send the line "unsubscribe git" in
the body of a message to [hidden email]
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Reply | Threaded
Open this post in threaded view
|

[PATCH v2 04/12] worktree.c: mark current worktree

Duy Nguyen
In reply to this post by Duy Nguyen
Signed-off-by: Nguyễn Thái Ngọc Duy <[hidden email]>
---
 worktree.c | 18 +++++++++++++++++-
 worktree.h |  1 +
 2 files changed, 18 insertions(+), 1 deletion(-)

diff --git a/worktree.c b/worktree.c
index 360ba41..452f64a 100644
--- a/worktree.c
+++ b/worktree.c
@@ -2,6 +2,7 @@
 #include "refs.h"
 #include "strbuf.h"
 #include "worktree.h"
+#include "dir.h"
 
 void free_worktrees(struct worktree **worktrees)
 {
@@ -94,6 +95,7 @@ static struct worktree *get_main_worktree(void)
  worktree->is_bare = is_bare;
  worktree->head_ref = NULL;
  worktree->is_detached = is_detached;
+ worktree->is_current = 0;
  add_head_info(&head_ref, worktree);
 
 done:
@@ -138,6 +140,7 @@ static struct worktree *get_linked_worktree(const char *id)
  worktree->is_bare = 0;
  worktree->head_ref = NULL;
  worktree->is_detached = is_detached;
+ worktree->is_current = 0;
  add_head_info(&head_ref, worktree);
 
 done:
@@ -150,10 +153,11 @@ done:
 struct worktree **get_worktrees(void)
 {
  struct worktree **list = NULL;
+ struct strbuf git_dir = STRBUF_INIT;
  struct strbuf path = STRBUF_INIT;
  DIR *dir;
  struct dirent *d;
- int counter = 0, alloc = 2;
+ int i, counter = 0, alloc = 2;
 
  list = xmalloc(alloc * sizeof(struct worktree *));
 
@@ -178,6 +182,18 @@ struct worktree **get_worktrees(void)
  }
  ALLOC_GROW(list, counter + 1, alloc);
  list[counter] = NULL;
+
+ strbuf_addstr(&git_dir, absolute_path(get_git_dir()));
+ for (i = 0; i < counter; i++) {
+ struct worktree *wt = list[i];
+ strbuf_addstr(&path, absolute_path(get_worktree_git_dir(wt)));
+ wt->is_current = !strcmp_icase(git_dir.buf, path.buf);
+ strbuf_reset(&path);
+ if (wt->is_current)
+ break;
+ }
+ strbuf_release(&git_dir);
+ strbuf_release(&path);
  return list;
 }
 
diff --git a/worktree.h b/worktree.h
index d71d7ec..625fb8d 100644
--- a/worktree.h
+++ b/worktree.h
@@ -8,6 +8,7 @@ struct worktree {
  unsigned char head_sha1[20];
  int is_detached;
  int is_bare;
+ int is_current;
 };
 
 /* Functions for acting on the information about worktrees. */
--
2.8.0.rc0.210.gd302cd2

--
To unsubscribe from this list: send the line "unsubscribe git" in
the body of a message to [hidden email]
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Reply | Threaded
Open this post in threaded view
|

[PATCH v2 05/12] path.c: refactor and add worktree_git_path()

Duy Nguyen
In reply to this post by Duy Nguyen
do_git_path(), which is the common code for all git_path* functions, is
modified to take a worktree struct and can produce paths for any
worktree.

worktree_git_path() is the first function that makes use of this. It can
be used to write code that can examine any worktree. For example,
wt_status_get_state() will be converted using this to take
am/rebase/... state of any worktree.

Signed-off-by: Nguyễn Thái Ngọc Duy <[hidden email]>
---
 path.c     | 34 ++++++++++++++++++++++++++++------
 worktree.h | 11 +++++++++++
 2 files changed, 39 insertions(+), 6 deletions(-)

diff --git a/path.c b/path.c
index 2ebb23d..c421d37 100644
--- a/path.c
+++ b/path.c
@@ -5,6 +5,7 @@
 #include "strbuf.h"
 #include "string-list.h"
 #include "dir.h"
+#include "worktree.h"
 
 static int get_st_mode_bits(const char *path, int *mode)
 {
@@ -383,10 +384,11 @@ static void adjust_git_path(struct strbuf *buf, int git_dir_len)
  update_common_dir(buf, git_dir_len, NULL);
 }
 
-static void do_git_path(struct strbuf *buf, const char *fmt, va_list args)
+static void do_git_path(const struct worktree *wt, struct strbuf *buf,
+ const char *fmt, va_list args)
 {
  int gitdir_len;
- strbuf_addstr(buf, get_git_dir());
+ strbuf_addstr(buf, get_worktree_git_dir(wt));
  if (buf->len && !is_dir_sep(buf->buf[buf->len - 1]))
  strbuf_addch(buf, '/');
  gitdir_len = buf->len;
@@ -400,7 +402,7 @@ char *git_path_buf(struct strbuf *buf, const char *fmt, ...)
  va_list args;
  strbuf_reset(buf);
  va_start(args, fmt);
- do_git_path(buf, fmt, args);
+ do_git_path(NULL, buf, fmt, args);
  va_end(args);
  return buf->buf;
 }
@@ -409,7 +411,7 @@ void strbuf_git_path(struct strbuf *sb, const char *fmt, ...)
 {
  va_list args;
  va_start(args, fmt);
- do_git_path(sb, fmt, args);
+ do_git_path(NULL, sb, fmt, args);
  va_end(args);
 }
 
@@ -418,7 +420,7 @@ const char *git_path(const char *fmt, ...)
  struct strbuf *pathname = get_pathname();
  va_list args;
  va_start(args, fmt);
- do_git_path(pathname, fmt, args);
+ do_git_path(NULL, pathname, fmt, args);
  va_end(args);
  return pathname->buf;
 }
@@ -428,7 +430,7 @@ char *git_pathdup(const char *fmt, ...)
  struct strbuf path = STRBUF_INIT;
  va_list args;
  va_start(args, fmt);
- do_git_path(&path, fmt, args);
+ do_git_path(NULL, &path, fmt, args);
  va_end(args);
  return strbuf_detach(&path, NULL);
 }
@@ -454,6 +456,26 @@ const char *mkpath(const char *fmt, ...)
  return cleanup_path(pathname->buf);
 }
 
+const char *worktree_git_path(const struct worktree *wt, const char *fmt, ...)
+{
+ struct strbuf *pathname = get_pathname();
+ va_list args;
+ va_start(args, fmt);
+ do_git_path(wt, pathname, fmt, args);
+ va_end(args);
+ return pathname->buf;
+}
+
+char *worktree_git_pathdup(const struct worktree *wt, const char *fmt, ...)
+{
+ struct strbuf path = STRBUF_INIT;
+ va_list args;
+ va_start(args, fmt);
+ do_git_path(wt, &path, fmt, args);
+ va_end(args);
+ return strbuf_detach(&path, NULL);
+}
+
 static void do_submodule_path(struct strbuf *buf, const char *path,
       const char *fmt, va_list args)
 {
diff --git a/worktree.h b/worktree.h
index 625fb8d..9d2463e 100644
--- a/worktree.h
+++ b/worktree.h
@@ -43,4 +43,15 @@ extern void free_worktrees(struct worktree **);
 extern const struct worktree *find_shared_symref(const char *symref,
  const char *target);
 
+/*
+ * Similar to git_path() and git_pathdup() but can produce paths for a
+ * specified worktree instead of current one
+ */
+extern const char *worktree_git_path(const struct worktree *wt,
+     const char *fmt, ...)
+ __attribute__((format (printf, 2, 3)));
+extern char *worktree_git_pathdup(const struct worktree *wt,
+  const char *fmt, ...)
+ __attribute__((format (printf, 2, 3)));
+
 #endif
--
2.8.0.rc0.210.gd302cd2

--
To unsubscribe from this list: send the line "unsubscribe git" in
the body of a message to [hidden email]
More majordomo info at  http://vger.kernel.org/majordomo-info.html
1234 ... 6