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
use std::ffi::OsStr;
use std::fmt::Write;
use eyre::Context;
use tracing::instrument;
use crate::core::eventlog::{is_gc_ref, EventLogDb, EventReplayer};
use crate::core::graph::{make_graph, BranchOids, CommitGraph, HeadOid, MainBranchOid};
use crate::core::mergebase::MergeBaseDb;
use crate::git::{NonZeroOid, Reference, Repo};
use crate::tui::Effects;
fn find_dangling_references<'repo>(
repo: &'repo Repo,
graph: &CommitGraph,
) -> eyre::Result<Vec<Reference<'repo>>> {
let mut result = Vec::new();
for reference in repo.get_all_references()? {
let reference_name = reference.get_name()?;
if let Some(commit) = reference.peel_to_commit()? {
if is_gc_ref(&reference_name) && !graph.contains_key(&commit.get_oid()) {
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.to_string());
eyre::ensure!(
Reference::is_valid_name(&ref_name),
format!("Invalid ref name to mark commit as reachable: {}", ref_name)
);
repo.create_reference(
OsStr::new(&ref_name),
commit_oid,
true,
"branchless: marking commit as reachable",
)
.wrap_err_with(|| format!("Creating reference {}", ref_name))?;
Ok(())
}
#[instrument]
pub fn gc(effects: &Effects) -> eyre::Result<()> {
let repo = Repo::from_current_dir()?;
let conn = repo.get_db_conn()?;
let merge_base_db = MergeBaseDb::new(&conn)?;
let event_log_db = EventLogDb::new(&conn)?;
let event_replayer = EventReplayer::from_event_log_db(effects, &repo, &event_log_db)?;
let head_oid = repo.get_head_info()?.oid;
let main_branch_oid = repo.get_main_branch_oid()?;
let branch_oid_to_names = repo.get_branch_oid_to_names()?;
let graph = make_graph(
effects,
&repo,
&merge_base_db,
&event_replayer,
event_replayer.make_default_cursor(),
&HeadOid(head_oid),
&MainBranchOid(main_branch_oid),
&BranchOids(branch_oid_to_names.keys().copied().collect()),
true,
)?;
writeln!(
effects.get_output_stream(),
"branchless: collecting garbage"
)?;
let dangling_references = find_dangling_references(&repo, &graph)?;
for mut reference in dangling_references.into_iter() {
reference
.delete()
.wrap_err_with(|| format!("Deleting reference {:?}", reference.get_name()))?;
}
Ok(())
}