Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
9 changes: 9 additions & 0 deletions git-branchless-lib/src/core/effects.rs
Original file line number Diff line number Diff line change
Expand Up @@ -567,6 +567,15 @@ impl Effects {
}
}

/// Apply transformations to the returned `Effects` to support emitting
/// graphical output in the opposite of its usual order.
pub fn reverse_order(&self, reverse: bool) -> Self {
Self {
glyphs: self.glyphs.clone().reverse_order(reverse),
..self.clone()
}
}

/// Start reporting progress for the specified operation type.
///
/// A progress spinner is shown until the returned `ProgressHandle` is
Expand Down
9 changes: 9 additions & 0 deletions git-branchless-lib/src/core/formatting.rs
Original file line number Diff line number Diff line change
Expand Up @@ -218,6 +218,15 @@ impl Glyphs {
}
}

/// Return a `Glyphs` object suitable for rendering graphs in the reverse of
/// their usual order.
pub fn reverse_order(mut self, reverse: bool) -> Self {
if reverse {
std::mem::swap(&mut self.split, &mut self.merge);
}
self
}

/// Write the provided string to `out`, using ANSI escape codes as necessary to
/// style it.
///
Expand Down
5 changes: 5 additions & 0 deletions git-branchless-opts/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -279,6 +279,11 @@ pub struct SmartlogArgs {
#[clap(value_parser)]
pub revset: Option<Revset>,

/// Print the smartlog in the opposite of the usual order, with the latest
/// commits first.
#[clap(long)]
pub reverse: bool,

/// Options for resolving revset expressions.
#[clap(flatten)]
pub resolve_revset_options: ResolveRevsetOptions,
Expand Down
31 changes: 22 additions & 9 deletions git-branchless-smartlog/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -749,6 +749,10 @@ mod render {

/// The options to use when resolving the revset.
pub resolve_revset_options: ResolveRevsetOptions,

/// Reverse the ordering of items in the smartlog output, list the most
/// recent commits first.
pub reverse: bool,
}

impl Default for SmartlogOptions {
Expand All @@ -757,6 +761,7 @@ mod render {
event_id: Default::default(),
revset: Revset::default_smartlog_revset(),
resolve_revset_options: Default::default(),
reverse: false,
}
}
}
Expand All @@ -771,9 +776,10 @@ pub fn smartlog(
) -> eyre::Result<ExitCode> {
let SmartlogOptions {
event_id,
revset,
resolve_revset_options,
} = options;
ref revset,
ref resolve_revset_options,
reverse,
} = *options;

