Re: [PATCHv7 4/6] worktree: have a function to check if worktrees are in use

2016-12-10 Thread Duy Nguyen
On Sat, Dec 10, 2016 at 1:49 AM, Stefan Beller  wrote:
> On Fri, Dec 9, 2016 at 4:00 AM, Duy Nguyen  wrote:
>
>> int submodule_uses_worktrees(const char *path)
>> {
>> struct strbuf path = STRBUF_INIT;
>> DIR *dir;
>> struct dirent *d;
>> int ret = 0;
>>
>> strbuf_addf(, "%s/worktrees", path);
>> dir = opendir(path.buf);
>> strbuf_release();
>>
>> if (!dir)
>> return 0;
>
> The submodule may be one of the linked worktrees, which would be
> caught if we use the code as I sent it out?

I think I simplified it too much, there should still be a
git_common_dir_noenv() to retrieve the correct common dir in the
submodule from gitdir. Then, if the repo in question has any linked
worktrees, you probably can't handle it. It does not matter if the
submodule gitdir in question is a linked or main worktree.

> If this is one of the linked worktrees, we'd rather check if a file
> "commondir" or "gitdir" exists?

Well, in theory yes. But we're apparently not ready for that. If you
check the files exist, but the files are not valid, then it's still
not considered a worktree. Which is not much different from what we do
here (if the directory exists, assuming it's a worktree). It should
catch all the valid worktrees. But yes it could give some false
positive. Since we're just using this function to stop the aborbing
git dir operation, i think this is acceptable.

(It goes even trickier, even get_worktrees() won't detect if the
linked worktree is already dead, .e.g. deleted manually, I believe.
Those have to be cleaned up by 'git worktree prune' which does even
more checks before it declare "this directory is garbage").

> I ask that because I would not know how to relocate such a linked
> worktree gitdir?



-- 
Duy


Re: [PATCHv7 4/6] worktree: have a function to check if worktrees are in use

2016-12-09 Thread Stefan Beller
On Fri, Dec 9, 2016 at 4:00 AM, Duy Nguyen  wrote:

> int submodule_uses_worktrees(const char *path)
> {
> struct strbuf path = STRBUF_INIT;
> DIR *dir;
> struct dirent *d;
> int ret = 0;
>
> strbuf_addf(, "%s/worktrees", path);
> dir = opendir(path.buf);
> strbuf_release();
>
> if (!dir)
> return 0;

The submodule may be one of the linked worktrees, which would be
caught if we use the code as I sent it out?

If this is one of the linked worktrees, we'd rather check if a file
"commondir" or "gitdir" exists?

I ask that because I would not know how to relocate such a linked
worktree gitdir?


Re: [PATCHv7 4/6] worktree: have a function to check if worktrees are in use

2016-12-09 Thread Duy Nguyen
On Thu, Dec 08, 2016 at 01:03:27PM -0800, Stefan Beller wrote:
> +/*
> + * NEEDSWORK: The values in the returned worktrees are broken, e.g.
> + * the refs or path resolution is influenced by the current repository.
> + */
> +static struct worktree **get_submodule_worktrees(const char *path, unsigned 
> flags)

I'm ok with this (at least we know the function is half-broken). But I
wonder if we could go simpler, with something like this. It's more
efficient as well. And we can replace its implementation with
get_worktrees() or something when we are able to.

As long as this function stays in worktree.c I think it's ok for it to
peek into "worktrees" directory directly. That's what all other
functions in this file do after all.

int submodule_uses_worktrees(const char *path)
{
struct strbuf path = STRBUF_INIT;
DIR *dir;
struct dirent *d;
int ret = 0;

strbuf_addf(, "%s/worktrees", path);
dir = opendir(path.buf);
strbuf_release();

if (!dir)
return 0;

while ((d = readdir(dir)) != NULL) {
if (is_dot_or_dotdot(d->d_name))
continue;

ret = 1;
break;
}
closedir(dir);
return ret;
}
--
Duy


[PATCHv7 4/6] worktree: have a function to check if worktrees are in use

2016-12-08 Thread Stefan Beller
In a later patch we want to move around the the git directory of
a submodule. Both submodules as well as worktrees are involved in
placing git directories at unusual places, so their functionality
may collide. To react appropriately to situations where worktrees
in submodules are in use, offer a new function to query the
a submodule if it uses the worktree feature.

This can be done cheaply (both in new code to write as well as run time)
by obtaining the list of worktrees based off that submodules git
directory. However as we have loaded the variables for the current
repository, the values in the submodule worktree
can be wrong, e.g.
* core.ignorecase may differ between these two repositories
* the ref resolution is broken (refs/heads/branch in the submodule
  resolves to the sha1 value of the `branch` in the current repository
  that may not exist or have another sha1)

Signed-off-by: Stefan Beller 
---
 worktree.c | 68 +-
 worktree.h |  7 +++
 2 files changed, 65 insertions(+), 10 deletions(-)

diff --git a/worktree.c b/worktree.c
index eb6121263b..1c46fcf25f 100644
--- a/worktree.c
+++ b/worktree.c
@@ -72,7 +72,7 @@ static void add_head_info(struct strbuf *head_ref, struct 
worktree *worktree)
 /**
  * get the main worktree
  */
-static struct worktree *get_main_worktree(void)
+static struct worktree *get_main_worktree(const char *git_common_dir)
 {
struct worktree *worktree = NULL;
struct strbuf path = STRBUF_INIT;
@@ -81,12 +81,12 @@ static struct worktree *get_main_worktree(void)
int is_bare = 0;
int is_detached = 0;
 
-   strbuf_add_absolute_path(_path, get_git_common_dir());
+   strbuf_add_absolute_path(_path, git_common_dir);
is_bare = !strbuf_strip_suffix(_path, "/.git");
if (is_bare)
strbuf_strip_suffix(_path, "/.");
 
-   strbuf_addf(, "%s/HEAD", get_git_common_dir());
+   strbuf_addf(, "%s/HEAD", git_common_dir);
 
worktree = xcalloc(1, sizeof(*worktree));
worktree->path = strbuf_detach(_path, NULL);
@@ -101,7 +101,8 @@ static struct worktree *get_main_worktree(void)
return worktree;
 }
 
-static struct worktree *get_linked_worktree(const char *id)
+static struct worktree *get_linked_worktree(const char *git_common_dir,
+   const char *id)
 {
struct worktree *worktree = NULL;
struct strbuf path = STRBUF_INIT;
@@ -112,7 +113,7 @@ static struct worktree *get_linked_worktree(const char *id)
if (!id)
die("Missing linked worktree name");
 
-   strbuf_git_common_path(, "worktrees/%s/gitdir", id);
+   strbuf_addf(, "%s/worktrees/%s/gitdir", git_common_dir, id);
if (strbuf_read_file(_path, path.buf, 0) <= 0)
/* invalid gitdir file */
goto done;
@@ -125,7 +126,7 @@ static struct worktree *get_linked_worktree(const char *id)
}
 
strbuf_reset();
-   strbuf_addf(, "%s/worktrees/%s/HEAD", get_git_common_dir(), id);
+   strbuf_addf(, "%s/worktrees/%s/HEAD", git_common_dir, id);
 
if (parse_ref(path.buf, _ref, _detached) < 0)
goto done;
@@ -167,7 +168,8 @@ static int compare_worktree(const void *a_, const void *b_)
return fspathcmp((*a)->path, (*b)->path);
 }
 
-struct worktree **get_worktrees(unsigned flags)
+static struct worktree **get_worktrees_internal(const char *git_common_dir,
+   unsigned flags)
 {
struct worktree **list = NULL;
struct strbuf path = STRBUF_INIT;
@@ -177,9 +179,10 @@ struct worktree **get_worktrees(unsigned flags)
 
list = xmalloc(alloc * sizeof(struct worktree *));
 
-   list[counter++] = get_main_worktree();
+   if (!(flags & GWT_LINKED_ONLY))
+   list[counter++] = get_main_worktree(git_common_dir);
 
-   strbuf_addf(, "%s/worktrees", get_git_common_dir());
+   strbuf_addf(, "%s/worktrees", git_common_dir);
dir = opendir(path.buf);
strbuf_release();
if (dir) {
@@ -188,7 +191,7 @@ struct worktree **get_worktrees(unsigned flags)
if (is_dot_or_dotdot(d->d_name))
continue;
 
-   if ((linked = get_linked_worktree(d->d_name))) {
+   if ((linked = get_linked_worktree(git_common_dir, 
d->d_name))) {
ALLOC_GROW(list, counter + 1, alloc);
list[counter++] = linked;
}
@@ -209,6 +212,34 @@ struct worktree **get_worktrees(unsigned flags)
return list;
 }
 
+struct worktree **get_worktrees(unsigned flags)
+{
+   return get_worktrees_internal(get_git_common_dir(), flags);
+}
+
+/*
+ * NEEDSWORK: The values in the returned worktrees are broken, e.g.
+ * the refs or path resolution is influenced by the current repository.
+