add -d option to 'got fetch' for deleting old branches and tags
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147
diff --git a/got/got.1 b/got/got.1
index 9b73410..36ad40d 100644
--- a/got/got.1
+++ b/got/got.1
@@ -272,7 +272,7 @@ The maximum is 3.
.It Cm cl
Short alias for
.Cm clone .
-.It Cm fetch Oo Fl a Oc Oo Fl b Ar branch Oc Oo Fl l Oc Oo Fl r Ar repository-path Oc Oo Fl q Oc Oo Fl v Oc Op Ar remote-repository
+.It Cm fetch Oo Fl a Oc Oo Fl b Ar branch Oc Oo Fl d Oc Oo Fl l Oc Oo Fl r Ar repository-path Oc Oo Fl q Oc Oo Fl v Oc Op Ar remote-repository
Fetch new changes from a remote repository.
If no
.Ar remote-repository
@@ -333,6 +333,13 @@ repository's HEAD reference will be fetched.
Cannot be used together with the
.Fl a
option.
+.It Fl d
+Delete branches and tags from the local repository which are no longer
+present in the remote repository.
+Only references are deleted.
+Any commit, tree, and blob objects belonging to deleted branches or
+tags remain in the repository and may be removed separately with
+Git's garbage collector.
.It Fl l
List branches and tags available for fetching from the remote repository
and exit immediately.
diff --git a/got/got.c b/got/got.c
index 2a73dd3..631195e 100644
--- a/got/got.c
+++ b/got/got.c
@@ -1373,13 +1373,62 @@ done:
__dead static void
usage_fetch(void)
{
- fprintf(stderr, "usage: %s fetch [-a] [-b branch] [-l] "
+ fprintf(stderr, "usage: %s fetch [-a] [-b branch] [-d] [-l] "
"[-r repository-path] [-q] [-v] [remote-repository-name]\n",
getprogname());
exit(1);
}
static const struct got_error *
+delete_missing_refs(struct got_pathlist_head *their_refs,
+ struct got_repository *repo)
+{
+ const struct got_error *err = NULL;
+ struct got_reflist_head my_refs;
+ struct got_reflist_entry *re;
+ struct got_pathlist_entry *pe;
+ struct got_object_id *id;
+ char *id_str;
+
+ SIMPLEQ_INIT(&my_refs);
+
+ err = got_ref_list(&my_refs, repo, NULL, got_ref_cmp_by_name, NULL);
+ if (err)
+ return err;
+
+ SIMPLEQ_FOREACH(re, &my_refs, entry) {
+ const char *refname = got_ref_get_name(re->ref);
+
+ if (strncmp(refname, "refs/heads/", 11) != 0 &&
+ strncmp(refname, "refs/tags/", 10) != 0)
+ continue;
+
+ TAILQ_FOREACH(pe, their_refs, entry) {
+ if (strcmp(refname, pe->path) == 0)
+ break;
+ }
+ if (pe != NULL)
+ continue;
+
+ err = got_ref_resolve(&id, repo, re->ref);
+ if (err)
+ break;
+ err = got_object_id_str(&id_str, id);
+ free(id);
+ if (err)
+ break;
+
+ printf("Deleting %s: %s\n", got_ref_get_name(re->ref), id_str);
+ free(id_str);
+ err = got_ref_delete(re->ref, repo);
+ if (err)
+ break;
+ }
+
+ return err;
+}
+
+static const struct got_error *
cmd_fetch(int argc, char *argv[])
{
const struct got_error *error = NULL;
@@ -1399,12 +1448,13 @@ cmd_fetch(int argc, char *argv[])
pid_t fetchpid = -1;
struct got_fetch_progress_arg fpa;
int verbosity = 0, fetch_all_branches = 0, list_refs_only = 0;
+ int delete_refs = 0;
TAILQ_INIT(&refs);
TAILQ_INIT(&symrefs);
TAILQ_INIT(&wanted_branches);
- while ((ch = getopt(argc, argv, "ab:lr:vq")) != -1) {
+ while ((ch = getopt(argc, argv, "ab:dlr:vq")) != -1) {
switch (ch) {
case 'a':
fetch_all_branches = 1;
@@ -1415,6 +1465,9 @@ cmd_fetch(int argc, char *argv[])
if (error)
return error;
break;
+ case 'd':
+ delete_refs = 1;
+ break;
case 'l':
list_refs_only = 1;
break;
@@ -1449,6 +1502,8 @@ cmd_fetch(int argc, char *argv[])
errx(1, "-l and -b options are mutually exclusive");
if (fetch_all_branches)
errx(1, "-l and -a options are mutually exclusive");
+ if (delete_refs)
+ errx(1, "-l and -d options are mutually exclusive");
if (verbosity == -1)
errx(1, "-l and -q options are mutually exclusive");
}
@@ -1568,6 +1623,8 @@ cmd_fetch(int argc, char *argv[])
if (pack_hash == NULL) {
if (verbosity >= 0)
printf("Already up-to-date\n");
+ if (delete_refs)
+ error = delete_missing_refs(&refs, repo);
goto done;
}
@@ -1642,6 +1699,8 @@ cmd_fetch(int argc, char *argv[])
free(id_str);
id_str = NULL;
}
+ if (delete_refs)
+ error = delete_missing_refs(&refs, repo);
done:
if (fetchpid > 0) {
if (kill(fetchpid, SIGTERM) == -1)