-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
worktree: new place for "git prune --worktrees"
Commit 23af91d (prune: strategies for linked checkouts - 2014-11-30) adds "--worktrees" to "git prune" without realizing that "git prune" is for object database only. This patch moves the same functionality to a new command "git worktree". Signed-off-by: Nguyễn Thái Ngọc Duy <pclouds@gmail.com>
- Loading branch information
Showing
11 changed files
with
198 additions
and
114 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,48 @@ | ||
git-worktree(1) | ||
=============== | ||
|
||
NAME | ||
---- | ||
git-worktree - Manage multiple worktrees | ||
|
||
|
||
SYNOPSIS | ||
-------- | ||
[verse] | ||
'git worktree prune' [-n] [-v] [--expire <expire>] | ||
|
||
DESCRIPTION | ||
----------- | ||
|
||
Manage multiple worktrees attached to the same repository. These are | ||
created by the command `git checkout --to`. | ||
|
||
COMMANDS | ||
-------- | ||
prune:: | ||
|
||
Prune working tree information in $GIT_DIR/worktrees. | ||
|
||
OPTIONS | ||
------- | ||
|
||
-n:: | ||
--dry-run:: | ||
Do not remove anything; just report what it would | ||
remove. | ||
|
||
-v:: | ||
--verbose:: | ||
Report all removals. | ||
|
||
--expire <time>:: | ||
Only expire unused worktrees older than <time>. | ||
|
||
SEE ALSO | ||
-------- | ||
|
||
linkgit:git-checkout[1] | ||
|
||
GIT | ||
--- | ||
Part of the linkgit:git[1] suite |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,133 @@ | ||
#include "cache.h" | ||
#include "builtin.h" | ||
#include "dir.h" | ||
#include "parse-options.h" | ||
|
||
static const char * const worktree_usage[] = { | ||
N_("git worktree prune [<options>]"), | ||
NULL | ||
}; | ||
|
||
static int show_only; | ||
static int verbose; | ||
static unsigned long expire; | ||
|
||
static int prune_worktree(const char *id, struct strbuf *reason) | ||
{ | ||
struct stat st; | ||
char *path; | ||
int fd, len; | ||
|
||
if (!is_directory(git_path("worktrees/%s", id))) { | ||
strbuf_addf(reason, _("Removing worktrees/%s: not a valid directory"), id); | ||
return 1; | ||
} | ||
if (file_exists(git_path("worktrees/%s/locked", id))) | ||
return 0; | ||
if (stat(git_path("worktrees/%s/gitdir", id), &st)) { | ||
strbuf_addf(reason, _("Removing worktrees/%s: gitdir file does not exist"), id); | ||
return 1; | ||
} | ||
fd = open(git_path("worktrees/%s/gitdir", id), O_RDONLY); | ||
if (fd < 0) { | ||
strbuf_addf(reason, _("Removing worktrees/%s: unable to read gitdir file (%s)"), | ||
id, strerror(errno)); | ||
return 1; | ||
} | ||
len = st.st_size; | ||
path = xmalloc(len + 1); | ||
read_in_full(fd, path, len); | ||
close(fd); | ||
while (len && (path[len - 1] == '\n' || path[len - 1] == '\r')) | ||
len--; | ||
if (!len) { | ||
strbuf_addf(reason, _("Removing worktrees/%s: invalid gitdir file"), id); | ||
free(path); | ||
return 1; | ||
} | ||
path[len] = '\0'; | ||
if (!file_exists(path)) { | ||
struct stat st_link; | ||
free(path); | ||
/* | ||
* the repo is moved manually and has not been | ||
* accessed since? | ||
*/ | ||
if (!stat(git_path("worktrees/%s/link", id), &st_link) && | ||
st_link.st_nlink > 1) | ||
return 0; | ||
if (st.st_mtime <= expire) { | ||
strbuf_addf(reason, _("Removing worktrees/%s: gitdir file points to non-existent location"), id); | ||
return 1; | ||
} else { | ||
return 0; | ||
} | ||
} | ||
free(path); | ||
return 0; | ||
} | ||
|
||
static void prune_worktrees(void) | ||
{ | ||
struct strbuf reason = STRBUF_INIT; | ||
struct strbuf path = STRBUF_INIT; | ||
DIR *dir = opendir(git_path("worktrees")); | ||
struct dirent *d; | ||
int ret; | ||
if (!dir) | ||
return; | ||
while ((d = readdir(dir)) != NULL) { | ||
if (!strcmp(d->d_name, ".") || !strcmp(d->d_name, "..")) | ||
continue; | ||
strbuf_reset(&reason); | ||
if (!prune_worktree(d->d_name, &reason)) | ||
continue; | ||
if (show_only || verbose) | ||
printf("%s\n", reason.buf); | ||
if (show_only) | ||
continue; | ||
strbuf_reset(&path); | ||
strbuf_addstr(&path, git_path("worktrees/%s", d->d_name)); | ||
ret = remove_dir_recursively(&path, 0); | ||
if (ret < 0 && errno == ENOTDIR) | ||
ret = unlink(path.buf); | ||
if (ret) | ||
error(_("failed to remove: %s"), strerror(errno)); | ||
} | ||
closedir(dir); | ||
if (!show_only) | ||
rmdir(git_path("worktrees")); | ||
strbuf_release(&reason); | ||
strbuf_release(&path); | ||
} | ||
|
||
static int prune(int ac, const char **av, const char *prefix) | ||
{ | ||
struct option options[] = { | ||
OPT__DRY_RUN(&show_only, N_("do not remove, show only")), | ||
OPT__VERBOSE(&verbose, N_("report pruned objects")), | ||
OPT_EXPIRY_DATE(0, "expire", &expire, | ||
N_("expire objects older than <time>")), | ||
OPT_END() | ||
}; | ||
|
||
expire = ULONG_MAX; | ||
ac = parse_options(ac, av, prefix, options, worktree_usage, 0); | ||
if (ac) | ||
usage_with_options(worktree_usage, options); | ||
prune_worktrees(); | ||
return 0; | ||
} | ||
|
||
int cmd_worktree(int ac, const char **av, const char *prefix) | ||
{ | ||
struct option options[] = { | ||
OPT_END() | ||
}; | ||
|
||
if (ac < 2) | ||
usage_with_options(worktree_usage, options); | ||
if (!strcmp(av[1], "prune")) | ||
return prune(ac - 1, av + 1, prefix); | ||
usage_with_options(worktree_usage, options); | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.