struct worktree *find_worktree(struct worktree **list, const char *prefix, const char *arg) { struct worktree *wt; char *path; char *to_free = NULL; if ((wt = find_worktree_by_suffix(list, arg))) return wt; if (prefix) arg = to_free = prefix_filename(prefix, arg); path = real_pathdup(arg, 0); if (!path) { free(to_free); return NULL; } for (; *list; list++) if (!fspathcmp(path, real_path((*list)->path))) break; free(path); free(to_free); return *list; }
void update_worktree_location(struct worktree *wt, const char *path_) { struct strbuf path = STRBUF_INIT; if (is_main_worktree(wt)) BUG("can't relocate main worktree"); strbuf_realpath(&path, path_, 1); if (fspathcmp(wt->path, path.buf)) { write_file(git_common_path("worktrees/%s/gitdir", wt->id), "%s/.git", path.buf); free(wt->path); wt->path = strbuf_detach(&path, NULL); } strbuf_release(&path); }
static void mark_current_worktree(struct worktree **worktrees) { char *git_dir = absolute_pathdup(get_git_dir()); int i; for (i = 0; worktrees[i]; i++) { struct worktree *wt = worktrees[i]; const char *wt_git_dir = get_worktree_git_dir(wt); if (!fspathcmp(git_dir, absolute_path(wt_git_dir))) { wt->is_current = 1; break; } } free(git_dir); }
struct worktree *find_worktree(struct worktree **list, const char *prefix, const char *arg) { struct worktree *wt; char *path; if ((wt = find_worktree_by_suffix(list, arg))) return wt; arg = prefix_filename(prefix, strlen(prefix), arg); path = xstrdup(real_path(arg)); for (; *list; list++) if (!fspathcmp(path, real_path((*list)->path))) break; free(path); return *list; }
static struct worktree *find_worktree_by_suffix(struct worktree **list, const char *suffix) { struct worktree *found = NULL; int nr_found = 0, suffixlen; suffixlen = strlen(suffix); if (!suffixlen) return NULL; for (; *list && nr_found < 2; list++) { const char *path = (*list)->path; int pathlen = strlen(path); int start = pathlen - suffixlen; /* suffix must start at directory boundary */ if ((!start || (start > 0 && is_dir_sep(path[start - 1]))) && !fspathcmp(suffix, path + start)) { found = *list; nr_found++; } } return nr_found == 1 ? found : NULL; }
int validate_worktree(const struct worktree *wt, struct strbuf *errmsg, unsigned flags) { struct strbuf wt_path = STRBUF_INIT; char *path = NULL; int err, ret = -1; strbuf_addf(&wt_path, "%s/.git", wt->path); if (is_main_worktree(wt)) { if (is_directory(wt_path.buf)) { ret = 0; goto done; } /* * Main worktree using .git file to point to the * repository would make it impossible to know where * the actual worktree is if this function is executed * from another worktree. No .git file support for now. */ strbuf_addf_gently(errmsg, _("'%s' at main working tree is not the repository directory"), wt_path.buf); goto done; } /* * Make sure "gitdir" file points to a real .git file and that * file points back here. */ if (!is_absolute_path(wt->path)) { strbuf_addf_gently(errmsg, _("'%s' file does not contain absolute path to the working tree location"), git_common_path("worktrees/%s/gitdir", wt->id)); goto done; } if (flags & WT_VALIDATE_WORKTREE_MISSING_OK && !file_exists(wt->path)) { ret = 0; goto done; } if (!file_exists(wt_path.buf)) { strbuf_addf_gently(errmsg, _("'%s' does not exist"), wt_path.buf); goto done; } path = xstrdup_or_null(read_gitfile_gently(wt_path.buf, &err)); if (!path) { strbuf_addf_gently(errmsg, _("'%s' is not a .git file, error code %d"), wt_path.buf, err); goto done; } ret = fspathcmp(path, real_path(git_common_path("worktrees/%s", wt->id))); if (ret) strbuf_addf_gently(errmsg, _("'%s' does not point back to '%s'"), wt->path, git_common_path("worktrees/%s", wt->id)); done: free(path); strbuf_release(&wt_path); return ret; }
static int compare_worktree(const void *a_, const void *b_) { const struct worktree *const *a = a_; const struct worktree *const *b = b_; return fspathcmp((*a)->path, (*b)->path); }