Skip to main content

Pluck any git repo from any forge — auto-detect, auto-install, done!

Project description

pluck
Pluck git repos from any forge — auto-detect, auto-install, done!

Platform: Linux | macOS Python 3.8+ License: MIT Zero dependencies 132 passing tests 11 forges supported PyPI: pluck-cli Code style: ruff GitLab CI


🚀 Quick Start

pluck chasing repos

# Install from any git forge — one command, zero fuss
pluck install https://github.com/user/repo
pluck install https://gitlab.com/user/project
pluck install https://codeberg.org/user/repo
pluck install https://bitbucket.org/owner/repo

# That's it. Pluck detects the project type and installs it.

🔄 How It Works

pluck stalking a repo

┌─────────────────┐     ┌──────────────┐     ┌─────────────────┐     ┌──────────────┐
│  Any git URL    │────▶│  Clone to    │────▶│  Detect Method  │────▶│  Install     │
│  (any forge)    │     │  Temp Dir    │     │  (Auto-detect)  │     │  (8 methods) │
└─────────────────┘     └──────────────┘     └─────────────────┘     └──────────────┘
                                                                         │
┌─────────────────┐     ┌──────────────┐                                │
│   Post-Install  │◀────│  Register    │◀───────────────────────────────┘
│   Hook (opt)    │     │  App         │
└─────────────────┘     └──────────────┘
         │
         ▼
┌─────────────────┐
│  Summary +      │
│  Cleanup        │
└─────────────────┘

Install Methods

Method Detection Action
🔧 Script install.sh Runs bash install.sh --yes
🐍 Python pyproject.toml, setup.py Creates venv, pip installs
🟢 Node.js package.json Copies source, runs npm install
🔵 Go go.mod, *.go Runs go build -o to install dir
🦀 Rust Cargo.toml Runs cargo build --release, copies binary
📋 Makefile Makefile Runs make install PREFIX=...
📦 Binary release/, bin/, *.AppImage, *.deb Copies to install dir
📥 Download Fallback Copies entire directory

✨ Features

Installation

  • 🔗 Any git forge — Install from GitHub, GitLab, Codeberg, Bitbucket, SourceHut, Gitea, Gogs, Pagure, Forgejo, self-hosted, or any git URL
  • 🔍 Auto-detection — Automatically detects project type and install method
  • 📦 Batch install — Install multiple repositories in one command
  • Shallow clone--shallow for faster downloads
  • 🏷️ Branch/tag support--ref to install specific versions
  • 🎯 Force method--method to override auto-detection
  • ⏱️ Timeout & retry--timeout and --retries for flaky connections

Management

  • 📋 List apps — See all installed applications with disk size
  • 🔄 Update apps — Re-install from original URL
  • 🗑️ Uninstall — Remove apps with safety guards
  • Verify — Check installed apps integrity
  • 🧹 Clean — Remove orphaned registry entries
  • 📊 Stats — Installation statistics and method breakdown
  • 🌐 Multi-forge search — Search GitHub, GitLab, or Codeberg with --forge
  • 🖱️ Browser right-click — Optional extension + protocol handler to install from any page
  • 📤 Export/Import — Migrate registry between machines

Configuration

  • 📁 Custom directory--dir to override default install location
  • ⚙️ User config — Persistent settings via config file
  • 🎨 JSON output--json for machine-readable output
  • 🚫 No colors--no-color for clean terminal output
  • 🔇 Non-interactive--yes for scripting
  • 🐳 Docker support — Containerized installation
  • 📖 Man pageman pluck for offline docs
  • 🔧 Post-install hooks — Custom scripts after each install

🌐 Supported Forges

All the forges

Forge Host Built-in Notes
GitHub github.com Full support including gists
GitLab gitlab.com HTTPS & SSH, self-hosted instances auto-detected
Codeberg codeberg.org Powered by Forgejo
Bitbucket bitbucket.org Both cloud & self-hosted
SourceHut git.sr.ht Supports ~user prefix
Gitea gitea.com Any Gitea instance works
Gogs gogs.io Lightweight git service
Pagure pagure.io Fedora's git hosting
Forgejo forgejo.org Self-hosted friendly
Any other hosted git Any domain Parses as generic type
Self-hosted Any IP/domain SSH & HTTPS both supported

Any git hosting platform that follows the standard host/owner/repo URL pattern works — no plugin or config needed.

📖 Commands

