Skip to content

Commit eab3296

Browse files
pcloudsgitster
authored andcommitted
prune: clean .git/shallow after pruning objects
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 <[email protected]> Signed-off-by: Junio C Hamano <[email protected]>
1 parent 0d7d285 commit eab3296

File tree

6 files changed

+71
-2
lines changed

6 files changed

+71
-2
lines changed

Documentation/git-prune.txt

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,8 @@ objects unreachable from any of these head objects from the object database.
2424
In addition, it
2525
prunes the unpacked objects that are also found in packs by
2626
running 'git prune-packed'.
27+
It also removes entries from .git/shallow that are not reachable by
28+
any ref.
2729

2830
Note that unreachable, packed objects will remain. If this is
2931
not desired, see linkgit:git-repack[1].

builtin/gc.c

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@
1616
#include "run-command.h"
1717
#include "sigchain.h"
1818
#include "argv-array.h"
19+
#include "commit.h"
1920

2021
#define FAILED_RUN "failed to run %s"
2122

builtin/prune.c

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -170,5 +170,9 @@ int cmd_prune(int argc, const char **argv, const char *prefix)
170170
s = mkpathdup("%s/pack", get_object_directory());
171171
remove_temporary_files(s);
172172
free(s);
173+
174+
if (is_repository_shallow())
175+
prune_shallow(show_only);
176+
173177
return 0;
174178
}

commit.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -235,6 +235,7 @@ extern void assign_shallow_commits_to_refs(struct shallow_info *info,
235235
uint32_t **used,
236236
int *ref_status);
237237
extern int delayed_reachability_test(struct shallow_info *si, int c);
238+
extern void prune_shallow(int show_only);
238239

239240
int is_descendant_of(struct commit *, struct commit_list *);
240241
int in_merge_bases(struct commit *, struct commit *);

shallow.c

Lines changed: 53 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -155,10 +155,14 @@ void check_shallow_file_for_update(void)
155155
die("shallow file was changed during fetch");
156156
}
157157

158+
#define SEEN_ONLY 1
159+
#define VERBOSE 2
160+
158161
struct write_shallow_data {
159162
struct strbuf *out;
160163
int use_pack_protocol;
161164
int count;
165+
unsigned flags;
162166
};
163167

164168
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)
167171
const char *hex = sha1_to_hex(graft->sha1);
168172
if (graft->nr_parent != -1)
169173
return 0;
174+
if (data->flags & SEEN_ONLY) {
175+
struct commit *c = lookup_commit(graft->sha1);
176+
if (!c || !(c->object.flags & SEEN)) {
177+
if (data->flags & VERBOSE)
178+
printf("Removing %s from .git/shallow\n",
179+
sha1_to_hex(c->object.sha1));
180+
return 0;
181+
}
182+
}
170183
data->count++;
171184
if (data->use_pack_protocol)
172185
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)
177190
return 0;
178191
}
179192

180-
int write_shallow_commits(struct strbuf *out, int use_pack_protocol,
181-
const struct sha1_array *extra)
193+
static int write_shallow_commits_1(struct strbuf *out, int use_pack_protocol,
194+
const struct sha1_array *extra,
195+
unsigned flags)
182196
{
183197
struct write_shallow_data data;
184198
int i;
185199
data.out = out;
186200
data.use_pack_protocol = use_pack_protocol;
187201
data.count = 0;
202+
data.flags = flags;
188203
for_each_commit_graft(write_one_shallow, &data);
189204
if (!extra)
190205
return data.count;
@@ -196,6 +211,12 @@ int write_shallow_commits(struct strbuf *out, int use_pack_protocol,
196211
return data.count;
197212
}
198213

214+
int write_shallow_commits(struct strbuf *out, int use_pack_protocol,
215+
const struct sha1_array *extra)
216+
{
217+
return write_shallow_commits_1(out, use_pack_protocol, extra, 0);
218+
}
219+
199220
char *setup_temporary_shallow(const struct sha1_array *extra)
200221
{
201222
struct strbuf sb = STRBUF_INIT;
@@ -258,6 +279,36 @@ void advertise_shallow_grafts(int fd)
258279
for_each_commit_graft(advertise_shallow_grafts_cb, &fd);
259280
}
260281

282+
/*
283+
* mark_reachable_objects() should have been run prior to this and all
284+
* reachable commits marked as "SEEN".
285+
*/
286+
void prune_shallow(int show_only)
287+
{
288+
static struct lock_file shallow_lock;
289+
struct strbuf sb = STRBUF_INIT;
290+
int fd;
291+
292+
if (show_only) {
293+
write_shallow_commits_1(&sb, 0, NULL, SEEN_ONLY | VERBOSE);
294+
strbuf_release(&sb);
295+
return;
296+
}
297+
check_shallow_file_for_update();
298+
fd = hold_lock_file_for_update(&shallow_lock, git_path("shallow"),
299+
LOCK_DIE_ON_ERROR);
300+
if (write_shallow_commits_1(&sb, 0, NULL, SEEN_ONLY)) {
301+
if (write_in_full(fd, sb.buf, sb.len) != sb.len)
302+
die_errno("failed to write to %s",
303+
shallow_lock.filename);
304+
commit_lock_file(&shallow_lock);
305+
} else {
306+
unlink(git_path("shallow"));
307+
rollback_lock_file(&shallow_lock);
308+
}
309+
strbuf_release(&sb);
310+
}
311+
261312
#define TRACE_KEY "GIT_TRACE_SHALLOW"
262313

263314
/*

t/t5304-prune.sh

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -221,4 +221,14 @@ EOF
221221
test_cmp expected actual
222222
'
223223

224+
test_expect_success 'prune .git/shallow' '
225+
SHA1=`echo hi|git commit-tree HEAD^{tree}` &&
226+
echo $SHA1 >.git/shallow &&
227+
git prune --dry-run >out &&
228+
grep $SHA1 .git/shallow &&
229+
grep $SHA1 out &&
230+
git prune &&
231+
! test -f .git/shallow
232+
'
233+
224234
test_done

0 commit comments

Comments
 (0)