From 359f96fd2dd04a4cbad8c0f919eb42090610b483 Mon Sep 17 00:00:00 2001 From: Timothy Andrew Date: Wed, 17 Jun 2020 18:32:43 +0530 Subject: [PATCH] don't leave repo in an intermediate state if autorebase is interrupted --- README.md | 4 ---- src/git.rs | 14 ++++++++++++-- 2 files changed, 12 insertions(+), 6 deletions(-) diff --git a/README.md b/README.md index 7070b41..0b9fb68 100644 --- a/README.md +++ b/README.md @@ -23,10 +23,6 @@ With this graph built up, the tool can: - Log a simple list of all PRs in the stack (+ dependencies) to stdout. - Automatically update the stack + push after making local changes. -Some caveats: - -- The `autorebase` command is not entirely idempotent in cases where it doesn't complete fully. In particular, if all local branches are updated but the final push doesn't go through, you can't run the command again without performing a (manual) reset. This happens because the command relies on remote tracking branches as signposts (this is true at the moment, but it's something of an artifical limitation - there's no reason we can't use a custom signpost of some kind to get around this) to make sure we don't cherry-pick too far. - ## Usage ```bash diff --git a/src/git.rs b/src/git.rs index 53b4d9d..4c55fed 100644 --- a/src/git.rs +++ b/src/git.rs @@ -175,7 +175,9 @@ pub async fn perform_rebase( let base = rev_to_commit(&repo, &remote_ref(remote, pr.base())); let head = rev_to_commit(&repo, pr.head()); + let mut stop_cherry_pick_at = repo.merge_base(base.id(), head.id()).unwrap(); + let mut update_local_branches_to = vec![]; println!("Checking out {:?}", base); checkout_commit(&repo, &base, None); @@ -197,8 +199,10 @@ pub async fn perform_rebase( // TODO: Skip if remote/ is the same SHA as (only until the first cherry-pick) cherry_pick_range(&repo, &mut walk); - // Update local branch so it points to the stack we're building now - repo.branch(pr.head(), &head_commit(&repo), true).unwrap(); + // Record the commit (in the new stack) that the local branch should now point to. + // Actually perform the switch later on in a batch so we don't leave the repo in + // a troubled state if this process is interrupted. + update_local_branches_to.push((pr.head(), head_commit(&repo))); // Use remote branch as boundary for the next cherry-pick let from = rev_to_commit(&repo, &remote_ref(remote, pr.head())); @@ -221,5 +225,11 @@ pub async fn perform_rebase( command.spawn()?.await?; + println!("\nUpdating local branches so they point to the new stack.\n"); + for (branch, target) in update_local_branches_to { + println!(" + Branch {} now points to {}", branch, target.id()); + repo.branch(branch, &target, true).unwrap(); + } + Ok(()) }