Skip to content

Commit

Permalink
worktree: add top-level worktree.c
Browse files Browse the repository at this point in the history
worktree.c contains functions to work with and get information from
worktrees.  This introduction moves functions related to worktrees
from branch.c into worktree.c

Signed-off-by: Michael Rappazzo <[email protected]>
Signed-off-by: Junio C Hamano <[email protected]>
  • Loading branch information
rappazzo authored and gitster committed Oct 2, 2015
1 parent 8d530c4 commit ac6c561
Show file tree
Hide file tree
Showing 6 changed files with 97 additions and 87 deletions.
1 change: 1 addition & 0 deletions Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -807,6 +807,7 @@ LIB_OBJS += version.o
LIB_OBJS += versioncmp.o
LIB_OBJS += walker.o
LIB_OBJS += wildmatch.o
LIB_OBJS += worktree.o
LIB_OBJS += wrapper.o
LIB_OBJS += write_or_die.o
LIB_OBJS += ws.o
Expand Down
79 changes: 1 addition & 78 deletions branch.c
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
#include "refs.h"
#include "remote.h"
#include "commit.h"
#include "worktree.h"

struct tracking {
struct refspec spec;
Expand Down Expand Up @@ -311,84 +312,6 @@ void remove_branch_state(void)
unlink(git_path_squash_msg());
}

static char *find_linked_symref(const char *symref, const char *branch,
const char *id)
{
struct strbuf sb = STRBUF_INIT;
struct strbuf path = STRBUF_INIT;
struct strbuf gitdir = STRBUF_INIT;
char *existing = NULL;

/*
* $GIT_COMMON_DIR/$symref (e.g. HEAD) is practically outside
* $GIT_DIR so resolve_ref_unsafe() won't work (it uses
* git_path). Parse the ref ourselves.
*/
if (id)
strbuf_addf(&path, "%s/worktrees/%s/%s", get_git_common_dir(), id, symref);
else
strbuf_addf(&path, "%s/%s", get_git_common_dir(), symref);

if (!strbuf_readlink(&sb, path.buf, 0)) {
if (!starts_with(sb.buf, "refs/") ||
check_refname_format(sb.buf, 0))
goto done;
} else if (strbuf_read_file(&sb, path.buf, 0) >= 0 &&
starts_with(sb.buf, "ref:")) {
strbuf_remove(&sb, 0, strlen("ref:"));
strbuf_trim(&sb);
} else
goto done;
if (strcmp(sb.buf, branch))
goto done;
if (id) {
strbuf_reset(&path);
strbuf_addf(&path, "%s/worktrees/%s/gitdir", get_git_common_dir(), id);
if (strbuf_read_file(&gitdir, path.buf, 0) <= 0)
goto done;
strbuf_rtrim(&gitdir);
} else
strbuf_addstr(&gitdir, get_git_common_dir());
strbuf_strip_suffix(&gitdir, ".git");

existing = strbuf_detach(&gitdir, NULL);
done:
strbuf_release(&path);
strbuf_release(&sb);
strbuf_release(&gitdir);

return existing;
}

char *find_shared_symref(const char *symref, const char *target)
{
struct strbuf path = STRBUF_INIT;
DIR *dir;
struct dirent *d;
char *existing;

if ((existing = find_linked_symref(symref, target, NULL)))
return existing;

strbuf_addf(&path, "%s/worktrees", get_git_common_dir());
dir = opendir(path.buf);
strbuf_release(&path);
if (!dir)
return NULL;

while ((d = readdir(dir)) != NULL) {
if (!strcmp(d->d_name, ".") || !strcmp(d->d_name, ".."))
continue;
existing = find_linked_symref(symref, target, d->d_name);
if (existing)
goto done;
}
done:
closedir(dir);

return existing;
}

void die_if_checked_out(const char *branch)
{
char *existing;
Expand Down
8 changes: 0 additions & 8 deletions branch.h
Original file line number Diff line number Diff line change
Expand Up @@ -59,12 +59,4 @@ extern int read_branch_desc(struct strbuf *, const char *branch_name);
*/
extern void die_if_checked_out(const char *branch);

/*
* 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.
*/
extern char *find_shared_symref(const char *symref, const char *target);

#endif
2 changes: 1 addition & 1 deletion builtin/notes.c
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@
#include "string-list.h"
#include "notes-merge.h"
#include "notes-utils.h"
#include "branch.h"
#include "worktree.h"

static const char * const git_notes_usage[] = {
N_("git notes [--ref <notes-ref>] [list [<object>]]"),
Expand Down
82 changes: 82 additions & 0 deletions worktree.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,82 @@
#include "cache.h"
#include "refs.h"
#include "strbuf.h"
#include "worktree.h"

static char *find_linked_symref(const char *symref, const char *branch,
const char *id)
{
struct strbuf sb = STRBUF_INIT;
struct strbuf path = STRBUF_INIT;
struct strbuf gitdir = STRBUF_INIT;
char *existing = NULL;

/*
* $GIT_COMMON_DIR/$symref (e.g. HEAD) is practically outside
* $GIT_DIR so resolve_ref_unsafe() won't work (it uses
* git_path). Parse the ref ourselves.
*/
if (id)
strbuf_addf(&path, "%s/worktrees/%s/%s", get_git_common_dir(), id, symref);
else
strbuf_addf(&path, "%s/%s", get_git_common_dir(), symref);

if (!strbuf_readlink(&sb, path.buf, 0)) {
if (!starts_with(sb.buf, "refs/") ||
check_refname_format(sb.buf, 0))
goto done;
} else if (strbuf_read_file(&sb, path.buf, 0) >= 0 &&
starts_with(sb.buf, "ref:")) {
strbuf_remove(&sb, 0, strlen("ref:"));
strbuf_trim(&sb);
} else
goto done;
if (strcmp(sb.buf, branch))
goto done;
if (id) {
strbuf_reset(&path);
strbuf_addf(&path, "%s/worktrees/%s/gitdir", get_git_common_dir(), id);
if (strbuf_read_file(&gitdir, path.buf, 0) <= 0)
goto done;
strbuf_rtrim(&gitdir);
} else
strbuf_addstr(&gitdir, get_git_common_dir());
strbuf_strip_suffix(&gitdir, ".git");

existing = strbuf_detach(&gitdir, NULL);
done:
strbuf_release(&path);
strbuf_release(&sb);
strbuf_release(&gitdir);

return existing;
}

char *find_shared_symref(const char *symref, const char *target)
{
struct strbuf path = STRBUF_INIT;
DIR *dir;
struct dirent *d;
char *existing;

if ((existing = find_linked_symref(symref, target, NULL)))
return existing;

strbuf_addf(&path, "%s/worktrees", get_git_common_dir());
dir = opendir(path.buf);
strbuf_release(&path);
if (!dir)
return NULL;

while ((d = readdir(dir)) != NULL) {
if (!strcmp(d->d_name, ".") || !strcmp(d->d_name, ".."))
continue;
existing = find_linked_symref(symref, target, d->d_name);
if (existing)
goto done;
}
done:
closedir(dir);

return existing;
}
12 changes: 12 additions & 0 deletions worktree.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
#ifndef WORKTREE_H
#define WORKTREE_H

/*
* 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.
*/
extern char *find_shared_symref(const char *symref, const char *target);

#endif

0 comments on commit ac6c561

Please sign in to comment.