autostage: enable behavior only if enabled via config

This commit is contained in:
Kipras Melnikovas 2024-02-23 06:30:14 +02:00
parent e063fa885a
commit 1f361115e1
No known key found for this signature in database
GPG key ID: 302DED4F38E4C2C6
3 changed files with 88 additions and 16 deletions

View file

@ -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

View file

@ -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,
}
}

View file

@ -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());
}
}