Command Description Example
install <url> Install from any git repo URL pluck install https://gitlab.com/user/project
update <name> Update an installed app pluck update myapp
info <name> Show app details pluck info myapp
list List installed apps pluck list
uninstall <name> Uninstall an app pluck uninstall myapp
remove <name> Alias for uninstall pluck remove myapp
verify Check apps validity pluck verify
clean Remove orphaned entries pluck clean --force
stats Show statistics pluck stats
doctor Check tool availability pluck doctor
config [key] [val] View/set config pluck config install_dir ~/Apps
search <query> [--forge <name>] [--all] [--output <file>] Search repos across forges pluck search python installer --all --output results.txt
pin <name> Pin an app to prevent updates pluck pin myapp
unpin <name> Unpin an app pluck unpin myapp
self-update Update pluck itself pluck self-update
cache prune Clear download cache pluck cache prune
export <file> Export registry pluck export ~/backup.json
import <file> Import registry pluck import ~/backup.json
completion <shell> Generate shell completion pluck completion bash
version Show version pluck version
help Show help pluck help

🏷️ Flags

Flag Description
--dir <path> Install to a custom directory
--dry-run Preview without making changes
--force Skip confirmation prompts
--shallow Use shallow clone (--depth 1)
--ref <ref> Clone a specific branch or tag
--method <method> Force install method
--yes Non-interactive mode (alias for --force)
--json Output in JSON format (for scripting)
--no-color Disable colored output
--timeout <secs> Timeout for git clone in seconds
--retries <n> Number of retries for failed git clone
--jobs <n> Number of parallel installs (default: 1)
--release Install from pre-built release assets instead of cloning
--verbose Show detailed git clone output

📥 Installation

From Source

# Clone the repository
git clone https://gitlab.com/mabodu/pluck.git
cd pluck

# Install via pip
pip install -e .

# Or run directly
./src/pluck.py install https://gitlab.com/user/project

Via pip

pip install pluck-cli

Via Docker

docker build -t pluck .
docker run pluck install https://gitlab.com/user/project

⚙️ Configuration

Default Paths

Constant macOS Linux Description
DEFAULT_INSTALL_DIR ~/Applications ~/.local/opt Where apps are installed
APP_REGISTRY_FILE ~/.pluck-registry.json ~/.pluck-registry.json App registry
CONFIG_FILE ~/.config/pluck/config.json ~/.config/pluck/config.json User config

User Config File

{
  "install_dir": "/custom/path",
  "method_priority": ["script", "python", "node", "go", "rust", "make", "binary", "download"]
}

Manage via CLI:

pluck config install_dir ~/Apps
pluck config method_priority '["python","node","binary","download"]'

Post-Install Hooks

Create ~/.config/pluck/hooks/post-install.sh to run custom scripts after each install.

Available environment variables:

  • $PLUCK_APP — Repository name
  • $PLUCK_PATH — Installation path
  • $PLUCK_METHOD — Install method used

🖱️ Browser Integration

pluck stalking repos in your browser

Pluck includes a right-click context menu integration. Install a repo from any forge without leaving your browser.

Quick Setup

# 1. Register the pluck:// protocol handler on your OS
bash scripts/install-protocol-handler.sh

# 2. Load the browser extension (Chrome/Chromium/Brave/Edge)
#    Open chrome://extensions → Developer mode → Load unpacked
#    Select assets/browser-extension/

# 3. Right-click any git repo link → "Install with pluck"

Works with GitHub, GitLab, Codeberg, Bitbucket, SourceHut — any forge.

No Extension? Use the Bookmarklet

If you prefer not to install an extension, create a bookmark with this URL:

javascript:location.href='pluck://install?url='+encodeURIComponent(location.href)

When you're on a git repo page, click the bookmark to install it.

How It Works

The protocol handler is a small shell script (scripts/pluck-protocol-handler.sh) that receives pluck://install?url=... calls from the browser, decodes the URL, and runs pluck install <url>. The browser extension adds the right-click menu item that triggers this protocol call.

📁 Project Structure

pluck/
├── src/
│   ├── pluck.py                # Main application (~2400 lines)
│   └── gh_install.py           # Backward-compat alias (imports pluck)
├── tests/
│   └── test_pluck.py           # Test suite (132 tests)
├── assets/
│   ├── images/                 # Logo and illustrations
│   └── browser-extension/      # Chrome/Chromium right-click extension
├── scripts/
│   ├── pluck-protocol-handler.sh    # pluck:// URL handler
│   └── install-protocol-handler.sh  # Protocol registration
├── docs/
│   └── IMPLEMENTATION.md      # Implementation details
├── man/
│   ├── pluck.1                # Man page
│   └── gh-install.1           # Legacy man page (kept for backward compat)
├── .github/
│   └── workflows/
│       └── release.yml        # Build wheel + binaries, publish to PyPI + GitHub Releases
├── README.md                  # This file
├── CHANGELOG.md               # Version history
├── CONTRIBUTING.md            # Developer guide
├── LICENSE                    # MIT License
├── Dockerfile                 # Container image
├── pyproject.toml             # Package config
├── .pre-commit-config.yaml    # Pre-commit hooks
├── .gitignore                 # Git ignore patterns
└── .dockerignore              # Docker ignore patterns

