Skip to content

Commit 0e7dc42

Browse files
authored
Merge pull request #80 from epage/squash
fix(graph): Gracefully handle squash-merges
2 parents 5970e72 + b7d0d3e commit 0e7dc42

File tree

14 files changed

+724
-18
lines changed

14 files changed

+724
-18
lines changed

Cargo.lock

+18
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

crates/git-fixture/Cargo.toml

+2
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,8 @@ edition = "2018"
1111

1212
[dependencies]
1313
serde = { version = "1", features = ["derive"] }
14+
humantime = "2"
15+
humantime-serde = "1"
1416
bstr = { version = "0.2", features = ["serde1"] }
1517
derive_more = "0.99.0"
1618
eyre = "0.6"

crates/git-fixture/src/lib.rs

+10-9
Original file line numberDiff line numberDiff line change
@@ -44,24 +44,26 @@ impl Dag {
4444
}
4545

4646
let mut marks: std::collections::HashMap<String, String> = Default::default();
47-
Self::run_events(self.events, cwd, &self.import_root, &mut marks)?;
47+
self.run_events(&self.events, cwd, &self.import_root, &mut marks)?;
4848

4949
Ok(())
5050
}
5151

5252
// Note: shelling out to git to minimize programming bugs
5353
fn run_events(
54-
events: Vec<Event>,
54+
&self,
55+
events: &[Event],
5556
cwd: &std::path::Path,
5657
import_root: &std::path::Path,
5758
marks: &mut std::collections::HashMap<String, String>,
5859
) -> eyre::Result<()> {
59-
for event in events.into_iter() {
60+
for event in events.iter() {
6061
match event {
6162
Event::Import(path) => {
6263
let path = import_root.join(path);
6364
let mut child_dag = Dag::load(&path)?;
6465
child_dag.init = false;
66+
child_dag.sleep = child_dag.sleep.or(self.sleep);
6567
child_dag.run(cwd).wrap_err_with(|| {
6668
format!("Failed when running imported fixcture {}", path.display())
6769
})?;
@@ -113,6 +115,9 @@ impl Dag {
113115
p.arg("--author").arg(author);
114116
}
115117
p.ok()?;
118+
if let Some(sleep) = self.sleep {
119+
std::thread::sleep(sleep);
120+
}
116121

117122
if let Some(branch) = tree.branch.as_ref() {
118123
let _ = std::process::Command::new("git")
@@ -135,15 +140,11 @@ impl Dag {
135140
}
136141
}
137142
}
138-
Event::Children(mut events) => {
143+
Event::Children(events) => {
139144
let start_commit = current_oid(cwd)?;
140-
let last_run = events.pop();
141145
for run in events {
142-
Self::run_events(run, cwd, import_root, marks)?;
143146
checkout(cwd, &start_commit)?;
144-
}
145-
if let Some(last_run) = last_run {
146-
Self::run_events(last_run, cwd, import_root, marks)?;
147+
self.run_events(run, cwd, import_root, marks)?;
147148
}
148149
}
149150
Event::Head(reference) => {

crates/git-fixture/src/main.rs

+6-1
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,9 @@ struct Args {
1010
input: Option<std::path::PathBuf>,
1111
#[structopt(short, long)]
1212
output: Option<std::path::PathBuf>,
13+
/// Sleep between commits
14+
#[structopt(long, parse(try_from_str))]
15+
sleep: Option<humantime::Duration>,
1316

1417
#[structopt(short, long, group = "mode")]
1518
schema: Option<std::path::PathBuf>,
@@ -24,11 +27,13 @@ fn run() -> proc_exit::ExitResult {
2427
let args = Args::from_args();
2528
let output = args
2629
.output
30+
.clone()
2731
.unwrap_or_else(|| std::env::current_dir().unwrap());
2832

2933
if let Some(input) = args.input.as_deref() {
3034
std::fs::create_dir_all(&output)?;
31-
let dag = git_fixture::Dag::load(input).with_code(proc_exit::Code::CONFIG_ERR)?;
35+
let mut dag = git_fixture::Dag::load(input).with_code(proc_exit::Code::CONFIG_ERR)?;
36+
dag.sleep = dag.sleep.or_else(|| args.sleep.map(|s| s.into()));
3237
dag.run(&output).with_code(proc_exit::Code::FAILURE)?;
3338
} else if let Some(schema_path) = args.schema.as_deref() {
3439
let schema = schemars::schema_for!(git_fixture::Dag);

crates/git-fixture/src/model.rs

+4
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,10 @@ pub struct Dag {
55
#[serde(default = "init_default")]
66
pub init: bool,
77
#[serde(default)]
8+
#[serde(serialize_with = "humantime_serde::serialize")]
9+
#[serde(deserialize_with = "humantime_serde::deserialize")]
10+
pub sleep: Option<std::time::Duration>,
11+
#[serde(default)]
812
pub events: Vec<Event>,
913
#[serde(skip)]
1014
pub import_root: std::path::PathBuf,

src/bin/git-stack/stack.rs

+14-5
Original file line numberDiff line numberDiff line change
@@ -340,11 +340,16 @@ pub fn stack(args: &crate::args::Args, colored_stdout: bool) -> proc_exit::ExitR
340340

341341
fn plan_rebase(state: &State, stack: &StackState) -> eyre::Result<git_stack::git::Script> {
342342
let mut graphed_branches = stack.graphed_branches();
343-
let mut root = git_stack::graph::Node::new(state.head_commit.clone(), &mut graphed_branches);
343+
let base_commit = state
344+
.repo
345+
.find_commit(stack.base.id)
346+
.expect("base branch is valid");
347+
let mut root = git_stack::graph::Node::new(base_commit, &mut graphed_branches);
344348
root = root.extend_branches(&state.repo, graphed_branches)?;
345349
git_stack::graph::protect_branches(&mut root, &state.repo, &state.protected_branches);
346350

347351
git_stack::graph::rebase_branches(&mut root, stack.onto.id);
352+
git_stack::graph::drop_by_tree_id(&mut root);
348353

349354
let script = git_stack::graph::to_script(&root);
350355

@@ -374,14 +379,18 @@ fn show(state: &State, colored_stdout: bool) -> eyre::Result<()> {
374379
.iter()
375380
.map(|stack| -> eyre::Result<git_stack::graph::Node> {
376381
let mut graphed_branches = stack.graphed_branches();
377-
let mut root =
378-
git_stack::graph::Node::new(state.head_commit.clone(), &mut graphed_branches);
382+
let base_commit = state
383+
.repo
384+
.find_commit(stack.base.id)
385+
.expect("base branch is valid");
386+
let mut root = git_stack::graph::Node::new(base_commit, &mut graphed_branches);
379387
root = root.extend_branches(&state.repo, graphed_branches)?;
380388
git_stack::graph::protect_branches(&mut root, &state.repo, &state.protected_branches);
381389

382390
if state.dry_run {
383391
// Show as-if we performed all mutations
384392
git_stack::graph::rebase_branches(&mut root, stack.onto.id);
393+
git_stack::graph::drop_by_tree_id(&mut root);
385394
}
386395

387396
eyre::Result::Ok(root)
@@ -680,7 +689,7 @@ fn drop_branches(
680689
if branch.name == potential_head {
681690
continue;
682691
} else if head_branch_name == Some(branch.name.as_str()) {
683-
// Dom't leave HEAD detached but instead switch to the branch we pulled
692+
// Don't leave HEAD detached but instead switch to the branch we pulled
684693
log::trace!("git switch {}", potential_head);
685694
if !dry_run {
686695
repo.switch(potential_head)?;
@@ -1187,7 +1196,7 @@ fn format_commit_status<'d>(
11871196
if node.action.is_protected() {
11881197
format!("")
11891198
} else if node.action.is_delete() {
1190-
format!("{} ", palette.warn.paint("(drop)"))
1199+
format!("{} ", palette.error.paint("(drop)"))
11911200
} else if 1 < repo
11921201
.raw()
11931202
.find_commit(node.local_commit.id)

0 commit comments

Comments
 (0)