Skip to content

Commit a8bcda1

Browse files
authored
Merge pull request #10487 from gitbutlerapp/status-add-verbose-output
Add -v/--verbose flag to status to show author and time
2 parents c14df9c + 789686e commit a8bcda1

File tree

3 files changed

+68
-20
lines changed

3 files changed

+68
-20
lines changed

crates/but/src/args.rs

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -24,11 +24,18 @@ pub enum Subcommands {
2424
/// Determines whether the committed files should be shown as well.
2525
#[clap(short = 'f', alias = "files", default_value_t = false)]
2626
show_files: bool,
27+
/// Show verbose output with commit author and timestamp.
28+
#[clap(short = 'v', long = "verbose", default_value_t = false)]
29+
verbose: bool,
2730
},
2831
/// Overview of the uncommitted changes in the repository with files shown.
2932
/// Equivalent to `but status --files`.
3033
#[clap(hide = true)]
31-
Stf,
34+
Stf {
35+
/// Show verbose output with commit author and timestamp.
36+
#[clap(short = 'v', long = "verbose", default_value_t = false)]
37+
verbose: bool,
38+
},
3239

3340
/// Combines two entities together to perform an operation.
3441
#[clap(

crates/but/src/main.rs

Lines changed: 7 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -134,13 +134,16 @@ async fn main() -> Result<()> {
134134
metrics_if_configured(app_settings, CommandName::Log, props(start, &result)).ok();
135135
Ok(())
136136
}
137-
Subcommands::Status { show_files } => {
138-
let result = status::worktree(&args.current_dir, args.json, *show_files);
137+
Subcommands::Status {
138+
show_files,
139+
verbose,
140+
} => {
141+
let result = status::worktree(&args.current_dir, args.json, *show_files, *verbose);
139142
metrics_if_configured(app_settings, CommandName::Status, props(start, &result)).ok();
140143
Ok(())
141144
}
142-
Subcommands::Stf => {
143-
let result = status::worktree(&args.current_dir, args.json, true);
145+
Subcommands::Stf { verbose } => {
146+
let result = status::worktree(&args.current_dir, args.json, true, *verbose);
144147
metrics_if_configured(app_settings, CommandName::Stf, props(start, &result)).ok();
145148
Ok(())
146149
}

crates/but/src/status/mod.rs

Lines changed: 53 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ use but_core::ui::{TreeChange, TreeStatus};
44
use but_hunk_assignment::HunkAssignment;
55
use but_settings::AppSettings;
66
use but_workspace::ui::StackDetails;
7+
use chrono::{DateTime, TimeZone, Utc};
78
use colored::{ColoredString, Colorize};
89
use gitbutler_command_context::CommandContext;
910
use gitbutler_commit::commit_ext::CommitExt;
@@ -32,7 +33,12 @@ struct WorktreeStatus {
3233
common_merge_base: CommonMergeBase,
3334
}
3435

35-
pub(crate) fn worktree(repo_path: &Path, json: bool, show_files: bool) -> anyhow::Result<()> {
36+
pub(crate) fn worktree(
37+
repo_path: &Path,
38+
json: bool,
39+
show_files: bool,
40+
verbose: bool,
41+
) -> anyhow::Result<()> {
3642
let project = Project::find_by_path(repo_path).expect("Failed to create project from path");
3743
let ctx = &mut CommandContext::open(&project, AppSettings::load_from_default_path_creating()?)?;
3844
but_rules::process_rules(ctx).ok(); // TODO: this is doing double work (dependencies can be reused)
@@ -108,6 +114,7 @@ pub(crate) fn worktree(repo_path: &Path, json: bool, show_files: bool) -> anyhow
108114
assignments,
109115
&worktree_changes.worktree_changes.changes,
110116
show_files,
117+
verbose,
111118
&mut stack_mark,
112119
ctx,
113120
)?;
@@ -161,12 +168,14 @@ fn print_assignments(assignments: &Vec<FileAssignment>, changes: &[TreeChange])
161168
}
162169
}
163170

171+
#[expect(clippy::too_many_arguments)]
164172
pub fn print_group(
165173
project: &Project,
166174
group: Option<StackDetails>,
167175
assignments: Vec<FileAssignment>,
168176
changes: &[TreeChange],
169177
show_files: bool,
178+
verbose: bool,
170179
stack_mark: &mut Option<ColoredString>,
171180
ctx: &mut CommandContext,
172181
) -> anyhow::Result<()> {
@@ -206,20 +215,49 @@ pub fn print_group(
206215
} else {
207216
"".normal()
208217
};
209-
println!(
210-
"● {}{} {} {} {}",
211-
&commit.id.to_string()[..2].blue().underline(),
212-
&commit.id.to_string()[2..7].blue(),
213-
conflicted_str,
214-
commit
215-
.message
216-
.to_string()
217-
.replace('\n', " ")
218-
.chars()
219-
.take(50)
220-
.collect::<String>(),
221-
mark.unwrap_or_default()
222-
);
218+
219+
if verbose {
220+
// Verbose format: author and timestamp on first line, message on second line
221+
let datetime = DateTime::from_timestamp_millis(commit.created_at as i64)
222+
.unwrap_or_else(|| Utc.timestamp_millis_opt(0).unwrap());
223+
let formatted_time = datetime.format("%Y-%m-%d %H:%M:%S");
224+
225+
println!(
226+
"● {}{} {} {} {} {}",
227+
&commit.id.to_string()[..2].blue().underline(),
228+
&commit.id.to_string()[2..7].blue(),
229+
conflicted_str,
230+
commit.author.name.dimmed(),
231+
formatted_time.to_string().dimmed(),
232+
mark.unwrap_or_default()
233+
);
234+
println!(
235+
"│ {}",
236+
commit
237+
.message
238+
.to_string()
239+
.replace('\n', " ")
240+
.chars()
241+
.take(100)
242+
.collect::<String>()
243+
);
244+
} else {
245+
// Original format: everything on one line
246+
println!(
247+
"● {}{} {} {} {}",
248+
&commit.id.to_string()[..2].blue().underline(),
249+
&commit.id.to_string()[2..7].blue(),
250+
conflicted_str,
251+
commit
252+
.message
253+
.to_string()
254+
.replace('\n', " ")
255+
.chars()
256+
.take(50)
257+
.collect::<String>(),
258+
mark.unwrap_or_default()
259+
);
260+
}
223261
if show_files {
224262
let commit_details =
225263
but_api::diff::commit_details(project.id, commit.id.into())?;

0 commit comments

Comments
 (0)