🛠️ Development

# Install dev dependencies
pip install pytest ruff

# Run tests
python -m pytest tests/ -v

# Run linter
ruff check src/ tests/

# Install pre-commit hooks
pip install pre-commit
pre-commit install

Test Coverage

132 tests passing across 31 test classes:
├── TestParseRepoUrl (22 tests)
├── TestGistUrl (7 tests) — includes GitLab snippets
├── TestDetectInstallMethod (17 tests)
├── TestSharedPaths (2 tests)
├── TestValidMethods (2 tests)
├── TestSanitizeRepoName (4 tests)
├── TestIsExecutable (6 tests)
├── TestGetDiskSize (3 tests)
├── TestParseArgs (10 tests)
├── TestDryRun (1 test)
├── TestRegistryOperations (3 tests)
├── TestUpdateApp (2 tests)
├── TestInfoApp (2 tests)
├── TestDoctor (2 tests)
├── TestConfigCommand (2 tests)
├── TestExportImport (4 tests)
├── TestVerifyApps (3 tests)
├── TestStatsCommand (2 tests)
├── TestFormatBytes (5 tests)
├── TestExtractGlobalFlags (5 tests)
├── TestDownloadAndInstallMocked (4 tests)
├── TestParseArgsMissingFlagValue (6 tests) — regression: flags with missing values
├── TestRegistryAtomicWrite (5 tests) — regression: atomic writes + locking across all registry ops
├── TestInstallPythonSymlink (2 tests) — regression: symlink bug + directory-guard
├── TestSafeTarMembers (2 tests) — regression: CVE-2007-4559 + backslash bypass
├── TestProtocolHandlerUrlParsing (4 tests) — regression: multi-param URL parsing
├── TestReleaseInstallFallback (1 test) — regression: --release fallback to clone
└── TestInstallMakeFallback (1 test) — regression: uncaught CalledProcessError on make failure

📄 License

This project is licensed under the MIT License — see the LICENSE file for details.

🤝 Contributing

Contributions are welcome! Please read the Contributing Guide for details on our code of conduct and the process for submitting pull requests.


Made with ❤️ for non-technical users everywhere

Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

pluck_cli-0.5.0.tar.gz (42.7 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

pluck_cli-0.5.0-py3-none-any.whl (29.0 kB view details)

Uploaded Python 3

File details

Details for the file pluck_cli-0.5.0.tar.gz.

File metadata

  • Download URL: pluck_cli-0.5.0.tar.gz
  • Upload date:
  • Size: 42.7 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/6.1.0 CPython/3.13.13

File hashes

Hashes for pluck_cli-0.5.0.tar.gz
Algorithm Hash digest
SHA256 426888a4f28cdabc63145a7eb80c8fa55d26fc1320cfe10028f418b9b80a8926
MD5 23e97b87aa93ec31e77198639a36a6b9
BLAKE2b-256 f4cb05dbd82591b2d1d1883e1fc261b3c511cc5445ad8d9bdef70db82063bfca

See more details on using hashes here.

Provenance

The following attestation bundles were made for pluck_cli-0.5.0.tar.gz:

Publisher: release.yml on mabo-du/pluck

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

File details

Details for the file pluck_cli-0.5.0-py3-none-any.whl.

File metadata

  • Download URL: pluck_cli-0.5.0-py3-none-any.whl
  • Upload date:
  • Size: 29.0 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/6.1.0 CPython/3.13.13

File hashes

Hashes for pluck_cli-0.5.0-py3-none-any.whl
Algorithm Hash digest
SHA256 0dec3d3e1d31a0311a40cdf3e1cad9f26b75c630be9449d7e609c2d6fda0243f
MD5 9c13b3de1e5564c4b32fc60a5ad496c7
BLAKE2b-256 1ef680366efe5439e1b2d98e5da8182b0c9de65c2a0094d1b5faa75744a0a1c4

See more details on using hashes here.

Provenance

The following attestation bundles were made for pluck_cli-0.5.0-py3-none-any.whl:

Publisher: release.yml on mabo-du/pluck

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page