This patch teaches "prune" to remove shallow roots that are no longer reachable from any refs (e.g. when the relevant refs are removed). Signed-off-by: Nguyễn Thái Ngọc Duy <pclouds@xxxxxxxxx> --- Documentation/git-prune.txt | 2 ++ builtin/gc.c | 1 + builtin/prune.c | 4 ++++ commit.h | 1 + shallow.c | 55 +++++++++++++++++++++++++++++++++++++++++++-- t/t5304-prune.sh | 10 +++++++++ 6 files changed, 71 insertions(+), 2 deletions(-) diff --git a/Documentation/git-prune.txt b/Documentation/git-prune.txt index bf82410..058ac0d 100644 --- a/Documentation/git-prune.txt +++ b/Documentation/git-prune.txt @@ -24,6 +24,8 @@ objects unreachable from any of these head objects from the object database. In addition, it prunes the unpacked objects that are also found in packs by running 'git prune-packed'. +It also removes entries from .git/shallow that are not reachable by +any ref. Note that unreachable, packed objects will remain. If this is not desired, see linkgit:git-repack[1]. diff --git a/builtin/gc.c b/builtin/gc.c index c14190f..cec8ecd 100644 --- a/builtin/gc.c +++ b/builtin/gc.c @@ -16,6 +16,7 @@ #include "run-command.h" #include "sigchain.h" #include "argv-array.h" +#include "commit.h" #define FAILED_RUN "failed to run %s" diff --git a/builtin/prune.c b/builtin/prune.c index 6366917..2214040 100644 --- a/builtin/prune.c +++ b/builtin/prune.c @@ -170,5 +170,9 @@ int cmd_prune(int argc, const char **argv, const char *prefix) s = mkpathdup("%s/pack", get_object_directory()); remove_temporary_files(s); free(s); + + if (is_repository_shallow()) + prune_shallow(show_only); + return 0; } diff --git a/commit.h b/commit.h index a1f2d49..affe210 100644 --- a/commit.h +++ b/commit.h @@ -235,6 +235,7 @@ extern void assign_shallow_commits_to_refs(struct shallow_info *info, uint32_t **used, int *ref_status); extern int delayed_reachability_test(struct shallow_info *si, int c); +extern void prune_shallow(int show_only); int is_descendant_of(struct commit *, struct commit_list *); int in_merge_bases(struct commit *, struct commit *); diff --git a/shallow.c b/shallow.c index e611639..f2ab72c 100644 --- a/shallow.c +++ b/shallow.c @@ -155,10 +155,14 @@ void check_shallow_file_for_update(void) die("shallow file was changed during fetch"); } +#define SEEN_ONLY 1 +#define VERBOSE 2 + struct write_shallow_data { struct strbuf *out; int use_pack_protocol; int count; + unsigned flags; }; static int write_one_shallow(const struct commit_graft *graft, void *cb_data) @@ -167,6 +171,15 @@ static int write_one_shallow(const struct commit_graft *graft, void *cb_data) const char *hex = sha1_to_hex(graft->sha1); if (graft->nr_parent != -1) return 0; + if (data->flags & SEEN_ONLY) { + struct commit *c = lookup_commit(graft->sha1); + if (!c || !(c->object.flags & SEEN)) { + if (data->flags & VERBOSE) + printf("Removing %s from .git/shallow\n", + sha1_to_hex(c->object.sha1)); + return 0; + } + } data->count++; if (data->use_pack_protocol) packet_buf_write(data->out, "shallow %s", hex); @@ -177,14 +190,16 @@ static int write_one_shallow(const struct commit_graft *graft, void *cb_data) return 0; } -int write_shallow_commits(struct strbuf *out, int use_pack_protocol, - const struct sha1_array *extra) +static int write_shallow_commits_1(struct strbuf *out, int use_pack_protocol, + const struct sha1_array *extra, + unsigned flags) { struct write_shallow_data data; int i; data.out = out; data.use_pack_protocol = use_pack_protocol; data.count = 0; + data.flags = flags; for_each_commit_graft(write_one_shallow, &data); if (!extra) return data.count; @@ -196,6 +211,12 @@ int write_shallow_commits(struct strbuf *out, int use_pack_protocol, return data.count; } +int write_shallow_commits(struct strbuf *out, int use_pack_protocol, + const struct sha1_array *extra) +{ + return write_shallow_commits_1(out, use_pack_protocol, extra, 0); +} + char *setup_temporary_shallow(const struct sha1_array *extra) { struct strbuf sb = STRBUF_INIT; @@ -258,6 +279,36 @@ void advertise_shallow_grafts(int fd) for_each_commit_graft(advertise_shallow_grafts_cb, &fd); } +/* + * mark_reachable_objects() should have been run prior to this and all + * reachable commits marked as "SEEN". + */ +void prune_shallow(int show_only) +{ + static struct lock_file shallow_lock; + struct strbuf sb = STRBUF_INIT; + int fd; + + if (show_only) { + write_shallow_commits_1(&sb, 0, NULL, SEEN_ONLY | VERBOSE); + strbuf_release(&sb); + return; + } + check_shallow_file_for_update(); + fd = hold_lock_file_for_update(&shallow_lock, git_path("shallow"), + LOCK_DIE_ON_ERROR); + if (write_shallow_commits_1(&sb, 0, NULL, SEEN_ONLY)) { + if (write_in_full(fd, sb.buf, sb.len) != sb.len) + die_errno("failed to write to %s", + shallow_lock.filename); + commit_lock_file(&shallow_lock); + } else { + unlink(git_path("shallow")); + rollback_lock_file(&shallow_lock); + } + strbuf_release(&sb); +} + #define TRACE_KEY "GIT_TRACE_SHALLOW" /* diff --git a/t/t5304-prune.sh b/t/t5304-prune.sh index e4bb3a1..66c9a41 100755 --- a/t/t5304-prune.sh +++ b/t/t5304-prune.sh @@ -221,4 +221,14 @@ EOF test_cmp expected actual ' +test_expect_success 'prune .git/shallow' ' + SHA1=`echo hi|git commit-tree HEAD^{tree}` && + echo $SHA1 >.git/shallow && + git prune --dry-run >out && + grep $SHA1 .git/shallow && + grep $SHA1 out && + git prune && + ! test -f .git/shallow +' + test_done -- 1.8.5.1.25.g8667982 -- To unsubscribe from this list: send the line "unsubscribe git" in the body of a message to majordomo@xxxxxxxxxxxxxxx More majordomo info at http://vger.kernel.org/majordomo-info.html