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
use std::fmt::Write;
use eyre::Context;
use tracing::instrument;
use crate::core::effects::Effects;
use crate::core::eventlog::{
is_gc_ref, CommitActivityStatus, EventCursor, EventLogDb, EventReplayer,
};
use crate::core::formatting::Pluralize;
use crate::git::{NonZeroOid, Reference, Repo};
pub fn find_dangling_references<'repo>(
repo: &'repo Repo,
event_replayer: &EventReplayer,
event_cursor: EventCursor,
) -> eyre::Result<Vec<Reference<'repo>>> {
let mut result = Vec::new();
for reference in repo.get_all_references()? {
let reference_name = reference.get_name()?;
if !is_gc_ref(&reference_name) {
continue;
}
let commit = match reference.peel_to_commit()? {
Some(commit) => commit,
None => continue,
};
match event_replayer.get_cursor_commit_activity_status(event_cursor, commit.get_oid()) {
CommitActivityStatus::Active => {
}
CommitActivityStatus::Inactive => {
}
CommitActivityStatus::Obsolete => {
result.push(reference)
}
}
}
Ok(result)
}
#[instrument]
pub fn mark_commit_reachable(repo: &Repo, commit_oid: NonZeroOid) -> eyre::Result<()> {
let ref_name = format!("refs/branchless/{commit_oid}");
eyre::ensure!(
Reference::is_valid_name(&ref_name),
format!("Invalid ref name to mark commit as reachable: {ref_name}")
);
if repo.find_commit(commit_oid)?.is_some() {
repo.create_reference(
&ref_name.into(),
commit_oid,
true,
"branchless: marking commit as reachable",
)
.wrap_err("Creating reference")?;
}
Ok(())
}
#[instrument]
pub fn gc(effects: &Effects) -> eyre::Result<()> {
let repo = Repo::from_current_dir()?;
let conn = repo.get_db_conn()?;
let event_log_db = EventLogDb::new(&conn)?;
let event_replayer = EventReplayer::from_event_log_db(effects, &repo, &event_log_db)?;
let event_cursor = event_replayer.make_default_cursor();
writeln!(
effects.get_output_stream(),
"branchless: collecting garbage"
)?;
let dangling_references = find_dangling_references(&repo, &event_replayer, event_cursor)?;
let num_dangling_references = Pluralize {
determiner: None,
amount: dangling_references.len(),
unit: ("dangling reference", "dangling references"),
}
.to_string();
for mut reference in dangling_references.into_iter() {
reference.delete()?;
}
writeln!(
effects.get_output_stream(),
"branchless: {num_dangling_references} deleted",
)?;
Ok(())
}