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
437 changes: 40 additions & 397 deletions Cargo.lock

Large diffs are not rendered by default.

6 changes: 2 additions & 4 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -16,11 +16,9 @@ anyhow = "1"
clap = { version = "4.5", features = ["derive"] }
clap_complete = "4.5"
comfy-table = "7.2.1"
crossterm = "0.29"
git2 = { version = "0.20", default-features = false, features = ["https", "ssh", "vendored-openssl"] }
log = "0.4.29"
parking_lot = "0.12.5"
ratatui = "0.29"
rayon = "1.11.0"
serde = { version = "1.0", features = ["derive"]}
serde_json = "1.0"
Expand All @@ -30,8 +28,8 @@ strum_macros = "0.27"
walkdir = "2.5"

[dev-dependencies]
insta = { version = "1.44", features = ["json"] }
tempfile = "3.23"
insta = { version = "1.45", features = ["json"] }
tempfile = "3.24"


[lints.rust]
Expand Down
1 change: 0 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -61,7 +61,6 @@ Options:
--completions <SHELL> Generate shell completions [possible values: bash, elvish, fish, powershell, zsh]
-p, --path Show the path to the repository
-n, --non-clean Only show non clean repositories
-i, --interactive Enable interactive mode to select and interact with repositories
-h, --help Print help
-V, --version Print version
```
Expand Down
13 changes: 8 additions & 5 deletions src/cli.rs
Original file line number Diff line number Diff line change
Expand Up @@ -58,9 +58,6 @@ pub struct Args {
/// Only show non clean repositories
#[arg(short = 'n', long)]
pub non_clean: bool,
/// Enable interactive mode to select and interact with repositories
#[arg(short, long)]
pub interactive: bool,
/// Output in JSON format
#[arg(long)]
pub json: bool,
Expand Down Expand Up @@ -97,13 +94,19 @@ impl Args {

walker.par_iter().for_each(|entry| {
let orig_path = entry.path();

// Skip internal .git/worktrees directories - these are metadata, not actual repos
if orig_path.to_string_lossy().contains("/.git/worktrees/") {
return;
}

let repo_name = orig_path.dir_name();
let path_buf = {
if orig_path.is_git_directory() {
if orig_path.is_git_directory() || orig_path.is_git_worktree() {
orig_path.to_path_buf()
} else if let Some(subdir) = &self.subdir {
let subdir_path = orig_path.join(subdir);
if subdir_path.is_git_directory() {
if subdir_path.is_git_directory() || subdir_path.is_git_worktree() {
subdir_path
} else {
// If the subdir does not exist, skip this directory
Expand Down
7 changes: 7 additions & 0 deletions src/gitinfo/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -30,11 +30,18 @@ fn get_remote_name(repo: &Repository) -> Option<String> {

/// Gets the path of the repository.
/// If the path ends with `.git`, it returns the parent directory.
/// For worktrees, returns the worktree's working directory path.
/// # Arguments
/// * `repo` - The Git repository to check for the path.
/// # Returns
/// A `PathBuf` containing the repository path.
fn get_repo_path(repo: &Repository) -> path::PathBuf {
// For worktrees, workdir() returns the actual working directory
if let Some(workdir) = repo.workdir() {
return workdir.to_path_buf();
}

// Fallback for bare repos or edge cases
let path = repo.path();
if path.ends_with(".git") {
path.parent().unwrap_or(path).to_path_buf()
Expand Down
8 changes: 8 additions & 0 deletions src/gitinfo/repoinfo.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,10 @@ use git2::Repository;
use crate::gitinfo::{self, status::Status};

/// Holds information about a Git repository for status display.
#[expect(
clippy::struct_excessive_bools,
reason = "This structure holds repository state flags that are naturally represented as booleans"
)]
#[derive(serde::Serialize, serde::Deserialize, Clone)]
pub struct RepoInfo {
/// The directory name of the repository.
Expand Down Expand Up @@ -33,6 +37,8 @@ pub struct RepoInfo {
pub fast_forwarded: bool,
/// relative path from the starting directory
pub repo_path: String,
/// True if this is a Git worktree
pub is_worktree: bool,
}

impl RepoInfo {
Expand Down Expand Up @@ -91,6 +97,7 @@ impl RepoInfo {
} else {
false
};
let is_worktree = repo.is_worktree();

Ok(Self {
name,
Expand All @@ -106,6 +113,7 @@ impl RepoInfo {
is_local_only,
fast_forwarded,
repo_path: repo_path_relative.display().to_string(),
is_worktree,
})
}

Expand Down
23 changes: 0 additions & 23 deletions src/gitinfo/status.rs
Original file line number Diff line number Diff line change
Expand Up @@ -120,29 +120,6 @@ impl Status {
}
}

pub const fn ratatui_color(&self) -> ratatui::style::Color {
use ratatui::style::Color;
match self {
Self::Clean => Color::Reset,
Self::Dirty(_) | Self::Unpushed | Self::Unpublished => Color::Red,
Self::Merge => Color::Blue,
Self::Revert => Color::Magenta,
Self::Rebase => Color::Cyan,
Self::Bisect => Color::LightYellow,
Self::CherryPick => Color::Yellow,
Self::Detached =>
// Purple color for detached HEAD state
{
Color::Rgb(255, 0, 255)
}
Self::Unknown =>
// Orange color for unknown status
{
Color::Rgb(255, 165, 0)
}
}
}

/// Converts the status to a `Cell` for use in a table.
/// This allows the status to be displayed with its associated color and attributes.
pub fn as_cell(&self) -> Cell {
Expand Down
38 changes: 0 additions & 38 deletions src/interactive/helpers.rs

This file was deleted.

Loading