summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorKipras Melnikovas <kipras@kipras.org>2024-02-23 06:30:14 +0200
committerKipras Melnikovas <kipras@kipras.org>2024-02-23 07:56:11 +0200
commit1f361115e1c3d0a354209b52f3c973e615b496ea (patch)
tree104a5b2c888701c11ddc9c6cfda7558241f95913
parente063fa885a1e7569b7d22f433be45551d24ea3b3 (diff)
autostage: enable behavior only if enabled via config
-rw-r--r--README.md11
-rw-r--r--src/config.rs13
-rw-r--r--src/lib.rs80
3 files changed, 88 insertions, 16 deletions
diff --git a/README.md b/README.md
index 6a568cd..7bd4a5b 100644
--- a/README.md
+++ b/README.md
@@ -104,6 +104,17 @@ To always have this behavior, set
oneFixupPerCommit = true
```
+### Auto-stage all changes if nothing staged
+
+By default, git-absorb will only consider files that you've staged to the index via `git add`. However, sometimes one wants to try and absorb from all changes, which would require to stage them first via `git add .`. To avoid this extra step, set
+
+```ini
+[absorb]
+ autoStageIfNothingStaged = true
+```
+
+which tells git-absorb, when no changes are staged, to auto-stage them all, create fixup commits where possible, and unstage remaining changes from the index.
+
## TODO
- implement force flag
diff --git a/src/config.rs b/src/config.rs
index 84cd601..bc212f0 100644
--- a/src/config.rs
+++ b/src/config.rs
@@ -4,6 +4,9 @@ pub const MAX_STACK: usize = 10;
pub const ONE_FIXUP_PER_COMMIT_CONFIG_NAME: &str = "absorb.oneFixupPerCommit";
pub const ONE_FIXUP_PER_COMMIT_DEFAULT: bool = false;
+pub const AUTO_STAGE_IF_NOTHING_STAGED_CONFIG_NAME: &str = "absorb.autoStageIfNothingStaged";
+pub const AUTO_STAGE_IF_NOTHING_STAGED_DEFAULT: bool = false;
+
pub fn max_stack(repo: &git2::Repository) -> usize {
match repo
.config()
@@ -23,3 +26,13 @@ pub fn one_fixup_per_commit(repo: &git2::Repository) -> bool {
_ => ONE_FIXUP_PER_COMMIT_DEFAULT,
}
}
+
+pub fn auto_stage_if_nothing_staged(repo: &git2::Repository) -> bool {
+ match repo
+ .config()
+ .and_then(|config| config.get_bool(AUTO_STAGE_IF_NOTHING_STAGED_CONFIG_NAME))
+ {
+ Ok(val) => val,
+ _ => AUTO_STAGE_IF_NOTHING_STAGED_DEFAULT,
+ }
+}
diff --git a/src/lib.rs b/src/lib.rs
index 147da34..be326bc 100644
--- a/src/lib.rs
+++ b/src/lib.rs
@@ -45,8 +45,9 @@ fn run_with_repo(config: &Config, repo: &git2::Repository) -> Result<()> {
return Ok(());
}
+ let autostage_enabled = config::auto_stage_if_nothing_staged(repo);
let mut we_added_everything_to_index = false;
- if nothing_left_in_index(repo)? {
+ if autostage_enabled && nothing_left_in_index(repo)? {
we_added_everything_to_index = true;
// no matter from what subdirectory we're executing,
@@ -333,7 +334,7 @@ fn run_with_repo(config: &Config, repo: &git2::Repository) -> Result<()> {
}
}
- if we_added_everything_to_index {
+ if autostage_enabled && we_added_everything_to_index {
// now that the fixup commits have been created,
// we should unstage the remaining changes from the index.
@@ -601,20 +602,33 @@ lines
assert!(nothing_left_in_index(&ctx.repo).unwrap());
}
- #[test]
- fn autostage_if_index_was_empty() {
- let (ctx, file_path) = prepare_repo();
-
- // 1 modification w/o staging - should get fixup commit created
+ fn autostage_common(ctx: &Context, file_path: &PathBuf) -> (PathBuf, PathBuf) {
+ // 1 modification w/o staging
let path = ctx.join(&file_path);
let contents = std::fs::read_to_string(&path).unwrap();
let modifications = format!("{contents}\nnew_line2");
std::fs::write(&path, &modifications).unwrap();
- // 1 extra file that should get staged & later removed from the index
+ // 1 extra file
let fp2 = PathBuf::from("unrel.txt");
std::fs::write(ctx.join(&fp2), "foo").unwrap();
+ (path, fp2)
+ }
+
+ #[test]
+ fn autostage_if_index_was_empty() {
+ let (ctx, file_path) = prepare_repo();
+
+ // requires enabled config var
+ ctx.repo
+ .config()
+ .unwrap()
+ .set_bool(config::AUTO_STAGE_IF_NOTHING_STAGED_CONFIG_NAME, true)
+ .unwrap();
+
+ autostage_common(&ctx, &file_path);
+
// run 'git-absorb'
let drain = slog::Discard;
let logger = slog::Logger::root(drain, o!());
@@ -640,15 +654,15 @@ lines
fn do_not_autostage_if_index_was_not_empty() {
let (ctx, file_path) = prepare_repo();
- // 1 modification w/o staging - should not get staged nor fixed up
- let path = ctx.join(&file_path);
- let contents = std::fs::read_to_string(&path).unwrap();
- let modifications = format!("{contents}\nnew_line2");
- std::fs::write(&path, &modifications).unwrap();
+ // enable config var
+ ctx.repo
+ .config()
+ .unwrap()
+ .set_bool(config::AUTO_STAGE_IF_NOTHING_STAGED_CONFIG_NAME, true)
+ .unwrap();
- // 1 extra file that we'll stage - should stay in index
- let fp2 = PathBuf::from("unrel.txt");
- std::fs::write(ctx.join(&fp2), "foo").unwrap();
+ let (_, fp2) = autostage_common(&ctx, &file_path);
+ // we stage the extra file - should stay in index
add(&ctx.repo, &fp2);
// run 'git-absorb'
@@ -671,4 +685,38 @@ lines
assert_eq!(index_stats(&ctx.repo).unwrap().files_changed(), 1);
}
+
+ #[test]
+ fn do_not_autostage_if_not_enabled_by_config_var() {
+ let (ctx, file_path) = prepare_repo();
+
+ // disable config var
+ ctx.repo
+ .config()
+ .unwrap()
+ .set_bool(config::AUTO_STAGE_IF_NOTHING_STAGED_CONFIG_NAME, false)
+ .unwrap();
+
+ autostage_common(&ctx, &file_path);
+
+ // run 'git-absorb'
+ let drain = slog::Discard;
+ let logger = slog::Logger::root(drain, o!());
+ let config = Config {
+ dry_run: false,
+ force: false,
+ base: None,
+ and_rebase: false,
+ whole_file: false,
+ one_fixup_per_commit: false,
+ logger: &logger,
+ };
+ run_with_repo(&config, &ctx.repo).unwrap();
+
+ let mut revwalk = ctx.repo.revwalk().unwrap();
+ revwalk.push_head().unwrap();
+ assert_eq!(revwalk.count(), 1);
+
+ assert!(nothing_left_in_index(&ctx.repo).unwrap());
+ }
}