Skip to content

Commit 35e0dd7

Browse files
committed
Add --no-limit option
disables stack limit, so revwalk reaches first merge commit, or other author, or actual root this is basically --root, but isn't named --root because --no-limit doesn't automatically mean your absorb base is the root commit because you can't absorb through a merge, or other author without the --force-author flag but it means that absorb stack will go as far as possible, allowing linear histories to even reach real root commit should be used carefully in case theres like 100k commits without any merges and from a single author... Closes: #118 Signed-off-by: p1k0chu <[email protected]>
1 parent a1de60b commit 35e0dd7

File tree

4 files changed

+62
-5
lines changed

4 files changed

+62
-5
lines changed

Documentation/git-absorb.adoc

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -51,6 +51,15 @@ FLAGS
5151
--dry-run::
5252
Don't make any actual changes
5353

54+
--no-limit::
55+
Remove absorb stack limit. Has no effect when used with `--base`
56+
+
57+
This will consider all commits until
58+
either root, merge commit, or a commit by other author
59+
(unless `--force-author` is used)
60+
+
61+
Which is why you should be careful when using this flag.
62+
5463
--force-author::
5564
Generate fixups to commits not made by you
5665

@@ -153,6 +162,8 @@ edit your local or global `.gitconfig` and add the following section:
153162
maxStack=50 # Or any other reasonable value for your project
154163
.............................................................................
155164

165+
Stack size can also be disabled temporarily for one command (see `--no-limit`)
166+
156167
ONE FIXUP PER FIXABLE COMMIT
157168
~~~~~~~~~~~~~~~~~~~~~~~~~~~~
158169

src/lib.rs

Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@ use std::path::Path;
1313

1414
pub struct Config<'a> {
1515
pub dry_run: bool,
16+
pub no_limit: bool,
1617
pub force_author: bool,
1718
pub force_detach: bool,
1819
pub base: Option<&'a str>,
@@ -64,6 +65,7 @@ fn run_with_repo(logger: &slog::Logger, config: &Config, repo: &git2::Repository
6465

6566
let (stack, stack_end_reason) = stack::working_stack(
6667
repo,
68+
config.no_limit,
6769
config.base,
6870
config.force_author,
6971
config.force_detach,
@@ -1031,6 +1033,38 @@ lines
10311033
);
10321034
}
10331035

