worktree: add a function to get worktree details
The worktree structure provided for an individual worktree includes the absolute path of the worktree. The fuction to get the worktree details is a refactor of the find main/linked symref functions. Signed-off-by: Michael Rappazzo <rappazzo@gmail.com> Signed-off-by: Junio C Hamano <gitster@pobox.com>
This commit is contained in:
parent
1ceb7f9067
commit
5193490442
156
worktree.c
156
worktree.c
@ -3,6 +3,17 @@
|
|||||||
#include "strbuf.h"
|
#include "strbuf.h"
|
||||||
#include "worktree.h"
|
#include "worktree.h"
|
||||||
|
|
||||||
|
void free_worktrees(struct worktree **worktrees)
|
||||||
|
{
|
||||||
|
int i = 0;
|
||||||
|
|
||||||
|
for (i = 0; worktrees[i]; i++) {
|
||||||
|
free(worktrees[i]->path);
|
||||||
|
free(worktrees[i]);
|
||||||
|
}
|
||||||
|
free (worktrees);
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* read 'path_to_ref' into 'ref'. Also if is_detached is not NULL,
|
* read 'path_to_ref' into 'ref'. Also if is_detached is not NULL,
|
||||||
* set is_detached to 1 (0) if the ref is detatched (is not detached).
|
* set is_detached to 1 (0) if the ref is detatched (is not detached).
|
||||||
@ -38,87 +49,138 @@ static int parse_ref(char *path_to_ref, struct strbuf *ref, int *is_detached)
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static char *find_main_symref(const char *symref, const char *branch)
|
/**
|
||||||
|
* get the main worktree
|
||||||
|
*/
|
||||||
|
static struct worktree *get_main_worktree(void)
|
||||||
{
|
{
|
||||||
struct strbuf sb = STRBUF_INIT;
|
struct worktree *worktree = NULL;
|
||||||
struct strbuf path = STRBUF_INIT;
|
struct strbuf path = STRBUF_INIT;
|
||||||
|
struct strbuf worktree_path = STRBUF_INIT;
|
||||||
struct strbuf gitdir = STRBUF_INIT;
|
struct strbuf gitdir = STRBUF_INIT;
|
||||||
char *existing = NULL;
|
struct strbuf head_ref = STRBUF_INIT;
|
||||||
|
|
||||||
strbuf_addf(&path, "%s/%s", get_git_common_dir(), symref);
|
strbuf_addf(&gitdir, "%s", absolute_path(get_git_common_dir()));
|
||||||
if (parse_ref(path.buf, &sb, NULL) < 0)
|
strbuf_addbuf(&worktree_path, &gitdir);
|
||||||
goto done;
|
if (!strbuf_strip_suffix(&worktree_path, "/.git"))
|
||||||
if (strcmp(sb.buf, branch))
|
strbuf_strip_suffix(&worktree_path, "/.");
|
||||||
goto done;
|
|
||||||
strbuf_addstr(&gitdir, get_git_common_dir());
|
strbuf_addf(&path, "%s/HEAD", get_git_common_dir());
|
||||||
strbuf_strip_suffix(&gitdir, ".git");
|
|
||||||
existing = strbuf_detach(&gitdir, NULL);
|
if (parse_ref(path.buf, &head_ref, NULL) >= 0) {
|
||||||
done:
|
worktree = xmalloc(sizeof(struct worktree));
|
||||||
|
worktree->path = strbuf_detach(&worktree_path, NULL);
|
||||||
|
worktree->git_dir = strbuf_detach(&gitdir, NULL);
|
||||||
|
}
|
||||||
strbuf_release(&path);
|
strbuf_release(&path);
|
||||||
strbuf_release(&sb);
|
|
||||||
strbuf_release(&gitdir);
|
strbuf_release(&gitdir);
|
||||||
|
strbuf_release(&worktree_path);
|
||||||
return existing;
|
strbuf_release(&head_ref);
|
||||||
|
return worktree;
|
||||||
}
|
}
|
||||||
|
|
||||||
static char *find_linked_symref(const char *symref, const char *branch,
|
static struct worktree *get_linked_worktree(const char *id)
|
||||||
const char *id)
|
|
||||||
{
|
{
|
||||||
struct strbuf sb = STRBUF_INIT;
|
struct worktree *worktree = NULL;
|
||||||
struct strbuf path = STRBUF_INIT;
|
struct strbuf path = STRBUF_INIT;
|
||||||
|
struct strbuf worktree_path = STRBUF_INIT;
|
||||||
struct strbuf gitdir = STRBUF_INIT;
|
struct strbuf gitdir = STRBUF_INIT;
|
||||||
char *existing = NULL;
|
struct strbuf head_ref = STRBUF_INIT;
|
||||||
|
|
||||||
if (!id)
|
if (!id)
|
||||||
die("Missing linked worktree name");
|
die("Missing linked worktree name");
|
||||||
|
|
||||||
strbuf_addf(&path, "%s/worktrees/%s/%s", get_git_common_dir(), id, symref);
|
strbuf_addf(&gitdir, "%s/worktrees/%s",
|
||||||
|
absolute_path(get_git_common_dir()), id);
|
||||||
|
strbuf_addf(&path, "%s/gitdir", gitdir.buf);
|
||||||
|
if (strbuf_read_file(&worktree_path, path.buf, 0) <= 0)
|
||||||
|
/* invalid gitdir file */
|
||||||
|
goto done;
|
||||||
|
|
||||||
|
strbuf_rtrim(&worktree_path);
|
||||||
|
if (!strbuf_strip_suffix(&worktree_path, "/.git")) {
|
||||||
|
strbuf_reset(&worktree_path);
|
||||||
|
strbuf_addstr(&worktree_path, absolute_path("."));
|
||||||
|
strbuf_strip_suffix(&worktree_path, "/.");
|
||||||
|
}
|
||||||
|
|
||||||
if (parse_ref(path.buf, &sb, NULL) < 0)
|
|
||||||
goto done;
|
|
||||||
if (strcmp(sb.buf, branch))
|
|
||||||
goto done;
|
|
||||||
strbuf_reset(&path);
|
strbuf_reset(&path);
|
||||||
strbuf_addf(&path, "%s/worktrees/%s/gitdir", get_git_common_dir(), id);
|
strbuf_addf(&path, "%s/worktrees/%s/HEAD", get_git_common_dir(), id);
|
||||||
if (strbuf_read_file(&gitdir, path.buf, 0) <= 0)
|
|
||||||
goto done;
|
if (parse_ref(path.buf, &head_ref, NULL) >= 0) {
|
||||||
strbuf_rtrim(&gitdir);
|
worktree = xmalloc(sizeof(struct worktree));
|
||||||
strbuf_strip_suffix(&gitdir, ".git");
|
worktree->path = strbuf_detach(&worktree_path, NULL);
|
||||||
|
worktree->git_dir = strbuf_detach(&gitdir, NULL);
|
||||||
|
}
|
||||||
|
|
||||||
existing = strbuf_detach(&gitdir, NULL);
|
|
||||||
done:
|
done:
|
||||||
strbuf_release(&path);
|
strbuf_release(&path);
|
||||||
strbuf_release(&sb);
|
|
||||||
strbuf_release(&gitdir);
|
strbuf_release(&gitdir);
|
||||||
|
strbuf_release(&worktree_path);
|
||||||
return existing;
|
strbuf_release(&head_ref);
|
||||||
|
return worktree;
|
||||||
}
|
}
|
||||||
|
|
||||||
char *find_shared_symref(const char *symref, const char *target)
|
struct worktree **get_worktrees(void)
|
||||||
{
|
{
|
||||||
|
struct worktree **list = NULL;
|
||||||
struct strbuf path = STRBUF_INIT;
|
struct strbuf path = STRBUF_INIT;
|
||||||
DIR *dir;
|
DIR *dir;
|
||||||
struct dirent *d;
|
struct dirent *d;
|
||||||
char *existing;
|
int counter = 0, alloc = 2;
|
||||||
|
|
||||||
if ((existing = find_main_symref(symref, target)))
|
list = xmalloc(alloc * sizeof(struct worktree *));
|
||||||
return existing;
|
|
||||||
|
if ((list[counter] = get_main_worktree()))
|
||||||
|
counter++;
|
||||||
|
|
||||||
strbuf_addf(&path, "%s/worktrees", get_git_common_dir());
|
strbuf_addf(&path, "%s/worktrees", get_git_common_dir());
|
||||||
dir = opendir(path.buf);
|
dir = opendir(path.buf);
|
||||||
strbuf_release(&path);
|
strbuf_release(&path);
|
||||||
if (!dir)
|
if (dir) {
|
||||||
return NULL;
|
while ((d = readdir(dir)) != NULL) {
|
||||||
|
struct worktree *linked = NULL;
|
||||||
|
if (!strcmp(d->d_name, ".") || !strcmp(d->d_name, ".."))
|
||||||
|
continue;
|
||||||
|
|
||||||
while ((d = readdir(dir)) != NULL) {
|
if ((linked = get_linked_worktree(d->d_name))) {
|
||||||
if (!strcmp(d->d_name, ".") || !strcmp(d->d_name, ".."))
|
ALLOC_GROW(list, counter + 1, alloc);
|
||||||
continue;
|
list[counter++] = linked;
|
||||||
existing = find_linked_symref(symref, target, d->d_name);
|
}
|
||||||
if (existing)
|
}
|
||||||
goto done;
|
closedir(dir);
|
||||||
}
|
}
|
||||||
done:
|
ALLOC_GROW(list, counter + 1, alloc);
|
||||||
closedir(dir);
|
list[counter] = NULL;
|
||||||
|
return list;
|
||||||
|
}
|
||||||
|
|
||||||
|
char *find_shared_symref(const char *symref, const char *target)
|
||||||
|
{
|
||||||
|
char *existing = NULL;
|
||||||
|
struct strbuf path = STRBUF_INIT;
|
||||||
|
struct strbuf sb = STRBUF_INIT;
|
||||||
|
struct worktree **worktrees = get_worktrees();
|
||||||
|
int i = 0;
|
||||||
|
|
||||||
|
for (i = 0; worktrees[i]; i++) {
|
||||||
|
strbuf_reset(&path);
|
||||||
|
strbuf_reset(&sb);
|
||||||
|
strbuf_addf(&path, "%s/%s", worktrees[i]->git_dir, symref);
|
||||||
|
|
||||||
|
if (parse_ref(path.buf, &sb, NULL)) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!strcmp(sb.buf, target)) {
|
||||||
|
existing = xstrdup(worktrees[i]->path);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
strbuf_release(&path);
|
||||||
|
strbuf_release(&sb);
|
||||||
|
free_worktrees(worktrees);
|
||||||
|
|
||||||
return existing;
|
return existing;
|
||||||
}
|
}
|
||||||
|
22
worktree.h
22
worktree.h
@ -1,6 +1,28 @@
|
|||||||
#ifndef WORKTREE_H
|
#ifndef WORKTREE_H
|
||||||
#define WORKTREE_H
|
#define WORKTREE_H
|
||||||
|
|
||||||
|
struct worktree {
|
||||||
|
char *path;
|
||||||
|
char *git_dir;
|
||||||
|
};
|
||||||
|
|
||||||
|
/* Functions for acting on the information about worktrees. */
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Get the worktrees. The primary worktree will always be the first returned,
|
||||||
|
* and linked worktrees will be pointed to by 'next' in each subsequent
|
||||||
|
* worktree. No specific ordering is done on the linked worktrees.
|
||||||
|
*
|
||||||
|
* The caller is responsible for freeing the memory from the returned
|
||||||
|
* worktree(s).
|
||||||
|
*/
|
||||||
|
extern struct worktree **get_worktrees(void);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Free up the memory for worktree(s)
|
||||||
|
*/
|
||||||
|
extern void free_worktrees(struct worktree **);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Check if a per-worktree symref points to a ref in the main 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
|
* or any linked worktree, and return the path to the exising worktree
|
||||||
|
Loading…
Reference in New Issue
Block a user