let repo = Repo::from_dir(&git_run_info.working_directory)?;
let head_info = repo.get_head_info()?;
Expand All @@ -786,8 +792,8 @@ pub fn smartlog(
None => (repo.get_references_snapshot()?, default_cursor),
Some(event_id) => {
let event_cursor = match event_id.cmp(&0) {
Ordering::Less => event_replayer.advance_cursor(default_cursor, *event_id),
Ordering::Equal | Ordering::Greater => event_replayer.make_cursor(*event_id),
Ordering::Less => event_replayer.advance_cursor(default_cursor, event_id),
Ordering::Equal | Ordering::Greater => event_replayer.make_cursor(event_id),
};
let references_snapshot =
event_replayer.get_references_snapshot(&repo, event_cursor)?;
Expand Down Expand Up @@ -829,8 +835,8 @@ pub fn smartlog(
&commits,
)?;

let lines = render_graph(
effects,
let mut lines = render_graph(
&effects.reverse_order(reverse),
&repo,
&dag,
&graph,
Expand All @@ -851,8 +857,13 @@ pub fn smartlog(
&mut DifferentialRevisionDescriptor::new(&repo, &Redactor::Disabled)?,
&mut CommitMessageDescriptor::new(&Redactor::Disabled)?,
],
)?;
for line in lines {
)?
.into_iter();
while let Some(line) = if reverse {
lines.next_back()
} else {
lines.next()
} {
writeln!(
effects.get_output_stream(),
"{}",
Expand Down Expand Up @@ -912,6 +923,7 @@ pub fn command_main(ctx: CommandContext, args: SmartlogArgs) -> eyre::Result<Exi
event_id,
revset,
resolve_revset_options,
reverse,
} = args;

smartlog(
Expand All @@ -921,6 +933,7 @@ pub fn command_main(ctx: CommandContext, args: SmartlogArgs) -> eyre::Result<Exi
event_id,
revset: revset.unwrap_or_else(Revset::default_smartlog_revset),
resolve_revset_options,
reverse,
},
)
}
70 changes: 70 additions & 0 deletions git-branchless-smartlog/tests/test_smartlog.rs
Original file line number Diff line number Diff line change
Expand Up @@ -178,6 +178,43 @@ fn test_merge_commit() -> eyre::Result<()> {
Ok(())
}

#[test]
fn test_merge_commit_reverse_order() -> eyre::Result<()> {
let git = make_git()?;

git.init_repo()?;
git.run(&["checkout", "-b", "test1", "master"])?;
git.commit_file("test1", 1)?;
git.run(&["checkout", "-b", "test2and3", "master"])?;
git.commit_file("test2", 2)?;
git.commit_file("test3", 3)?;
git.run_with_options(
&["merge", "test1"],
&GitRunOptions {
time: 4,
..Default::default()
},
)?;

let (stdout, _) = git.branchless("smartlog", &["--reverse"])?;
insta::assert_snapshot!(stdout, @r###"
@ fa4e4e1 (> test2and3) Merge branch 'test1' into test2and3
|\
| & (merge) 62fc20d (test1) create test1.txt
|
o 0206717 create test3.txt
|
o fe65c1f create test2.txt
|
| & (merge) fa4e4e1 (> test2and3) Merge branch 'test1' into test2and3
| o 62fc20d (test1) create test1.txt
|/
O f777ecc (master) create initial.txt
"###);

Ok(())
}

#[test]
fn test_rebase_conflict() -> eyre::Result<()> {
let git = make_git()?;
Expand Down Expand Up @@ -462,6 +499,39 @@ fn test_smartlog_hint_abandoned_except_current_commit() -> eyre::Result<()> {
Ok(())
}

/// When --reverse is specified hints still appear at the end of output
#[test]
fn test_smartlog_hint_abandoned_reverse_order() -> eyre::Result<()> {
let git = make_git()?;

if !git.supports_reference_transactions()? {
return Ok(());
}
git.init_repo()?;

git.detach_head()?;
git.commit_file("test1", 1)?;
git.commit_file("test2", 2)?;
git.run(&["checkout", "HEAD^"])?;
git.run(&["commit", "--amend", "-m", "amended test1"])?;

let (stdout, _) = git.branchless("smartlog", &["--reverse"])?;
insta::assert_snapshot!(stdout, @r###"
o 96d1c37 create test2.txt
|
x 62fc20d (rewritten as ae94dc2a) create test1.txt
|
| @ ae94dc2 amended test1
|/
O f777ecc (master) create initial.txt
hint: there is 1 abandoned commit in your commit graph
hint: to fix this, run: git restack
hint: disable this hint by running: git config --global branchless.hint.smartlogFixAbandoned false
"###);

Ok(())
}

#[test]
fn test_smartlog_sparse() -> eyre::Result<()> {
let git = make_git()?;
Expand Down
4 changes: 2 additions & 2 deletions git-branchless/tests/test_init.rs
Original file line number Diff line number Diff line change
Expand Up @@ -316,9 +316,9 @@ fn test_main_branch_not_found_error_message() -> eyre::Result<()> {

0: branchless::core::eventlog::from_event_log_db with effects=<Output fancy=false> repo=<Git repository at: "<repo-path>/.git/"> event_log_db=<EventLogDb>
at some/file/path.rs:123
1: git_branchless_smartlog::smartlog with effects=<Output fancy=false> git_run_info=<GitRunInfo path_to_git="<git-executable>" working_directory="<repo-path>" env=not shown> options=SmartlogOptions { event_id: None, revset: Revset("((draft() | branches() | @) % main()) | branches() | @"), resolve_revset_options: ResolveRevsetOptions { show_hidden_commits: false } }
1: git_branchless_smartlog::smartlog with effects=<Output fancy=false> git_run_info=<GitRunInfo path_to_git="<git-executable>" working_directory="<repo-path>" env=not shown> options=SmartlogOptions { event_id: None, revset: Revset("((draft() | branches() | @) % main()) | branches() | @"), resolve_revset_options: ResolveRevsetOptions { show_hidden_commits: false }, reverse: false }
at some/file/path.rs:123
2: git_branchless_smartlog::command_main with ctx=CommandContext { effects: <Output fancy=false>, git_run_info: <GitRunInfo path_to_git="<git-executable>" working_directory="<repo-path>" env=not shown> } args=SmartlogArgs { event_id: None, revset: None, resolve_revset_options: ResolveRevsetOptions { show_hidden_commits: false } }
2: git_branchless_smartlog::command_main with ctx=CommandContext { effects: <Output fancy=false>, git_run_info: <GitRunInfo path_to_git="<git-executable>" working_directory="<repo-path>" env=not shown> } args=SmartlogArgs { event_id: None, revset: None, reverse: false, resolve_revset_options: ResolveRevsetOptions { show_hidden_commits: false } }
at some/file/path.rs:123

Suggestion:
Expand Down