From 6835314459794831a1b88bed56549653710e910c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Nguy=E1=BB=85n=20Th=C3=A1i=20Ng=E1=BB=8Dc=20Duy?= Date: Fri, 3 Jun 2016 19:19:39 +0700 Subject: [PATCH 1/6] worktree.c: add find_worktree() MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit So far we haven't needed to identify an existing worktree from command line. Future commands such as lock or move will need it. The current implementation identifies worktrees by path (*). In future, the function could learn to identify by $(basename $path) or tags... (*) We could probably go cheaper with comparing inode number (and probably more reliable than paths when unicode enters the game). But not all systems have good inode that so let's stick to something simple for now. Helped-by: Eric Sunshine Signed-off-by: Nguyễn Thái Ngọc Duy Signed-off-by: Junio C Hamano --- worktree.c | 15 +++++++++++++++ worktree.h | 8 ++++++++ 2 files changed, 23 insertions(+) diff --git a/worktree.c b/worktree.c index f4a4f38092..0782e00983 100644 --- a/worktree.c +++ b/worktree.c @@ -214,6 +214,21 @@ const char *get_worktree_git_dir(const struct worktree *wt) return git_common_path("worktrees/%s", wt->id); } +struct worktree *find_worktree(struct worktree **list, + const char *prefix, + const char *arg) +{ + char *path; + + 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; +} + int is_worktree_being_rebased(const struct worktree *wt, const char *target) { diff --git a/worktree.h b/worktree.h index 13949093cc..7ad15da0dc 100644 --- a/worktree.h +++ b/worktree.h @@ -29,6 +29,14 @@ extern struct worktree **get_worktrees(void); */ extern const char *get_worktree_git_dir(const struct worktree *wt); +/* + * Search a worktree that can be unambiguously identified by + * "arg". "prefix" must not be NULL. + */ +extern struct worktree *find_worktree(struct worktree **list, + const char *prefix, + const char *arg); + /* * Free up the memory for worktree(s) */ From 984ad9e56c9d884f7f1aa7d6b2052f3fb082ee5d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Nguy=E1=BB=85n=20Th=C3=A1i=20Ng=E1=BB=8Dc=20Duy?= Date: Fri, 3 Jun 2016 19:19:40 +0700 Subject: [PATCH 2/6] worktree.c: add is_main_worktree() MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Main worktree _is_ different. You can lock (*) a linked worktree but not the main one, for example. Provide an API for checking that. (*) Add the file $GIT_DIR/worktrees/xxx/locked to avoid worktree xxx from being removed or moved. Signed-off-by: Nguyễn Thái Ngọc Duy Signed-off-by: Junio C Hamano --- worktree.c | 5 +++++ worktree.h | 5 +++++ 2 files changed, 10 insertions(+) diff --git a/worktree.c b/worktree.c index 0782e00983..12a766a38d 100644 --- a/worktree.c +++ b/worktree.c @@ -229,6 +229,11 @@ struct worktree *find_worktree(struct worktree **list, return *list; } +int is_main_worktree(const struct worktree *wt) +{ + return !wt->id; +} + int is_worktree_being_rebased(const struct worktree *wt, const char *target) { diff --git a/worktree.h b/worktree.h index 7ad15da0dc..e1c4715238 100644 --- a/worktree.h +++ b/worktree.h @@ -37,6 +37,11 @@ extern struct worktree *find_worktree(struct worktree **list, const char *prefix, const char *arg); +/* + * Return true if the given worktree is the main one. + */ +extern int is_main_worktree(const struct worktree *wt); + /* * Free up the memory for worktree(s) */ From 346ef53058ef25f5a7273ee77c03ebc5f732ad77 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Nguy=E1=BB=85n=20Th=C3=A1i=20Ng=E1=BB=8Dc=20Duy?= Date: Mon, 13 Jun 2016 19:18:23 +0700 Subject: [PATCH 3/6] worktree.c: add is_worktree_locked() MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit We need this later to avoid double locking a worktree, or unlocking one when it's not even locked. Signed-off-by: Nguyễn Thái Ngọc Duy Signed-off-by: Junio C Hamano --- worktree.c | 28 ++++++++++++++++++++++++++++ worktree.h | 8 ++++++++ 2 files changed, 36 insertions(+) diff --git a/worktree.c b/worktree.c index 12a766a38d..2bcfff3850 100644 --- a/worktree.c +++ b/worktree.c @@ -13,6 +13,7 @@ void free_worktrees(struct worktree **worktrees) free(worktrees[i]->path); free(worktrees[i]->id); free(worktrees[i]->head_ref); + free(worktrees[i]->lock_reason); free(worktrees[i]); } free (worktrees); @@ -98,6 +99,8 @@ static struct worktree *get_main_worktree(void) worktree->is_detached = is_detached; worktree->is_current = 0; add_head_info(&head_ref, worktree); + worktree->lock_reason = NULL; + worktree->lock_reason_valid = 0; done: strbuf_release(&path); @@ -143,6 +146,8 @@ static struct worktree *get_linked_worktree(const char *id) worktree->is_detached = is_detached; worktree->is_current = 0; add_head_info(&head_ref, worktree); + worktree->lock_reason = NULL; + worktree->lock_reason_valid = 0; done: strbuf_release(&path); @@ -234,6 +239,29 @@ int is_main_worktree(const struct worktree *wt) return !wt->id; } +const char *is_worktree_locked(struct worktree *wt) +{ + assert(!is_main_worktree(wt)); + + if (!wt->lock_reason_valid) { + struct strbuf path = STRBUF_INIT; + + strbuf_addstr(&path, worktree_git_path(wt, "locked")); + if (file_exists(path.buf)) { + struct strbuf lock_reason = STRBUF_INIT; + if (strbuf_read_file(&lock_reason, path.buf, 0) < 0) + die_errno(_("failed to read '%s'"), path.buf); + strbuf_trim(&lock_reason); + wt->lock_reason = strbuf_detach(&lock_reason, NULL); + } else + wt->lock_reason = NULL; + wt->lock_reason_valid = 1; + strbuf_release(&path); + } + + return wt->lock_reason; +} + int is_worktree_being_rebased(const struct worktree *wt, const char *target) { diff --git a/worktree.h b/worktree.h index e1c4715238..90e1311fa7 100644 --- a/worktree.h +++ b/worktree.h @@ -5,10 +5,12 @@ struct worktree { char *path; char *id; char *head_ref; + char *lock_reason; /* internal use */ unsigned char head_sha1[20]; int is_detached; int is_bare; int is_current; + int lock_reason_valid; }; /* Functions for acting on the information about worktrees. */ @@ -42,6 +44,12 @@ extern struct worktree *find_worktree(struct worktree **list, */ extern int is_main_worktree(const struct worktree *wt); +/* + * Return the reason string if the given worktree is locked or NULL + * otherwise. + */ +extern const char *is_worktree_locked(struct worktree *wt); + /* * Free up the memory for worktree(s) */ From 58142c09a4fe825912e5a2ebfa1ba5f7f6d8beb5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Nguy=E1=BB=85n=20Th=C3=A1i=20Ng=E1=BB=8Dc=20Duy?= Date: Mon, 13 Jun 2016 19:18:24 +0700 Subject: [PATCH 4/6] worktree: add "lock" command MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Helped-by: Eric Sunshine Signed-off-by: Nguyễn Thái Ngọc Duy Signed-off-by: Junio C Hamano --- Documentation/git-worktree.txt | 26 ++++++++++---- builtin/worktree.c | 38 ++++++++++++++++++++ contrib/completion/git-completion.bash | 5 ++- t/t2028-worktree-move.sh | 48 ++++++++++++++++++++++++++ 4 files changed, 110 insertions(+), 7 deletions(-) create mode 100755 t/t2028-worktree-move.sh diff --git a/Documentation/git-worktree.txt b/Documentation/git-worktree.txt index 27feff6dba..b49b25bf52 100644 --- a/Documentation/git-worktree.txt +++ b/Documentation/git-worktree.txt @@ -11,6 +11,7 @@ SYNOPSIS [verse] 'git worktree add' [-f] [--detach] [--checkout] [-b ] [] 'git worktree list' [--porcelain] +'git worktree lock' [--reason ] 'git worktree prune' [-n] [-v] [--expire ] DESCRIPTION @@ -38,9 +39,8 @@ section "DETAILS" for more information. If a linked working tree is stored on a portable device or network share which is not always mounted, you can prevent its administrative files from -being pruned by creating a file named 'locked' alongside the other -administrative files, optionally containing a plain text reason that -pruning should be suppressed. See section "DETAILS" for more information. +being pruned by issuing the `git worktree lock` command, optionally +specifying `--reason` to explain why the working tree is locked. COMMANDS -------- @@ -61,6 +61,14 @@ each of the linked worktrees. The output details include if the worktree is bare, the revision currently checked out, and the branch currently checked out (or 'detached HEAD' if none). +lock:: + +If a working tree is on a portable device or network share which +is not always mounted, lock it to prevent its administrative +files from being pruned automatically. This also prevents it from +being moved or deleted. Optionally, specify a reason for the lock +with `--reason`. + prune:: Prune working tree information in $GIT_DIR/worktrees. @@ -110,6 +118,13 @@ OPTIONS --expire