static int lock_worktree(int ac, const char **av, const char *prefix) { const char *reason = "", *old_reason; struct option options[] = { OPT_STRING(0, "reason", &reason, N_("string"), N_("reason for locking")), OPT_END() }; struct worktree **worktrees, *wt; ac = parse_options(ac, av, prefix, options, worktree_usage, 0); if (ac != 1) usage_with_options(worktree_usage, options); worktrees = get_worktrees(0); wt = find_worktree(worktrees, prefix, av[0]); if (!wt) die(_("'%s' is not a working tree"), av[0]); if (is_main_worktree(wt)) die(_("The main working tree cannot be locked or unlocked")); old_reason = is_worktree_locked(wt); if (old_reason) { if (*old_reason) die(_("'%s' is already locked, reason: %s"), av[0], old_reason); die(_("'%s' is already locked"), av[0]); } write_file(git_common_path("worktrees/%s/locked", wt->id), "%s", reason); free_worktrees(worktrees); return 0; }
const char *get_worktree_git_dir(const struct worktree *wt) { if (!wt) return get_git_dir(); else if (!wt->id) return get_git_common_dir(); else return git_common_path("worktrees/%s", wt->id); }
static int delete_git_dir(struct worktree *wt) { struct strbuf sb = STRBUF_INIT; int ret = 0; strbuf_addstr(&sb, git_common_path("worktrees/%s", wt->id)); if (remove_dir_recursively(&sb, 0)) { error_errno(_("failed to delete '%s'"), sb.buf); ret = -1; } strbuf_release(&sb); return ret; }
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 int unlock_worktree(int ac, const char **av, const char *prefix) { struct option options[] = { OPT_END() }; struct worktree **worktrees, *wt; int ret; ac = parse_options(ac, av, prefix, options, worktree_usage, 0); if (ac != 1) usage_with_options(worktree_usage, options); worktrees = get_worktrees(0); wt = find_worktree(worktrees, prefix, av[0]); if (!wt) die(_("'%s' is not a working tree"), av[0]); if (is_main_worktree(wt)) die(_("The main working tree cannot be locked or unlocked")); if (!is_worktree_locked(wt)) die(_("'%s' is not locked"), av[0]); ret = unlink_or_warn(git_common_path("worktrees/%s/locked", wt->id)); free_worktrees(worktrees); return ret; }
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; }