Skip to content

Commit 09e0aa6

Browse files
committed
Merge branch 'pw/gc-during-rebase'
The sequencer machinery does not use the ref API and instead records names of certain objects it needs for its correct operation in temporary files, which makes these objects susceptible to loss by garbage collection. These temporary files have been added as starting points for reachability analysis to fix this. * pw/gc-during-rebase: prune: mark rebase autostash and orig-head as reachable
2 parents edae91a + bc7f5db commit 09e0aa6

File tree

3 files changed

+76
-1
lines changed

3 files changed

+76
-1
lines changed

reachable.c

Lines changed: 50 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@
1717
#include "pack-mtimes.h"
1818
#include "config.h"
1919
#include "run-command.h"
20+
#include "sequencer.h"
2021

2122
struct connectivity_progress {
2223
struct progress *progress;
@@ -30,6 +31,52 @@ static void update_progress(struct connectivity_progress *cp)
3031
display_progress(cp->progress, cp->count);
3132
}
3233

34+
static void add_one_file(const char *path, struct rev_info *revs)
35+
{
36+
struct strbuf buf = STRBUF_INIT;
37+
struct object_id oid;
38+
struct object *object;
39+
40+
if (!read_oneliner(&buf, path, READ_ONELINER_SKIP_IF_EMPTY)) {
41+
strbuf_release(&buf);
42+
return;
43+
}
44+
strbuf_trim(&buf);
45+
if (!get_oid_hex(buf.buf, &oid)) {
46+
object = parse_object_or_die(&oid, buf.buf);
47+
add_pending_object(revs, object, "");
48+
}
49+
strbuf_release(&buf);
50+
}
51+
52+
/* Mark objects recorded in rebase state files as reachable. */
53+
static void add_rebase_files(struct rev_info *revs)
54+
{
55+
struct strbuf buf = STRBUF_INIT;
56+
size_t len;
57+
const char *path[] = {
58+
"rebase-apply/autostash",
59+
"rebase-apply/orig-head",
60+
"rebase-merge/autostash",
61+
"rebase-merge/orig-head",
62+
};
63+
struct worktree **worktrees = get_worktrees();
64+
65+
for (struct worktree **wt = worktrees; *wt; wt++) {
66+
strbuf_reset(&buf);
67+
strbuf_addstr(&buf, get_worktree_git_dir(*wt));
68+
strbuf_complete(&buf, '/');
69+
len = buf.len;
70+
for (size_t i = 0; i < ARRAY_SIZE(path); i++) {
71+
strbuf_setlen(&buf, len);
72+
strbuf_addstr(&buf, path[i]);
73+
add_one_file(buf.buf, revs);
74+
}
75+
}
76+
strbuf_release(&buf);
77+
free_worktrees(worktrees);
78+
}
79+
3380
static int add_one_ref(const char *path, const struct object_id *oid,
3481
int flag, void *cb_data)
3582
{
@@ -322,6 +369,9 @@ void mark_reachable_objects(struct rev_info *revs, int mark_reflog,
322369
head_ref(add_one_ref, revs);
323370
other_head_refs(add_one_ref, revs);
324371

372+
/* rebase autostash and orig-head */
373+
add_rebase_files(revs);
374+
325375
/* Add all reflog info */
326376
if (mark_reflog)
327377
add_reflogs_to_pending(revs, 0);

t/t3407-rebase-abort.sh

Lines changed: 16 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -40,9 +40,24 @@ testrebase() {
4040
test_path_is_missing "$state_dir"
4141
'
4242

43+
test_expect_success "pre rebase$type head is marked as reachable" '
44+
# Clean up the state from the previous one
45+
git checkout -f --detach pre-rebase &&
46+
test_tick &&
47+
git commit --amend --only -m "reworded" &&
48+
orig_head=$(git rev-parse HEAD) &&
49+
test_must_fail git rebase$type main &&
50+
# Stop ORIG_HEAD marking $state_dir/orig-head as reachable
51+
git update-ref -d ORIG_HEAD &&
52+
git reflog expire --expire="$GIT_COMMITTER_DATE" --all &&
53+
git prune --expire=now &&
54+
git rebase --abort &&
55+
test_cmp_rev $orig_head HEAD
56+
'
57+
4358
test_expect_success "rebase$type --abort after --skip" '
4459
# Clean up the state from the previous one
45-
git reset --hard pre-rebase &&
60+
git checkout -B to-rebase pre-rebase &&
4661
test_must_fail git rebase$type main &&
4762
test_path_is_dir "$state_dir" &&
4863
test_must_fail git rebase --skip &&

t/t3420-rebase-autostash.sh

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -333,4 +333,14 @@ test_expect_success 'never change active branch' '
333333
test_cmp_rev not-the-feature-branch unrelated-onto-branch
334334
'
335335

336+
test_expect_success 'autostash commit is marked as reachable' '
337+
echo changed >file0 &&
338+
git rebase --autostash --exec "git prune --expire=now" \
339+
feature-branch^ feature-branch &&
340+
# git rebase succeeds if the stash cannot be applied so we need to check
341+
# the contents of file0
342+
echo changed >expect &&
343+
test_cmp expect file0
344+
'
345+
336346
test_done

0 commit comments

Comments
 (0)