Skip to content

Commit c2042c1

Browse files
committed
edit-config feature
1 parent 53682ef commit c2042c1

File tree

2 files changed

+186
-76
lines changed

2 files changed

+186
-76
lines changed

src/main.rs

Lines changed: 105 additions & 68 deletions
Original file line numberDiff line numberDiff line change
@@ -1,20 +1,28 @@
11
#![allow(dead_code, unused_imports, unused_variables)]
2-
use crate::git::run_git;
3-
use crate::state::State;
4-
use colored::Colorize;
2+
use std::{env, fs::canonicalize};
53

64
use anyhow::{Context, Result, anyhow, bail, ensure};
75
use clap::{Parser, Subcommand};
6+
use colored::Colorize;
87
use git::{
9-
DEFAULT_REMOTE, GitBranchStatus, after_text, git_branch_status, git_checkout_main, git_fetch,
10-
git_get_upstream, git_remote_main, git_sha, is_ancestor, run_git_status, shas_match,
8+
DEFAULT_REMOTE,
9+
GitBranchStatus,
10+
after_text,
11+
git_branch_status,
12+
git_checkout_main,
13+
git_fetch,
14+
git_get_upstream,
15+
git_remote_main,
16+
git_sha,
17+
is_ancestor,
18+
run_git_status,
19+
shas_match,
1120
};
12-
use state::{Branch, RebaseStep};
13-
use std::env;
14-
use std::fs::canonicalize;
21+
use state::{Branch, RestackStep, StackMethod};
1522
use tracing::level_filters::LevelFilter;
16-
use tracing_subscriber::layer::SubscriberExt as _;
17-
use tracing_subscriber::util::SubscriberInitExt; //prelude::*;
23+
use tracing_subscriber::{layer::SubscriberExt as _, util::SubscriberInitExt};
24+
25+
use crate::{git::run_git, state::State}; //prelude::*;
1826

