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
2 changes: 1 addition & 1 deletion Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ version = "0.2.0"
edition = "2021"
description = "Standalone CLI for configuring git repos — hooks, .gitignore, and .gitattributes"
license = "MIT"
repository = "https://github.com/JheisonMB/gitkit"
repository = "https://github.com/UniverLab/gitkit"
keywords = ["git", "hooks", "cli", "gitignore", "gitattributes"]
categories = ["command-line-utilities", "development-tools"]

Expand Down
59 changes: 52 additions & 7 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -12,8 +12,8 @@
░░░░░░
```

[![CI](https://github.com/JheisonMB/gitkit/actions/workflows/ci.yml/badge.svg)](https://github.com/JheisonMB/gitkit/actions/workflows/ci.yml)
[![Release](https://github.com/JheisonMB/gitkit/actions/workflows/release.yml/badge.svg)](https://github.com/JheisonMB/gitkit/actions/workflows/release.yml)
[![CI](https://github.com/UniverLab/gitkit/actions/workflows/ci.yml/badge.svg)](https://github.com/UniverLab/gitkit/actions/workflows/ci.yml)
[![Release](https://github.com/UniverLab/gitkit/actions/workflows/release.yml/badge.svg)](https://github.com/UniverLab/gitkit/actions/workflows/release.yml)
[![Crates.io](https://img.shields.io/crates/v/gitkit)](https://crates.io/crates/gitkit)
[![License: MIT](https://img.shields.io/badge/license-MIT-blue.svg)](LICENSE)

Expand All @@ -28,13 +28,13 @@ Configure a git repo in seconds — hooks, `.gitignore`, `.gitattributes`, and g
**Linux / macOS:**

```bash
curl -fsSL https://raw.githubusercontent.com/JheisonMB/gitkit/main/install.sh | sh
curl -fsSL https://raw.githubusercontent.com/UniverLab/gitkit/main/scripts/install.sh | sh
```

**Windows (PowerShell):**

```powershell
irm https://raw.githubusercontent.com/JheisonMB/gitkit/main/install.ps1 | iex
irm https://raw.githubusercontent.com/UniverLab/gitkit/main/scripts/install.ps1 | iex
```

### Via cargo
Expand All @@ -47,7 +47,7 @@ Available on [crates.io](https://crates.io/crates/gitkit).

### GitHub Releases

Check the [Releases](https://github.com/JheisonMB/gitkit/releases) page for precompiled binaries (Linux x86_64, macOS x86_64/ARM64, Windows x86_64).
Check the [Releases](https://github.com/UniverLab/gitkit/releases) page for precompiled binaries (Linux x86_64, macOS x86_64/ARM64, Windows x86_64).

### Uninstall

Expand All @@ -65,7 +65,13 @@ Remove-Item "$env:LOCALAPPDATA\gitkit\gitkit.exe" -Force

## Quick Start

Interactive wizard — guided setup for a new repo:
**Clone and configure a repo in one command:**

```bash
gitkit clone https://github.com/user/repo
```

Or configure an existing repo:

```bash
gitkit init
Expand All @@ -91,12 +97,51 @@ Interactive wizard that guides you through configuring a repo step by step.
- `.gitattributes` — line endings and binary file presets
- Git config — 6 individual options, recommended ones pre-selected

```
Automatically initializes a git repository if one doesn't exist:

```bash
gitkit init
```

---

## `gitkit clone`

Clone a repository and automatically run `gitkit init` to configure it.

**Usage:**

```bash
gitkit clone [OPTIONS] <REPOSITORY> [DIRECTORY]
```

**Arguments:**

- `<REPOSITORY>` — Repository URL or path to clone
- `[DIRECTORY]` — Target directory (defaults to repository name)

**Options:**

- `-b, --branch <BRANCH>` — Clone specific branch (defaults to repository default)
- `-h, --help` — Print help

**Examples:**

```bash
# Clone and auto-configure
gitkit clone https://github.com/user/repo

# Clone specific branch
gitkit clone -b develop https://github.com/user/repo

