2 #include "repository.h"
 
   9 void free_worktrees(struct worktree **worktrees)
 
  13         for (i = 0; worktrees[i]; i++) {
 
  14                 free(worktrees[i]->path);
 
  15                 free(worktrees[i]->id);
 
  16                 free(worktrees[i]->head_ref);
 
  17                 free(worktrees[i]->lock_reason);
 
  24  * Update head_sha1, head_ref and is_detached of the given worktree
 
  26 static void add_head_info(struct worktree *wt)
 
  31         target = refs_resolve_ref_unsafe(get_worktree_ref_store(wt),
 
  34                                          &wt->head_oid, &flags);
 
  38         if (flags & REF_ISSYMREF)
 
  39                 wt->head_ref = xstrdup(target);
 
  45  * get the main worktree
 
  47 static struct worktree *get_main_worktree(void)
 
  49         struct worktree *worktree = NULL;
 
  50         struct strbuf path = STRBUF_INIT;
 
  51         struct strbuf worktree_path = STRBUF_INIT;
 
  53         strbuf_add_absolute_path(&worktree_path, get_git_common_dir());
 
  54         if (!strbuf_strip_suffix(&worktree_path, "/.git"))
 
  55                 strbuf_strip_suffix(&worktree_path, "/.");
 
  57         strbuf_addf(&path, "%s/HEAD", get_git_common_dir());
 
  59         worktree = xcalloc(1, sizeof(*worktree));
 
  60         worktree->path = strbuf_detach(&worktree_path, NULL);
 
  62          * NEEDSWORK: If this function is called from a secondary worktree and
 
  63          * config.worktree is present, is_bare_repository_cfg will reflect the
 
  64          * contents of config.worktree, not the contents of the main worktree.
 
  65          * This means that worktree->is_bare may be set to 0 even if the main
 
  66          * worktree is configured to be bare.
 
  68         worktree->is_bare = (is_bare_repository_cfg == 1) ||
 
  70         add_head_info(worktree);
 
  72         strbuf_release(&path);
 
  73         strbuf_release(&worktree_path);
 
  77 static struct worktree *get_linked_worktree(const char *id)
 
  79         struct worktree *worktree = NULL;
 
  80         struct strbuf path = STRBUF_INIT;
 
  81         struct strbuf worktree_path = STRBUF_INIT;
 
  84                 die("Missing linked worktree name");
 
  86         strbuf_git_common_path(&path, the_repository, "worktrees/%s/gitdir", id);
 
  87         if (strbuf_read_file(&worktree_path, path.buf, 0) <= 0)
 
  88                 /* invalid gitdir file */
 
  91         strbuf_rtrim(&worktree_path);
 
  92         if (!strbuf_strip_suffix(&worktree_path, "/.git")) {
 
  93                 strbuf_reset(&worktree_path);
 
  94                 strbuf_add_absolute_path(&worktree_path, ".");
 
  95                 strbuf_strip_suffix(&worktree_path, "/.");
 
  99         strbuf_addf(&path, "%s/worktrees/%s/HEAD", get_git_common_dir(), id);
 
 101         worktree = xcalloc(1, sizeof(*worktree));
 
 102         worktree->path = strbuf_detach(&worktree_path, NULL);
 
 103         worktree->id = xstrdup(id);
 
 104         add_head_info(worktree);
 
 107         strbuf_release(&path);
 
 108         strbuf_release(&worktree_path);
 
 112 static void mark_current_worktree(struct worktree **worktrees)
 
 114         char *git_dir = absolute_pathdup(get_git_dir());
 
 117         for (i = 0; worktrees[i]; i++) {
 
 118                 struct worktree *wt = worktrees[i];
 
 119                 const char *wt_git_dir = get_worktree_git_dir(wt);
 
 121                 if (!fspathcmp(git_dir, absolute_path(wt_git_dir))) {
 
 129 static int compare_worktree(const void *a_, const void *b_)
 
 131         const struct worktree *const *a = a_;
 
 132         const struct worktree *const *b = b_;
 
 133         return fspathcmp((*a)->path, (*b)->path);
 
 136 struct worktree **get_worktrees(unsigned flags)
 
 138         struct worktree **list = NULL;
 
 139         struct strbuf path = STRBUF_INIT;
 
 142         int counter = 0, alloc = 2;
 
 144         ALLOC_ARRAY(list, alloc);
 
 146         list[counter++] = get_main_worktree();
 
 148         strbuf_addf(&path, "%s/worktrees", get_git_common_dir());
 
 149         dir = opendir(path.buf);
 
 150         strbuf_release(&path);
 
 152                 while ((d = readdir(dir)) != NULL) {
 
 153                         struct worktree *linked = NULL;
 
 154                         if (is_dot_or_dotdot(d->d_name))
 
 157                         if ((linked = get_linked_worktree(d->d_name))) {
 
 158                                 ALLOC_GROW(list, counter + 1, alloc);
 
 159                                 list[counter++] = linked;
 
 164         ALLOC_GROW(list, counter + 1, alloc);
 
 165         list[counter] = NULL;
 
 167         if (flags & GWT_SORT_LINKED)
 
 169                  * don't sort the first item (main worktree), which will
 
 170                  * always be the first
 
 172                 QSORT(list + 1, counter - 1, compare_worktree);
 
 174         mark_current_worktree(list);
 
 178 const char *get_worktree_git_dir(const struct worktree *wt)
 
 181                 return get_git_dir();
 
 183                 return get_git_common_dir();
 
 185                 return git_common_path("worktrees/%s", wt->id);
 
 188 static struct worktree *find_worktree_by_suffix(struct worktree **list,
 
 191         struct worktree *found = NULL;
 
 192         int nr_found = 0, suffixlen;
 
 194         suffixlen = strlen(suffix);
 
 198         for (; *list && nr_found < 2; list++) {
 
 199                 const char      *path    = (*list)->path;
 
 200                 int              pathlen = strlen(path);
 
 201                 int              start   = pathlen - suffixlen;
 
 203                 /* suffix must start at directory boundary */
 
 204                 if ((!start || (start > 0 && is_dir_sep(path[start - 1]))) &&
 
 205                     !fspathcmp(suffix, path + start)) {
 
 210         return nr_found == 1 ? found : NULL;
 
 213 struct worktree *find_worktree(struct worktree **list,
 
 219         char *to_free = NULL;
 
 221         if ((wt = find_worktree_by_suffix(list, arg)))
 
 225                 arg = to_free = prefix_filename(prefix, arg);
 
 226         path = real_pathdup(arg, 0);
 
 231         for (; *list; list++) {
 
 232                 const char *wt_path = real_path_if_valid((*list)->path);
 
 234                 if (wt_path && !fspathcmp(path, wt_path))
 
 242 int is_main_worktree(const struct worktree *wt)
 
 247 const char *worktree_lock_reason(struct worktree *wt)
 
 249         assert(!is_main_worktree(wt));
 
 251         if (!wt->lock_reason_valid) {
 
 252                 struct strbuf path = STRBUF_INIT;
 
 254                 strbuf_addstr(&path, worktree_git_path(wt, "locked"));
 
 255                 if (file_exists(path.buf)) {
 
 256                         struct strbuf lock_reason = STRBUF_INIT;
 
 257                         if (strbuf_read_file(&lock_reason, path.buf, 0) < 0)
 
 258                                 die_errno(_("failed to read '%s'"), path.buf);
 
 259                         strbuf_trim(&lock_reason);
 
 260                         wt->lock_reason = strbuf_detach(&lock_reason, NULL);
 
 262                         wt->lock_reason = NULL;
 
 263                 wt->lock_reason_valid = 1;
 
 264                 strbuf_release(&path);
 
 267         return wt->lock_reason;
 
 270 /* convenient wrapper to deal with NULL strbuf */
 
 271 static void strbuf_addf_gently(struct strbuf *buf, const char *fmt, ...)
 
 278         va_start(params, fmt);
 
 279         strbuf_vaddf(buf, fmt, params);
 
 283 int validate_worktree(const struct worktree *wt, struct strbuf *errmsg,
 
 286         struct strbuf wt_path = STRBUF_INIT;
 
 290         strbuf_addf(&wt_path, "%s/.git", wt->path);
 
 292         if (is_main_worktree(wt)) {
 
 293                 if (is_directory(wt_path.buf)) {
 
 298                  * Main worktree using .git file to point to the
 
 299                  * repository would make it impossible to know where
 
 300                  * the actual worktree is if this function is executed
 
 301                  * from another worktree. No .git file support for now.
 
 303                 strbuf_addf_gently(errmsg,
 
 304                                    _("'%s' at main working tree is not the repository directory"),
 
 310          * Make sure "gitdir" file points to a real .git file and that
 
 311          * file points back here.
 
 313         if (!is_absolute_path(wt->path)) {
 
 314                 strbuf_addf_gently(errmsg,
 
 315                                    _("'%s' file does not contain absolute path to the working tree location"),
 
 316                                    git_common_path("worktrees/%s/gitdir", wt->id));
 
 320         if (flags & WT_VALIDATE_WORKTREE_MISSING_OK &&
 
 321             !file_exists(wt->path)) {
 
 326         if (!file_exists(wt_path.buf)) {
 
 327                 strbuf_addf_gently(errmsg, _("'%s' does not exist"), wt_path.buf);
 
 331         path = xstrdup_or_null(read_gitfile_gently(wt_path.buf, &err));
 
 333                 strbuf_addf_gently(errmsg, _("'%s' is not a .git file, error code %d"),
 
 338         ret = fspathcmp(path, real_path(git_common_path("worktrees/%s", wt->id)));
 
 341                 strbuf_addf_gently(errmsg, _("'%s' does not point back to '%s'"),
 
 342                                    wt->path, git_common_path("worktrees/%s", wt->id));
 
 345         strbuf_release(&wt_path);
 
 349 void update_worktree_location(struct worktree *wt, const char *path_)
 
 351         struct strbuf path = STRBUF_INIT;
 
 353         if (is_main_worktree(wt))
 
 354                 BUG("can't relocate main worktree");
 
 356         strbuf_realpath(&path, path_, 1);
 
 357         if (fspathcmp(wt->path, path.buf)) {
 
 358                 write_file(git_common_path("worktrees/%s/gitdir", wt->id),
 
 359                            "%s/.git", path.buf);
 
 361                 wt->path = strbuf_detach(&path, NULL);
 
 363         strbuf_release(&path);
 
 366 int is_worktree_being_rebased(const struct worktree *wt,
 
 369         struct wt_status_state state;
 
 372         memset(&state, 0, sizeof(state));
 
 373         found_rebase = wt_status_check_rebase(wt, &state) &&
 
 374                 ((state.rebase_in_progress ||
 
 375                   state.rebase_interactive_in_progress) &&
 
 377                  starts_with(target, "refs/heads/") &&
 
 378                  !strcmp(state.branch, target + strlen("refs/heads/")));
 
 384 int is_worktree_being_bisected(const struct worktree *wt,
 
 387         struct wt_status_state state;
 
 390         memset(&state, 0, sizeof(state));
 
 391         found_rebase = wt_status_check_bisect(wt, &state) &&
 
 393                 starts_with(target, "refs/heads/") &&
 
 394                 !strcmp(state.branch, target + strlen("refs/heads/"));
 
 400  * note: this function should be able to detect shared symref even if
 
 401  * HEAD is temporarily detached (e.g. in the middle of rebase or
 
 402  * bisect). New commands that do similar things should update this
 
 405 const struct worktree *find_shared_symref(const char *symref,
 
 408         const struct worktree *existing = NULL;
 
 409         static struct worktree **worktrees;
 
 413                 free_worktrees(worktrees);
 
 414         worktrees = get_worktrees(0);
 
 416         for (i = 0; worktrees[i]; i++) {
 
 417                 struct worktree *wt = worktrees[i];
 
 418                 const char *symref_target;
 
 419                 struct ref_store *refs;
 
 425                 if (wt->is_detached && !strcmp(symref, "HEAD")) {
 
 426                         if (is_worktree_being_rebased(wt, target)) {
 
 430                         if (is_worktree_being_bisected(wt, target)) {
 
 436                 refs = get_worktree_ref_store(wt);
 
 437                 symref_target = refs_resolve_ref_unsafe(refs, symref, 0,
 
 439                 if ((flags & REF_ISSYMREF) &&
 
 440                     symref_target && !strcmp(symref_target, target)) {
 
 449 int submodule_uses_worktrees(const char *path)
 
 451         char *submodule_gitdir;
 
 452         struct strbuf sb = STRBUF_INIT;
 
 456         struct repository_format format = REPOSITORY_FORMAT_INIT;
 
 458         submodule_gitdir = git_pathdup_submodule(path, "%s", "");
 
 459         if (!submodule_gitdir)
 
 462         /* The env would be set for the superproject. */
 
 463         get_common_dir_noenv(&sb, submodule_gitdir);
 
 464         free(submodule_gitdir);
 
 467          * The check below is only known to be good for repository format
 
 468          * version 0 at the time of writing this code.
 
 470         strbuf_addstr(&sb, "/config");
 
 471         read_repository_format(&format, sb.buf);
 
 472         if (format.version != 0) {
 
 474                 clear_repository_format(&format);
 
 477         clear_repository_format(&format);
 
 479         /* Replace config by worktrees. */
 
 480         strbuf_setlen(&sb, sb.len - strlen("config"));
 
 481         strbuf_addstr(&sb, "worktrees");
 
 483         /* See if there is any file inside the worktrees directory. */
 
 484         dir = opendir(sb.buf);
 
 490         while ((d = readdir(dir)) != NULL) {
 
 491                 if (is_dot_or_dotdot(d->d_name))
 
 501 int parse_worktree_ref(const char *worktree_ref, const char **name,
 
 502                        int *name_length, const char **ref)
 
 504         if (skip_prefix(worktree_ref, "main-worktree/", &worktree_ref)) {
 
 515         if (skip_prefix(worktree_ref, "worktrees/", &worktree_ref)) {
 
 516                 const char *slash = strchr(worktree_ref, '/');
 
 518                 if (!slash || slash == worktree_ref || !slash[1])
 
 521                         *name = worktree_ref;
 
 523                         *name_length = slash - worktree_ref;
 
 531 void strbuf_worktree_ref(const struct worktree *wt,
 
 535         switch (ref_type(refname)) {
 
 536         case REF_TYPE_PSEUDOREF:
 
 537         case REF_TYPE_PER_WORKTREE:
 
 538                 if (wt && !wt->is_current) {
 
 539                         if (is_main_worktree(wt))
 
 540                                 strbuf_addstr(sb, "main-worktree/");
 
 542                                 strbuf_addf(sb, "worktrees/%s/", wt->id);
 
 546         case REF_TYPE_MAIN_PSEUDOREF:
 
 547         case REF_TYPE_OTHER_PSEUDOREF:
 
 550         case REF_TYPE_NORMAL:
 
 552                  * For shared refs, don't prefix worktrees/ or
 
 553                  * main-worktree/. It's not necessary and
 
 554                  * files-backend.c can't handle it anyway.
 
 558         strbuf_addstr(sb, refname);
 
 561 const char *worktree_ref(const struct worktree *wt, const char *refname)
 
 563         static struct strbuf sb = STRBUF_INIT;
 
 566         strbuf_worktree_ref(wt, &sb, refname);
 
 570 int other_head_refs(each_ref_fn fn, void *cb_data)
 
 572         struct worktree **worktrees, **p;
 
 575         worktrees = get_worktrees(0);
 
 576         for (p = worktrees; *p; p++) {
 
 577                 struct worktree *wt = *p;
 
 578                 struct object_id oid;
 
 584                 if (!refs_read_ref_full(get_main_ref_store(the_repository),
 
 585                                         worktree_ref(wt, "HEAD"),
 
 588                         ret = fn(worktree_ref(wt, "HEAD"), &oid, flag, cb_data);
 
 592         free_worktrees(worktrees);