1927
mod git;
2028
mod state;
@@ -42,6 +50,8 @@ enum Command {
4250
#[arg(long, short, default_value_t = false)]
4351
fetch: bool,
4452
},
53+
/// Open the git-stack state file in an editor for manual editing.
54+
EditState,
4555
/// Restack your active branch and all branches in its related stack.
4656
Restack {
4757
/// The name of the branch to restack.
@@ -144,6 +154,7 @@ fn inner_main() -> Result<()> {
144154
Some(Command::Checkout { branch_name }) => {
145155
state.checkout(&repo, current_branch, current_upstream, branch_name)
146156
}
157+
Some(Command::EditState) => state.edit_config(),
147158
Some(Command::Restack {
148159
branch,
149160
fetch,
@@ -261,7 +272,7 @@ fn recur_tree(
261272
}
262273

263274
println!(
264-
"{} ({}) {}{}{}",
275+
"{} ({}) {}{}{}{}",
265276
match (is_current_branch, branch_status.is_descendent) {
266277
(true, true) => branch.name.truecolor(142, 192, 124).bold(),
267278
(true, false) => branch.name.truecolor(215, 153, 33).bold(),
@@ -310,7 +321,11 @@ fn recur_tree(
310321
} else {
311322
String::new()
312323
}
313-
}
324+
},
325+
match branch.stack_method {
326+
StackMethod::ApplyMerge => " (apply-merge)".truecolor(142, 192, 124),
327+
StackMethod::Merge => " (merge)".truecolor(142, 192, 124),
328+
},
314329
);
315330
if let Some(note) = &branch.note {
316331
print!(" ");
@@ -353,7 +368,7 @@ fn status(mut state: State, repo: &str, orig_branch: &str, fetch: bool) -> Resul
353368
}
354369
let trunk = state.ensure_trunk(repo)?;
355370

356-
let Some(tree) = state.get_tree(repo) else {
371+
let Some(tree) = state.get_tree_mut(repo) else {
357372
eprintln!(
358373
"No stack tree found for repo {repo}.",
359374
repo = repo.truecolor(178, 178, 218)
@@ -392,7 +407,7 @@ fn restack(
392407

393408
tracing::debug!(?plan, "Restacking branches with plan...");
394409
git_checkout_main(None)?;
395-
for RebaseStep { parent, branch } in plan {
410+
for RestackStep { parent, branch } in plan {
396411
tracing::debug!(
397412
"Starting branch: {} [pwd={}]",
398413
restack_branch,
@@ -406,74 +421,96 @@ fn restack(
406421
branch.name,
407422
parent
408423
);
409-
tracing::debug!("Force-pushing '{}' to {DEFAULT_REMOTE}...", branch.name);
410424
if push && !shas_match(&format!("{DEFAULT_REMOTE}/{}", branch.name), &branch.name) {
411425
run_git(&[
412426
"push",
413-
"-fu",
427+
match branch.stack_method {
428+
StackMethod::ApplyMerge => {
429+
tracing::debug!(
430+
"Force-pushing '{}' to {DEFAULT_REMOTE}...",
431+
branch.name
432+
);
433+
"-fu"
434+
}
435+
StackMethod::Merge => "-u",
436+
},
414437
DEFAULT_REMOTE,
415438
&format!("{branch_name}:{branch_name}", branch_name = branch.name),
416439
])?;
417440
}
418-
continue;
419441
} else {
420442
tracing::info!("Branch '{}' is not stacked on '{}'...", branch.name, parent);
421443
make_backup(&run_version, branch, &source)?;
422444

423-
if let Some(lkg_parent) = branch.lkg_parent.as_deref() {
424-
tracing::info!("LKG parent: {}", lkg_parent);
425-
if is_ancestor(lkg_parent, &source)? {
426-
let patch_rev = format!("{}..{}", &lkg_parent, &branch.name);
427-
tracing::info!("Creating patch {}", &patch_rev);
428-
// The branch is still on top of the LKG parent. Let's create a format-patch of the
429-
// difference, and apply it on top of the new parent.
430-
let format_patch = run_git(&["format-patch", "--stdout", &patch_rev])?.output();
431-
run_git(&["checkout", "-B", &branch.name, &parent])?;
432-
let Some(format_patch) = format_patch else {
433-
tracing::debug!("No diff between LKG and branch?!");
434-
continue;
435-
};
436-
tracing::info!("Applying patch...");
437-
let rebased = run_git_status(&["am", "--3way"], Some(&format_patch))?.success();
438-
if !rebased {
439-
eprintln!(
440-
"{} did not complete successfully.",
441-
"`git am`".green().bold()
442-
);
443-
eprintln!("Run `git mergetool` to resolve conflicts.");
444-
eprintln!(
445-
"Once you have finished with {}, re-run `git stack restack`.",
446-
"`git am --continue`".green().bold()
447-
);
448-
std::process::exit(1);
445+
match branch.stack_method {
446+
StackMethod::ApplyMerge => {
447+
if let Some(lkg_parent) = branch.lkg_parent.as_deref() {
448+
tracing::info!("LKG parent: {}", lkg_parent);
449+
if is_ancestor(lkg_parent, &source)? {
450+
let patch_rev = format!("{}..{}", &lkg_parent, &branch.name);
451+
tracing::info!("Creating patch {}", &patch_rev);
452+
// The branch is still on top of the LKG parent. Let's create a format-patch of the
453+
// difference, and apply it on top of the new parent.
454+
let format_patch =
455+
run_git(&["format-patch", "--stdout", &patch_rev])?.output();
456+
run_git(&["checkout", "-B", &branch.name, &parent])?;
457+
let Some(format_patch) = format_patch else {
458+
tracing::debug!("No diff between LKG and branch?!");
459+
continue;
460+
};
461+
tracing::info!("Applying patch...");
462+
let rebased =
463+
run_git_status(&["am", "--3way"], Some(&format_patch))?.success();
464+
if !rebased {
465+
eprintln!(
466+
"{} did not complete successfully.",
467+
"`git am`".green().bold()
468+
);
469+
eprintln!("Run `git mergetool` to resolve conflicts.");
470+
eprintln!(
471+
"Once you have finished with {}, re-run `git stack restack`.",
472+
"`git am --continue`".green().bold()
473+
);
474+
std::process::exit(1);
475+
}
476+
if push {
477+
git_push(&branch.name)?;
478+
}
479+
continue;
480+
} else {
481+
tracing::info!(
482+
"Branch '{}' is not on top of the LKG parent. Using `git rebase`...",
483+
branch.name
484+
);
485+
run_git(&["checkout", &branch.name])?;
486+
let rebased = run_git_status(&["rebase", &parent], None)?.success();
487+
488+
if !rebased {
489+
eprintln!(
490+
"{} did not complete automatically.",
491+
"Rebase".blue().bold()
492+
);
493+
eprintln!("Run `git mergetool` to resolve conflicts.");
494+
eprintln!(
495+
"Once you have finished the {}, re-run this script.",
496+
"rebase".blue().bold()
497+
);
498+
std::process::exit(1);
499+
}
500+
if push {
501+
git_push(&branch.name)?;
502+
}
503+
tracing::info!("Rebase completed successfully. Continuing...");
504+
}
449505
}
450-
if push {
451-
git_push(&branch.name)?;
452-
}
453-
continue;
454-
} else {
455-
tracing::info!(
456-
"Branch '{}' is not on top of the LKG parent. Falling through to `git rebase`...",
457-
branch.name
458-
);
506+
}
507+
StackMethod::Merge => {
508+
run_git(&["checkout", &branch.name])
509+
.with_context(|| format!("checking out {}", branch.name))?;
510+
run_git(&["merge", &parent])
511+
.with_context(|| format!("merging {parent} into {}", branch.name))?;
459512
}
460513
}
461-
run_git(&["checkout", &branch.name])?;
462-
let rebased = run_git_status(&["rebase", &parent], None)?.success();
463-
464-
if !rebased {
465-
eprintln!("{} did not complete automatically.", "Rebase".blue().bold());
466-
eprintln!("Run `git mergetool` to resolve conflicts.");
467-
eprintln!(
468-
"Once you have finished the {}, re-run this script.",
469-
"rebase".blue().bold()
470-
);
471-
std::process::exit(1);
472-
}
473-
if push {
474-
git_push(&branch.name)?;
475-
}
476-
tracing::info!("Rebase completed successfully. Continuing...");
477514
}
478515
}
479516
tracing::info!("Restoring starting branch '{}'...", restack_branch);

0 commit comments

Comments
 (0)