# Clone to custom directory
gitkit clone https://github.com/user/repo my-project
```

The wizard runs automatically after cloning, allowing you to configure hooks, `.gitignore`, `.gitattributes`, and git config in one workflow.

---

## Commands

### Hooks
Expand Down
6 changes: 3 additions & 3 deletions install.ps1 → scripts/install.ps1
Original file line number Diff line number Diff line change
@@ -1,13 +1,13 @@
# install.ps1 — download and install gitkit on Windows
# Usage: irm https://raw.githubusercontent.com/JheisonMB/gitkit/main/install.ps1 | iex
# Usage: irm https://raw.githubusercontent.com/UniverLab/gitkit/main/scripts/install.ps1 | iex
#
# Options (set as env vars before running):
# $env:VERSION = "0.1.0" # pin a specific version
# $env:INSTALL_DIR = "C:\my\bin" # custom install directory

$ErrorActionPreference = "Stop"

$Repo = "JheisonMB/gitkit"
$Repo = "UniverLab/gitkit"
$Binary = "gitkit.exe"
$Target = "x86_64-pc-windows-msvc"
$InstallDir = if ($env:INSTALL_DIR) { $env:INSTALL_DIR } else { "$env:USERPROFILE\.local\bin" }
Expand Down Expand Up @@ -72,4 +72,4 @@ Remove-Item $Tmp -Recurse -Force
$ver = & "$InstallDir\$Binary" --version 2>$null
Info "done" $ver
Write-Host ""
Info "ready" "Run 'gitkit hooks init commit-msg conventional-commits' to get started!"
Info "ready" "Run 'gitkit init' to get started!"
6 changes: 3 additions & 3 deletions install.sh → scripts/install.sh
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
#!/bin/sh
# install.sh — download and install gitkit from GitHub Releases
# Usage: curl -fsSL https://raw.githubusercontent.com/JheisonMB/gitkit/main/install.sh | sh
# Usage: curl -fsSL https://raw.githubusercontent.com/UniverLab/gitkit/main/scripts/install.sh | sh
set -eu

REPO="JheisonMB/gitkit"
REPO="UniverLab/gitkit"
BINARY="gitkit"
INSTALL_DIR="${INSTALL_DIR:-$HOME/.local/bin}"

Expand Down Expand Up @@ -79,4 +79,4 @@ esac
# --- verify ---
info "done" "$($INSTALL_DIR/$BINARY --version 2>/dev/null || echo "$BINARY installed")"
echo ""
info "ready" "Run 'gitkit hooks init commit-msg conventional-commits' to get started!"
info "ready" "Run 'gitkit init' to get started!"
70 changes: 70 additions & 0 deletions src/clone.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,70 @@
use anyhow::Result;
use clap::Parser;
use std::process::Command;

#[derive(Parser)]
pub struct CloneArgs {
/// Repository URL or path to clone
repository: String,

/// Directory to clone into (defaults to repository name)
directory: Option<String>,

/// Clone specific branch
#[arg(short, long)]
branch: Option<String>,
}

pub fn run(args: CloneArgs) -> Result<()> {
let repository = &args.repository;
let directory = &args.directory;
let branch = &args.branch;

println!();
println!(" ◇ cloning repository...");

let mut cmd = Command::new("git");
cmd.arg("clone");

if let Some(b) = branch {
cmd.arg("--branch").arg(b);
}

cmd.arg(repository);
if let Some(d) = directory {
cmd.arg(d);
}

let status = cmd
.output()
.map_err(|e| anyhow::anyhow!("Failed to run 'git clone': {}", e))?
.status;

if !status.success() {
anyhow::bail!("git clone failed");
}

println!(" ◇ clone completed ✓");

let target_dir = if let Some(d) = directory {
d.to_string()
} else {
repository
.split('/')
.next_back()
.unwrap_or(repository)
.trim_end_matches(".git")
.to_string()
};

std::env::set_current_dir(&target_dir)
.map_err(|e| anyhow::anyhow!("Failed to enter directory '{}': {}", target_dir, e))?;

println!();
println!(" ◇ running gitkit init...");
println!();

crate::init::run()?;

Ok(())
}
35 changes: 35 additions & 0 deletions src/git.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
use anyhow::Result;
use std::path::Path;
use std::process::Command;

/// Check if directory is a valid git repository.
pub fn is_git_repo() -> bool {
Command::new("git")
.args(["rev-parse", "--is-inside-work-tree"])
.output()
.map(|o| o.status.success())
.unwrap_or(false)
}

/// Check if .git directory exists.
fn git_dir_exists() -> bool {
Path::new(".git").exists()
}

/// Initialize git repository if not already a git repo.
pub fn init_if_needed() -> Result<bool> {
if git_dir_exists() {
return Ok(false);
}

Command::new("git")
.arg("init")
.output()
.map_err(|e| anyhow::anyhow!("Failed to run 'git init': {}", e))?;

if !is_git_repo() {
anyhow::bail!("git init succeeded but .git not found");
}

Ok(true)
}
8 changes: 7 additions & 1 deletion src/init.rs
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
use anyhow::Result;
use inquire::{MultiSelect, Text};

use crate::{attributes, config, hooks, ignore};
use crate::{attributes, config, git, hooks, ignore};

const BANNER: &str = r#"
███ █████ █████ ███ █████
Expand All @@ -18,6 +18,12 @@ const BANNER: &str = r#"
"#;

pub fn run() -> Result<()> {
// Initialize git repository if not already one
let git_initialized = git::init_if_needed()?;
if git_initialized {
println!(" ◇ git repository initialized ✓");
}

println!("{BANNER}");
println!(" Configure your git repo\n");

Expand Down
5 changes: 5 additions & 0 deletions src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,9 @@ use anyhow::Result;
use clap::{Parser, Subcommand};

mod attributes;
mod clone;
mod config;
mod git;
mod hooks;
mod ignore;
mod init;
Expand All @@ -23,6 +25,8 @@ struct Cli {
enum Command {
/// Interactive wizard to configure your repo
Init,
/// Clone repository and run init wizard
Clone(clone::CloneArgs),
/// Manage git hooks
Hooks {
#[command(subcommand)]
Expand All @@ -49,6 +53,7 @@ fn main() -> Result<()> {
let cli = Cli::parse();
match cli.command {
Command::Init => init::run(),
Command::Clone(args) => clone::run(args),
Command::Hooks { action } => hooks::run(action),
Command::Ignore { action } => ignore::run(action),
Command::Attributes { action } => attributes::run(action),
Expand Down
Loading