1036+
#[test]
1037+
fn no_stack_limit_exceeds_stack_limit() {
1038+
let (ctx, initial_fp) = repo_utils::prepare_repo();
1039+
let parent_commit = ctx.repo.head().unwrap().peel_to_commit().unwrap();
1040+
repo_utils::empty_commit_chain(&ctx.repo, "HEAD", &[&parent_commit], config::MAX_STACK);
1041+
1042+
repo_utils::stage_file_changes(&ctx, &initial_fp);
1043+
1044+
let config = Config {
1045+
no_limit: true,
1046+
// to have a predictable number of commits for unit test
1047+
one_fixup_per_commit: true,
1048+
..DEFAULT_CONFIG
1049+
};
1050+
1051+
// run 'git-absorb'
1052+
let capturing_logger = log_utils::CapturingLogger::new();
1053+
run_with_repo(&capturing_logger.logger, &config, &ctx.repo).unwrap();
1054+
1055+
let mut revwalk = ctx.repo.revwalk().unwrap();
1056+
revwalk.push_head().unwrap();
1057+
1058+
assert_eq!(
1059+
revwalk.count(),
1060+
// initial + 10 empty + fixup
1061+
config::MAX_STACK + 2,
1062+
"Wrong number of commits."
1063+
);
1064+
1065+
assert!(nothing_left_in_index(&ctx.repo).unwrap());
1066+
}
1067+
10341068
#[test]
10351069
fn reached_root() {
10361070
let (ctx, _) = repo_utils::prepare_repo();
@@ -2073,6 +2107,7 @@ lines
20732107

20742108
const DEFAULT_CONFIG: Config = Config {
20752109
dry_run: false,
2110+
no_limit: false,
20762111
force_author: false,
20772112
force_detach: false,
20782113
base: None,

src/main.rs

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,9 @@ struct Cli {
1919
/// Don't make any actual changes
2020
#[clap(long, short = 'n')]
2121
dry_run: bool,
22+
/// Remove absorb stack limit. Be careful with this
23+
#[clap(long)]
24+
no_limit: bool,
2225
/// Generate fixups to commits not made by you
2326
#[clap(long)]
2427
force_author: bool,
@@ -58,6 +61,7 @@ fn main() {
5861
let Cli {
5962
base,
6063
dry_run,
64+
no_limit,
6165
force_author,
6266
force_detach,
6367
force,
@@ -120,6 +124,7 @@ fn main() {
120124
base: base.as_deref(),
121125
and_rebase,
122126
rebase_options: &rebase_options,
127+
no_limit,
123128
whole_file,
124129
one_fixup_per_commit,
125130
squash,

src/stack.rs

Lines changed: 11 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@ pub enum StackEndReason {
1616

1717
pub fn working_stack<'repo>(
1818
repo: &'repo git2::Repository,
19+
no_limit: bool,
1920
user_provided_base: Option<&str>,
2021
force_author: bool,
2122
force_detach: bool,
@@ -88,7 +89,7 @@ pub fn working_stack<'repo>(
8889
break;
8990
}
9091

91-
if ret.len() == config::max_stack(repo) && user_provided_base.is_none() {
92+
if !no_limit && ret.len() == config::max_stack(repo) && user_provided_base.is_none() {
9293
debug!(logger, "Stopping at stack limit.";
9394
"limit" => ret.len());
9495
stack_end_reason = Some(StackEndReason::ReachedLimit);
@@ -203,7 +204,8 @@ mod tests {
203204
let commits = repo_utils::empty_commit_chain(&repo, "HEAD", &[], 2);
204205
repo.branch("hide", &commits[0], false).unwrap();
205206

206-
let (stack, reason) = working_stack(&repo, None, false, false, &empty_slog()).unwrap();
207+
let (stack, reason) =
208+
working_stack(&repo, false, None, false, false, &empty_slog()).unwrap();
207209
assert_stack_matches_chain(1, &stack, &commits);
208210
assert_eq!(reason, StackEndReason::CommitsHiddenByBranches);
209211
}
@@ -216,6 +218,7 @@ mod tests {
216218

217219
let (stack, reason) = working_stack(
218220
&repo,
221+
false,
219222
Some(&commits[0].id().to_string()),
220223
false,
221224
false,
@@ -238,7 +241,8 @@ mod tests {
238241
)
239242
.unwrap();
240243

241-
let (stack, reason) = working_stack(&repo, None, false, false, &empty_slog()).unwrap();
244+
let (stack, reason) =
245+
working_stack(&repo, false, None, false, false, &empty_slog()).unwrap();
242246
assert_stack_matches_chain(config::MAX_STACK + 1, &stack, &commits);
243247
assert_eq!(reason, StackEndReason::ReachedLimit);
244248
}
@@ -254,7 +258,8 @@ mod tests {
254258
let new_commits =
255259
repo_utils::empty_commit_chain(&repo, "HEAD", &[old_commits.last().unwrap()], 2);
256260

257-
let (stack, reason) = working_stack(&repo, None, false, false, &empty_slog()).unwrap();
261+
let (stack, reason) =
262+
working_stack(&repo, false, None, false, false, &empty_slog()).unwrap();
258263
assert_stack_matches_chain(2, &stack, &new_commits);
259264
assert_eq!(reason, StackEndReason::ReachedAnotherAuthor);
260265
}
@@ -265,7 +270,8 @@ mod tests {
265270
let merge = repo_utils::merge_commit(&repo, &[]);
266271
let commits = repo_utils::empty_commit_chain(&repo, "HEAD", &[&merge], 2);
267272

268-
let (stack, reason) = working_stack(&repo, None, false, false, &empty_slog()).unwrap();
273+
let (stack, reason) =
274+
working_stack(&repo, false, None, false, false, &empty_slog()).unwrap();
269275
assert_stack_matches_chain(2, &stack, &commits);
270276
assert_eq!(reason, StackEndReason::ReachedMergeCommit);
271277
}

0 commit comments

Comments
 (0)