gittyup


Namegittyup JSON
Version 1.1.0 PyPI version JSON
download
home_pageNone
SummaryAutomatically discover and update all git repositories in a directory tree
upload_time2025-10-25 17:30:11
maintainerNone
docs_urlNone
authorMichael Kennedy
requires_python>=3.13
licenseMIT
keywords automation cli git repository update
VCS
bugtrack_url
requirements click colorama diskcache platformdirs
Travis-CI No Travis.
coveralls test coverage No coveralls.
            <div align="center">

# 🐴 Gitty Up!

### *Never forget to pull again*

**Automatically discover and update all your Git repositories with one command**

[![Python Version](https://img.shields.io/badge/python-3.13%2B-blue.svg)](https://www.python.org/downloads/)
[![PyPI Version](https://img.shields.io/pypi/v/gittyup.svg)](https://pypi.org/project/gittyup/)
[![PyPI Downloads](https://img.shields.io/pypi/dm/gittyup.svg)](https://pypi.org/project/gittyup/)
[![Test Coverage](https://img.shields.io/badge/coverage-91.93%25-brightgreen.svg)](https://github.com)
[![Tests](https://img.shields.io/badge/tests-216%20passing-brightgreen.svg)](https://github.com)
[![Code Style](https://img.shields.io/badge/code%20style-ruff-black.svg)](https://github.com/astral-sh/ruff)
[![License](https://img.shields.io/badge/license-MIT-blue.svg)](LICENSE)

[Features](#-features) β€’ [Installation](#-installation) β€’ [Quick Start](#-quick-start) β€’ [Documentation](#-documentation) β€’ [FAQ](#-faq)

</div>

---

## 🎯 The Problem

You're about to start coding. You open your project, dive into the code, make changes... then realize you forgot to `git pull`. Now you're dealing with merge conflicts, rebasing headaches, and lost time. Sound familiar?

When you're juggling multiple projects, working across different machines, or collaborating with a team, keeping every repository up-to-date becomes a mental burden. One forgotten `git pull` can derail your entire workflow.

## ✨ The Solution

**Gitty Up** is your automated Git guardian. Point it at your projects directory, and it intelligently scans every repository, pulling the latest changes while keeping your work safe. It documents everything it does, so you always know exactly what changed. No more forgotten pulls. No more merge conflict surprises. No more wondering what happened. Just smooth, up-to-date repositories ready for actionβ€”with complete accountability.

Think of it as your morning coffee routine for your codebaseβ€”one command, and everything's fresh, safe, and fully documented.

---

## πŸš€ Features

<table>
<tr>
<td width="50%">

### πŸ›‘οΈ **Safety First**
Smart checks prevent data loss. Skips repos with uncommitted changes, detached HEADs, or missing upstreams. Your local work is always protected.

### πŸ” **Complete Transparency**
Your Git guardian keeps detailed records. Every operation is automatically logged with commit details, file changes, and timing data. Use `--explain` to review exactly what happenedβ€”perfect for debugging, auditing, or understanding what changed.

### 🎨 **Visual Clarity**  
Beautiful, color-coded output with intuitive symbols. Green for success, red for errorsβ€”know exactly what's happening at a glance.

### πŸ”Ž **Intelligent Discovery**
Recursively finds every Git repository in your directory tree, no matter how deeply nested.

</td>
<td width="50%">

### ⚑ **Lightning Fast**
Concurrent batch processing updates multiple repositories simultaneously. Configurable batch sizes optimize performance for your workflow. Auto-excludes common junk directories.

### 🎯 **Flexible Control**
Dry-run mode, depth limits, custom exclusions, verbosity levelsβ€”you're in complete control of every operation.

### βœ… **Battle-Tested**
91.93% test coverage with 216 comprehensive tests. Production-ready and reliable with every release.

</td>
</tr>
</table>

---

## πŸ“¦ Installation

### Prerequisites

- **Python 3.13+** installed on your system
- **Git** available in your PATH
- **uv** package manager (recommended) or pip

### Method 1: Install from PyPI (Recommended) ⭐

Install directly from PyPI as a global CLI toolβ€”no virtual environment needed!

```bash
# Install as a global tool with uv
uv tool install gittyup

# That's it! Use from anywhere without activating venv
gittyup --version
```

**Benefits:** βœ… No venv activation β€’ βœ… Available system-wide β€’ βœ… Isolated environment β€’ βœ… Easy updates


### Method 2: Install from Source

For development or contributing to the project:

```bash
# Clone and navigate to the project
git clone https://github.com/mikeckennedy/gittyup
cd gittyup

# Install in editable mode with uv
uv tool install --editable .
```

---

## ⚑ Quick Start

### Basic Commands

```bash
# Update all repos in current directory
gittyup

# Update repos in a specific location
gittyup ~/dev/projects

# Preview what would happen (dry run)
gittyup --dry-run

# Get detailed output
gittyup --verbose
```

### Common Workflows

**The Monday Morning Refresh** πŸŒ…
```bash
gittyup ~/projects
```
Start your week with every project up-to-date.

**The Quick Check** πŸ‘€
```bash
gittyup --dry-run --verbose
```
See what's outdated without touching anything.

**The Deep Dive** πŸ”Ž
```bash
gittyup ~/dev --max-depth 3 --exclude archive --verbose
```
Scan thoroughly but skip archived projects.

**The Accountability Check** πŸ”
```bash
gittyup --explain
```
Review your guardian's detailed report: see exactly what commits were pulled, which files changed, and why any repos were skipped. Perfect for Monday morning catch-up or debugging unexpected changes.

**The Performance Mode** ⚑
```bash
gittyup ~/projects --batch-size 5
```
Update multiple repositories concurrently for maximum speed. Adjust batch size based on your system resources and network connection. Careful you don't over do it and get rate limited at GitHub.

**The Safe and Sequential** 🎯
```bash
gittyup --sync --verbose
```
Process repositories one at a time for careful monitoring or when debugging issues. Perfect for troubleshooting or conservative workflows.

---

## πŸ“– Documentation

### Command Reference

```bash
gittyup [DIRECTORY] [OPTIONS]
```

| Argument/Option | Description | Default |
|----------------|-------------|---------|
| `DIRECTORY` | Path to scan for repositories | Current directory |
| `-n, --dry-run` | Preview changes without updating | Disabled |
| `-b, --batch-size N` | Number of repos to update concurrently | 3 |
| `-s, --sync` | Force sequential updates (batch size = 1) | Concurrent |
| `-d, --max-depth N` | Maximum directory depth to scan | Unlimited |
| `-e, --exclude PATTERN` | Skip directories matching pattern | None |
| `-v, --verbose` | Show all repos, including up-to-date | Normal |
| `-q, --quiet` | Only show errors | Normal |
| `--explain` | Show detailed history of last run | Disabled |
| `--version` | Display version information | - |
| `--help` | Show help message | - |

### Output Guide

Gitty Up uses clear visual indicators to communicate status:

<table>
<tr>
<td><strong>βœ“</strong> Green</td>
<td>Repository is up-to-date or successfully updated</td>
</tr>
<tr>
<td><strong>↓</strong> Cyan</td>
<td>Repository pulled new commits</td>
</tr>
<tr>
<td><strong>βŠ™</strong> Yellow</td>
<td>Repository skipped (safety check failed)</td>
</tr>
<tr>
<td><strong>βœ—</strong> Red</td>
<td>Error occurred during update</td>
</tr>
<tr>
<td><strong>β†’</strong> White</td>
<td>Processing repository</td>
</tr>
</table>

### Example Output

```
╔════════════════════════════════════════════════════════════════════════════╗
β•‘                              Gitty Up                                       β•‘
β•šβ•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•

βœ“ Scanning directory: /Users/dev/projects
βœ“ Found 9 git repositories

Updating: project-alpha, project-beta, project-gamma
βœ“ project-alpha - Already up-to-date
↓ project-beta - Pulled 3 commits
βŠ™ project-gamma - Uncommitted changes

Updating: project-delta, project-epsilon, project-zeta
βœ“ project-delta - Already up-to-date
βœ— project-epsilon - Network timeout
↓ project-zeta - Pulled 1 commit

Updating: project-omega, project-sigma, project-theta
βœ“ project-omega - Already up-to-date
βœ“ project-sigma - Already up-to-date
βœ“ project-theta - Already up-to-date

════════════════════════════════════════════════════════════════════════════
Summary
════════════════════════════════════════════════════════════════════════════
Total repositories found: 9
  βœ“ Up to date: 5
  ↓ Updated: 2
  βŠ™ Skipped: 1
  βœ— Errors: 1

Completed in 4.23 seconds
════════════════════════════════════════════════════════════════════════════
```

**Note:** The example shows default batch processing (3 repos at a time). Use `--sync` for sequential updates with individual progress indicators.

### Using --explain to Review History

Your Git guardian keeps detailed records of every operation. Need to know what changed? Just ask:

```bash
$ cd ~/projects
$ gittyup --explain
```

```
═══════════════════════════════════════════════════════════════════════════
                    Gitty Up - Operation History
═══════════════════════════════════════════════════════════════════════════

═══════════════════════════════════════════════════════════════════════════
Operation Details
═══════════════════════════════════════════════════════════════════════════
  πŸ“… Run Date: 2025-10-15 14:23:45
  πŸ“‚ Directory: /Users/dev/projects
  ⏱️  Duration: 2.34 seconds
  πŸ”§ Gittyup Version: 1.0.0
  πŸ™ Git Version: 2.39.0

═══════════════════════════════════════════════════════════════════════════
Summary
═══════════════════════════════════════════════════════════════════════════
  Total repositories: 5
  βœ… Updated: 1
  πŸ’€ Already up-to-date: 3
  ⏭️  Skipped: 1
  ❌ Errors: 0

═══════════════════════════════════════════════════════════════════════════
Repository Details
═══════════════════════════════════════════════════════════════════════════

βœ… project-alpha
   Path: /Users/dev/projects/project-alpha
   Duration: 487ms
   Branch: main
   Changes pulled successfully
   Commits: 3
   Files changed: 5
   Insertions: +127
   Deletions: -43

   πŸ“ Commits:
      a7f2c3d - Add new feature for user authentication
         John Doe β€’ 2025-10-15T10:23:00
      b8e1d4f - Fix bug in login validation
         Jane Smith β€’ 2025-10-15T09:15:00
      c9f2e5g - Update dependencies to latest versions
         John Doe β€’ 2025-10-14T16:45:00

   πŸ“ Files:
      ~ src/auth.py
         (+45/-12)
      + src/validators.py
         (+32/-0)
      ~ tests/test_auth.py
         (+28/-8)

πŸ’€ project-beta
   Path: /Users/dev/projects/project-beta
   Duration: 123ms
   Branch: develop
   Already up-to-date

⏭️  project-gamma
   Path: /Users/dev/projects/project-gamma
   Duration: 89ms
   Branch: main
   Skipped
   Reason: Repository has uncommitted changes
   Details: Pull would conflict with local modifications

═══════════════════════════════════════════════════════════════════════════
```

**What --explain shows:**
- **Complete operation metadata**: When it ran, how long it took, tool versions
- **Summary statistics**: Overall results across all repositories  
- **Detailed repository information**:
  - Every commit that was pulled (who wrote it, when, what changed)
  - Exactly which files changed with insertion/deletion counts
  - Why any repos were skipped with specific reasons
  - Full error details for debugging failed operations
  - Branch information and precise timing data

**Perfect for:**
- Debugging issues or understanding unexpected changes
- Auditing what happened during automated runs
- Reviewing what you missed while away from your desk
- Team accountability and change tracking

**Where logs are stored:**
Your guardian keeps records in OS-specific cache directories:
- **macOS**: `~/Library/Caches/gittyup/logs`
- **Linux**: `~/.cache/gittyup/logs`
- **Windows**: `C:\Users\<user>\AppData\Local\gittyup\logs`

Each directory you scan gets its own log, automatically updated with each run. Storage is minimal (10-50 KB per log).

---

## πŸ›‘οΈ Safety Features

Gitty Up protects your work with intelligent safety checks. It will **skip** updating a repository if it detects:

| Condition | Why it's Skipped | What to Do |
|-----------|------------------|------------|
| πŸ”’ Uncommitted changes | Prevents losing your work | Commit, stash, or discard changes first |
| πŸ”— No remote configured | Nothing to pull from | Add a remote: `git remote add origin <url>` |
| πŸ“ Detached HEAD state | Not on a branch | Checkout a branch: `git checkout main` |
| 🎯 No upstream branch | Branch not tracking remote | Set upstream: `git push -u origin <branch>` |
| 🌐 Network errors | Can't reach remote | Check connection and remote URL |
| πŸ” Authentication failed | Credentials missing | Configure Git credentials |

**Your local work is always safe.** Gitty Up never forces changes or overwrites uncommitted work.

---

## 🧠 Smart Filtering

Gitty Up automatically skips common directories that aren't your code:

**Development Environments:**  
`node_modules`, `venv`, `.venv`, `env`, `.env`, `vendor`

**Build Artifacts:**  
`dist`, `build`, `target`, `.eggs`, `eggs`

**Caches:**  
`__pycache__`, `.pytest_cache`, `.mypy_cache`, `.ruff_cache`, `htmlcov`

**Tools:**  
`.tox`, `.nox`, `.idea`, `.vscode`

**Version Control:**  
`.git`, `.svn`, `.hg`

Want to exclude more? Use `--exclude`:
```bash
gittyup --exclude temp --exclude backup --exclude old-stuff
```

### 🧹 Always-Ignored Files

GittyUp knows the difference between real changes and desktop clutter. These common system and cache files are automatically ignored when checking for uncommitted changes:

- **`.DS_Store`** - macOS metadata that clutters every directory
- **`Thumbs.db`** - Windows thumbnail caches you never asked for  
- **`__pycache__`** - Python bytecode that regenerates anyway

**Why this matters:** Repositories with only these files are treated as clean and can be updated automatically. No more "uncommitted changes" blocks just because your OS left metadata files lying around.

**πŸ“š Learn more:** See [Always-Ignored Files Documentation](docs/always-ignored-files.md) for detailed examples and implementation details.

---

## ❓ FAQ

<details>
<summary><strong>Will Gitty Up overwrite my local changes?</strong></summary>

**Absolutely not.** Gitty Up includes comprehensive safety checks and will skip any repository with uncommitted changes. Your local work is always protected.
</details>

<details>
<summary><strong>What happens if I have a merge conflict?</strong></summary>

Gitty Up will detect the conflict, report it as an error, and move on to the next repository. You'll need to resolve conflicts manuallyβ€”Gitty Up never forces merges.
</details>

<details>
<summary><strong>Can I use this with private repositories?</strong></summary>

Yes! As long as your Git credentials are properly configured (SSH keys or credential helper), Gitty Up will work seamlessly with private repos.
</details>

<details>
<summary><strong>How do I exclude specific directories?</strong></summary>

Use the `--exclude` option (multiple times if needed):
```bash
gittyup --exclude archive --exclude temp --exclude old-projects
```
</details>

<details>
<summary><strong>Does it work with Git submodules?</strong></summary>

Gitty Up treats the parent repository as a single unit and doesn't traverse into submodules. This prevents confusion and duplicate updates.
</details>

<details>
<summary><strong>Can I run this on a schedule?</strong></summary>

Absolutely! Set up a cron job (Unix) or Task Scheduler (Windows):
```bash
# Example: Daily at 9 AM
0 9 * * * cd ~/projects && ~/.local/bin/gittyup --quiet
```
</details>

<details>
<summary><strong>What if one repository fails?</strong></summary>

Gitty Up continues processing all other repositories. Failures are clearly reported at the end, and you can address them individually.
</details>

<details>
<summary><strong>Does it support SVN or Mercurial?</strong></summary>

No, Gitty Up is specifically designed for Git repositories. It's Git all the way down. 🐴
</details>

<details>
<summary><strong>What information does --explain show?</strong></summary>

Think of `--explain` as your guardian's detailed report card. It shows:
- **Every commit that was pulled**: Who wrote it, when they committed it, and the commit message
- **Exactly which files changed**: File paths with insertion/deletion counts
- **Why any repos were skipped**: Specific reasons like uncommitted changes or detached HEAD
- **Full error details**: Complete diagnostics for debugging any issues
- **Operation metadata**: When it ran, how long it took, versions used

Perfect when you need to understand what happened, debug an issue, or provide accountability for automated runs. No need to re-run the operationβ€”your guardian remembers everything.
</details>

<details>
<summary><strong>Where are logs stored and how much space do they use?</strong></summary>

Your guardian stores logs in OS-specific cache directories using efficient key-value storage:
- **macOS**: `~/Library/Caches/gittyup/logs`
- **Linux**: `~/.cache/gittyup/logs`
- **Windows**: `C:\Users\<user>\AppData\Local\gittyup\logs`

Storage impact is minimal: each log is typically 10-50 KB. Even with 100 directories logged, total storage is only 1-5 MB. Each directory gets one log that's updated with each run, so space doesn't grow unbounded.
</details>

<details>
<summary><strong>Do dry runs create logs?</strong></summary>

No, dry runs (`--dry-run`) do not save logs. Your guardian only records actual operations that modify repositories. This keeps your history clean and focused on real changes, not "what if" scenarios.
</details>

<details>
<summary><strong>How does concurrent batch processing work?</strong></summary>

By default, Gitty Up updates repositories in batches of 3 simultaneously using async I/O operations. This dramatically improves performance when updating many repositories:

```bash
# Default: 3 repos at a time
gittyup ~/projects

# High performance: 5 repos at a time
gittyup ~/projects --batch-size 5

# Sequential (old behavior): 1 repo at a time
gittyup ~/projects --sync
```

**Benefits:**
- **Faster updates**: Network I/O happens concurrently while waiting for git operations
- **Controlled resources**: Batch size prevents overwhelming your system
- **Clear output**: Results are displayed in order after each batch completes

**When to adjust batch size:**
- **Increase** (`--batch-size 5-10`): Fast internet, powerful system, many repos
- **Decrease** (`--batch-size 1` or `--sync`): Debugging issues, slow connection, conservative approach

The concurrent processing is safe and respects all the same safety checks as sequential mode.
</details>

---

## 🚨 Troubleshooting

### Git Not Found
```
Error: Git is not installed or not found in PATH
```
**Fix:** Install Git and ensure it's in your system PATH:
```bash
# macOS
brew install git

# Linux (Debian/Ubuntu)  
sudo apt-get install git

# Verify
git --version
```

### Authentication Issues
```
Error: Authentication failed
```
**Fix:** Configure your Git credentials:
```bash
# SSH keys (recommended)
ssh-keygen -t ed25519 -C "your@email.com"
# Then add to GitHub/GitLab/etc.

# Or use credential helper
git config --global credential.helper store
```

### Permission Denied
```
Error: Permission denied
```
**Fix:** Ensure you have read access to the directories being scanned. Check file permissions or run with appropriate privileges.

### Network Timeouts
```
Error: Network error
```
**Fix:**
- Check your internet connection
- Verify remote URLs: `git remote -v`
- Check firewall settings
- Consider using `--max-depth` to reduce scope

### Log History Not Found
```
⚠️  No history found for: /path/to/directory
```
**Fix:**
- Run `gittyup` in this directory first (your guardian needs something to record!)
- Remember: logs are only created for actual operations (non-dry-run)
- Verify you're in the same directory where you previously ran gittyup
- Check that the cache directory has write permissions

### Cache Permission Errors
```
Error: Failed to save operation log
```
**Fix:**
- Ensure write access to cache directory:
  - macOS: `~/Library/Caches/gittyup/logs`
  - Linux: `~/.cache/gittyup/logs`
  - Windows: `C:\Users\<user>\AppData\Local\gittyup\logs`
- Check directory permissions: `ls -la ~/.cache/gittyup` (Unix/macOS)
- Create directory manually if needed: `mkdir -p ~/.cache/gittyup/logs`

---

## πŸ”§ Development & Contributing

Interested in contributing to Gitty Up or running it locally for development?

**πŸ“š See the [Development Guide](docs/development.md)** for:
- Development setup instructions
- Testing and code quality guidelines
- Contributing guidelines and PR process
- Project architecture and design decisions
- Release process and versioning

We welcome contributions of all kindsβ€”bug reports, feature requests, documentation improvements, and code contributions!

---

## πŸ“Š Project Stats

<div align="center">

| Metric | Value |
|--------|-------|
| **Test Coverage** | 91.93% |
| **Total Tests** | 216 passing |
| **Code Quality** | Zero linting issues |
| **Python Version** | 3.13+ |
| **Dependencies** | Minimal (click, colorama, platformdirs, diskcache) |
| **Lines of Code** | ~2,100 |

</div>

---

## πŸ“„ License

This project is licensed under the MIT License - see the [LICENSE](LICENSE) file for details.

---

## πŸ™ Acknowledgments

Built with ❀️ for developers who juggle too many projects and forget to `git pull`.

**Powered by:**
- [Click](https://click.palletsprojects.com/) - Command-line interface magic
- [Colorama](https://github.com/tartley/colorama) - Cross-platform colored output
- [platformdirs](https://github.com/platformdirs/platformdirs) - OS-specific directory paths
- [diskcache](https://github.com/grantjenks/python-diskcache) - Fast persistent caching
- [Ruff](https://github.com/astral-sh/ruff) - Lightning-fast Python linting

---

## πŸ“Œ Version

**Current Release:** `1.0.0`

See [change-log.md](change-log.md) for complete version history and release notes.

---

<div align="center">

**Made with 🐴 by developers, for developers**

[⬆ Back to Top](#-gitty-up)

</div>

            

Raw data

            {
    "_id": null,
    "home_page": null,
    "name": "gittyup",
    "maintainer": null,
    "docs_url": null,
    "requires_python": ">=3.13",
    "maintainer_email": null,
    "keywords": "automation, cli, git, repository, update",
    "author": "Michael Kennedy",
    "author_email": null,
    "download_url": "https://files.pythonhosted.org/packages/5a/9e/48548cbb2267e2090c956c105fde71ec2e121add0573df1158b0ea1145e6/gittyup-1.1.0.tar.gz",
    "platform": null,
    "description": "<div align=\"center\">\n\n# \ud83d\udc34 Gitty Up!\n\n### *Never forget to pull again*\n\n**Automatically discover and update all your Git repositories with one command**\n\n[![Python Version](https://img.shields.io/badge/python-3.13%2B-blue.svg)](https://www.python.org/downloads/)\n[![PyPI Version](https://img.shields.io/pypi/v/gittyup.svg)](https://pypi.org/project/gittyup/)\n[![PyPI Downloads](https://img.shields.io/pypi/dm/gittyup.svg)](https://pypi.org/project/gittyup/)\n[![Test Coverage](https://img.shields.io/badge/coverage-91.93%25-brightgreen.svg)](https://github.com)\n[![Tests](https://img.shields.io/badge/tests-216%20passing-brightgreen.svg)](https://github.com)\n[![Code Style](https://img.shields.io/badge/code%20style-ruff-black.svg)](https://github.com/astral-sh/ruff)\n[![License](https://img.shields.io/badge/license-MIT-blue.svg)](LICENSE)\n\n[Features](#-features) \u2022 [Installation](#-installation) \u2022 [Quick Start](#-quick-start) \u2022 [Documentation](#-documentation) \u2022 [FAQ](#-faq)\n\n</div>\n\n---\n\n## \ud83c\udfaf The Problem\n\nYou're about to start coding. You open your project, dive into the code, make changes... then realize you forgot to `git pull`. Now you're dealing with merge conflicts, rebasing headaches, and lost time. Sound familiar?\n\nWhen you're juggling multiple projects, working across different machines, or collaborating with a team, keeping every repository up-to-date becomes a mental burden. One forgotten `git pull` can derail your entire workflow.\n\n## \u2728 The Solution\n\n**Gitty Up** is your automated Git guardian. Point it at your projects directory, and it intelligently scans every repository, pulling the latest changes while keeping your work safe. It documents everything it does, so you always know exactly what changed. No more forgotten pulls. No more merge conflict surprises. No more wondering what happened. Just smooth, up-to-date repositories ready for action\u2014with complete accountability.\n\nThink of it as your morning coffee routine for your codebase\u2014one command, and everything's fresh, safe, and fully documented.\n\n---\n\n## \ud83d\ude80 Features\n\n<table>\n<tr>\n<td width=\"50%\">\n\n### \ud83d\udee1\ufe0f **Safety First**\nSmart checks prevent data loss. Skips repos with uncommitted changes, detached HEADs, or missing upstreams. Your local work is always protected.\n\n### \ud83d\udd0d **Complete Transparency**\nYour Git guardian keeps detailed records. Every operation is automatically logged with commit details, file changes, and timing data. Use `--explain` to review exactly what happened\u2014perfect for debugging, auditing, or understanding what changed.\n\n### \ud83c\udfa8 **Visual Clarity**  \nBeautiful, color-coded output with intuitive symbols. Green for success, red for errors\u2014know exactly what's happening at a glance.\n\n### \ud83d\udd0e **Intelligent Discovery**\nRecursively finds every Git repository in your directory tree, no matter how deeply nested.\n\n</td>\n<td width=\"50%\">\n\n### \u26a1 **Lightning Fast**\nConcurrent batch processing updates multiple repositories simultaneously. Configurable batch sizes optimize performance for your workflow. Auto-excludes common junk directories.\n\n### \ud83c\udfaf **Flexible Control**\nDry-run mode, depth limits, custom exclusions, verbosity levels\u2014you're in complete control of every operation.\n\n### \u2705 **Battle-Tested**\n91.93% test coverage with 216 comprehensive tests. Production-ready and reliable with every release.\n\n</td>\n</tr>\n</table>\n\n---\n\n## \ud83d\udce6 Installation\n\n### Prerequisites\n\n- **Python 3.13+** installed on your system\n- **Git** available in your PATH\n- **uv** package manager (recommended) or pip\n\n### Method 1: Install from PyPI (Recommended) \u2b50\n\nInstall directly from PyPI as a global CLI tool\u2014no virtual environment needed!\n\n```bash\n# Install as a global tool with uv\nuv tool install gittyup\n\n# That's it! Use from anywhere without activating venv\ngittyup --version\n```\n\n**Benefits:** \u2705 No venv activation \u2022 \u2705 Available system-wide \u2022 \u2705 Isolated environment \u2022 \u2705 Easy updates\n\n\n### Method 2: Install from Source\n\nFor development or contributing to the project:\n\n```bash\n# Clone and navigate to the project\ngit clone https://github.com/mikeckennedy/gittyup\ncd gittyup\n\n# Install in editable mode with uv\nuv tool install --editable .\n```\n\n---\n\n## \u26a1 Quick Start\n\n### Basic Commands\n\n```bash\n# Update all repos in current directory\ngittyup\n\n# Update repos in a specific location\ngittyup ~/dev/projects\n\n# Preview what would happen (dry run)\ngittyup --dry-run\n\n# Get detailed output\ngittyup --verbose\n```\n\n### Common Workflows\n\n**The Monday Morning Refresh** \ud83c\udf05\n```bash\ngittyup ~/projects\n```\nStart your week with every project up-to-date.\n\n**The Quick Check** \ud83d\udc40\n```bash\ngittyup --dry-run --verbose\n```\nSee what's outdated without touching anything.\n\n**The Deep Dive** \ud83d\udd0e\n```bash\ngittyup ~/dev --max-depth 3 --exclude archive --verbose\n```\nScan thoroughly but skip archived projects.\n\n**The Accountability Check** \ud83d\udd0d\n```bash\ngittyup --explain\n```\nReview your guardian's detailed report: see exactly what commits were pulled, which files changed, and why any repos were skipped. Perfect for Monday morning catch-up or debugging unexpected changes.\n\n**The Performance Mode** \u26a1\n```bash\ngittyup ~/projects --batch-size 5\n```\nUpdate multiple repositories concurrently for maximum speed. Adjust batch size based on your system resources and network connection. Careful you don't over do it and get rate limited at GitHub.\n\n**The Safe and Sequential** \ud83c\udfaf\n```bash\ngittyup --sync --verbose\n```\nProcess repositories one at a time for careful monitoring or when debugging issues. Perfect for troubleshooting or conservative workflows.\n\n---\n\n## \ud83d\udcd6 Documentation\n\n### Command Reference\n\n```bash\ngittyup [DIRECTORY] [OPTIONS]\n```\n\n| Argument/Option | Description | Default |\n|----------------|-------------|---------|\n| `DIRECTORY` | Path to scan for repositories | Current directory |\n| `-n, --dry-run` | Preview changes without updating | Disabled |\n| `-b, --batch-size N` | Number of repos to update concurrently | 3 |\n| `-s, --sync` | Force sequential updates (batch size = 1) | Concurrent |\n| `-d, --max-depth N` | Maximum directory depth to scan | Unlimited |\n| `-e, --exclude PATTERN` | Skip directories matching pattern | None |\n| `-v, --verbose` | Show all repos, including up-to-date | Normal |\n| `-q, --quiet` | Only show errors | Normal |\n| `--explain` | Show detailed history of last run | Disabled |\n| `--version` | Display version information | - |\n| `--help` | Show help message | - |\n\n### Output Guide\n\nGitty Up uses clear visual indicators to communicate status:\n\n<table>\n<tr>\n<td><strong>\u2713</strong> Green</td>\n<td>Repository is up-to-date or successfully updated</td>\n</tr>\n<tr>\n<td><strong>\u2193</strong> Cyan</td>\n<td>Repository pulled new commits</td>\n</tr>\n<tr>\n<td><strong>\u2299</strong> Yellow</td>\n<td>Repository skipped (safety check failed)</td>\n</tr>\n<tr>\n<td><strong>\u2717</strong> Red</td>\n<td>Error occurred during update</td>\n</tr>\n<tr>\n<td><strong>\u2192</strong> White</td>\n<td>Processing repository</td>\n</tr>\n</table>\n\n### Example Output\n\n```\n\u2554\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2557\n\u2551                              Gitty Up                                       \u2551\n\u255a\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u255d\n\n\u2713 Scanning directory: /Users/dev/projects\n\u2713 Found 9 git repositories\n\nUpdating: project-alpha, project-beta, project-gamma\n\u2713 project-alpha - Already up-to-date\n\u2193 project-beta - Pulled 3 commits\n\u2299 project-gamma - Uncommitted changes\n\nUpdating: project-delta, project-epsilon, project-zeta\n\u2713 project-delta - Already up-to-date\n\u2717 project-epsilon - Network timeout\n\u2193 project-zeta - Pulled 1 commit\n\nUpdating: project-omega, project-sigma, project-theta\n\u2713 project-omega - Already up-to-date\n\u2713 project-sigma - Already up-to-date\n\u2713 project-theta - Already up-to-date\n\n\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\nSummary\n\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\nTotal repositories found: 9\n  \u2713 Up to date: 5\n  \u2193 Updated: 2\n  \u2299 Skipped: 1\n  \u2717 Errors: 1\n\nCompleted in 4.23 seconds\n\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\n```\n\n**Note:** The example shows default batch processing (3 repos at a time). Use `--sync` for sequential updates with individual progress indicators.\n\n### Using --explain to Review History\n\nYour Git guardian keeps detailed records of every operation. Need to know what changed? Just ask:\n\n```bash\n$ cd ~/projects\n$ gittyup --explain\n```\n\n```\n\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\n                    Gitty Up - Operation History\n\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\n\n\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\nOperation Details\n\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\n  \ud83d\udcc5 Run Date: 2025-10-15 14:23:45\n  \ud83d\udcc2 Directory: /Users/dev/projects\n  \u23f1\ufe0f  Duration: 2.34 seconds\n  \ud83d\udd27 Gittyup Version: 1.0.0\n  \ud83d\udc19 Git Version: 2.39.0\n\n\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\nSummary\n\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\n  Total repositories: 5\n  \u2705 Updated: 1\n  \ud83d\udca4 Already up-to-date: 3\n  \u23ed\ufe0f  Skipped: 1\n  \u274c Errors: 0\n\n\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\nRepository Details\n\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\n\n\u2705 project-alpha\n   Path: /Users/dev/projects/project-alpha\n   Duration: 487ms\n   Branch: main\n   Changes pulled successfully\n   Commits: 3\n   Files changed: 5\n   Insertions: +127\n   Deletions: -43\n\n   \ud83d\udcdd Commits:\n      a7f2c3d - Add new feature for user authentication\n         John Doe \u2022 2025-10-15T10:23:00\n      b8e1d4f - Fix bug in login validation\n         Jane Smith \u2022 2025-10-15T09:15:00\n      c9f2e5g - Update dependencies to latest versions\n         John Doe \u2022 2025-10-14T16:45:00\n\n   \ud83d\udcc1 Files:\n      ~ src/auth.py\n         (+45/-12)\n      + src/validators.py\n         (+32/-0)\n      ~ tests/test_auth.py\n         (+28/-8)\n\n\ud83d\udca4 project-beta\n   Path: /Users/dev/projects/project-beta\n   Duration: 123ms\n   Branch: develop\n   Already up-to-date\n\n\u23ed\ufe0f  project-gamma\n   Path: /Users/dev/projects/project-gamma\n   Duration: 89ms\n   Branch: main\n   Skipped\n   Reason: Repository has uncommitted changes\n   Details: Pull would conflict with local modifications\n\n\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\n```\n\n**What --explain shows:**\n- **Complete operation metadata**: When it ran, how long it took, tool versions\n- **Summary statistics**: Overall results across all repositories  \n- **Detailed repository information**:\n  - Every commit that was pulled (who wrote it, when, what changed)\n  - Exactly which files changed with insertion/deletion counts\n  - Why any repos were skipped with specific reasons\n  - Full error details for debugging failed operations\n  - Branch information and precise timing data\n\n**Perfect for:**\n- Debugging issues or understanding unexpected changes\n- Auditing what happened during automated runs\n- Reviewing what you missed while away from your desk\n- Team accountability and change tracking\n\n**Where logs are stored:**\nYour guardian keeps records in OS-specific cache directories:\n- **macOS**: `~/Library/Caches/gittyup/logs`\n- **Linux**: `~/.cache/gittyup/logs`\n- **Windows**: `C:\\Users\\<user>\\AppData\\Local\\gittyup\\logs`\n\nEach directory you scan gets its own log, automatically updated with each run. Storage is minimal (10-50 KB per log).\n\n---\n\n## \ud83d\udee1\ufe0f Safety Features\n\nGitty Up protects your work with intelligent safety checks. It will **skip** updating a repository if it detects:\n\n| Condition | Why it's Skipped | What to Do |\n|-----------|------------------|------------|\n| \ud83d\udd12 Uncommitted changes | Prevents losing your work | Commit, stash, or discard changes first |\n| \ud83d\udd17 No remote configured | Nothing to pull from | Add a remote: `git remote add origin <url>` |\n| \ud83d\udccd Detached HEAD state | Not on a branch | Checkout a branch: `git checkout main` |\n| \ud83c\udfaf No upstream branch | Branch not tracking remote | Set upstream: `git push -u origin <branch>` |\n| \ud83c\udf10 Network errors | Can't reach remote | Check connection and remote URL |\n| \ud83d\udd10 Authentication failed | Credentials missing | Configure Git credentials |\n\n**Your local work is always safe.** Gitty Up never forces changes or overwrites uncommitted work.\n\n---\n\n## \ud83e\udde0 Smart Filtering\n\nGitty Up automatically skips common directories that aren't your code:\n\n**Development Environments:**  \n`node_modules`, `venv`, `.venv`, `env`, `.env`, `vendor`\n\n**Build Artifacts:**  \n`dist`, `build`, `target`, `.eggs`, `eggs`\n\n**Caches:**  \n`__pycache__`, `.pytest_cache`, `.mypy_cache`, `.ruff_cache`, `htmlcov`\n\n**Tools:**  \n`.tox`, `.nox`, `.idea`, `.vscode`\n\n**Version Control:**  \n`.git`, `.svn`, `.hg`\n\nWant to exclude more? Use `--exclude`:\n```bash\ngittyup --exclude temp --exclude backup --exclude old-stuff\n```\n\n### \ud83e\uddf9 Always-Ignored Files\n\nGittyUp knows the difference between real changes and desktop clutter. These common system and cache files are automatically ignored when checking for uncommitted changes:\n\n- **`.DS_Store`** - macOS metadata that clutters every directory\n- **`Thumbs.db`** - Windows thumbnail caches you never asked for  \n- **`__pycache__`** - Python bytecode that regenerates anyway\n\n**Why this matters:** Repositories with only these files are treated as clean and can be updated automatically. No more \"uncommitted changes\" blocks just because your OS left metadata files lying around.\n\n**\ud83d\udcda Learn more:** See [Always-Ignored Files Documentation](docs/always-ignored-files.md) for detailed examples and implementation details.\n\n---\n\n## \u2753 FAQ\n\n<details>\n<summary><strong>Will Gitty Up overwrite my local changes?</strong></summary>\n\n**Absolutely not.** Gitty Up includes comprehensive safety checks and will skip any repository with uncommitted changes. Your local work is always protected.\n</details>\n\n<details>\n<summary><strong>What happens if I have a merge conflict?</strong></summary>\n\nGitty Up will detect the conflict, report it as an error, and move on to the next repository. You'll need to resolve conflicts manually\u2014Gitty Up never forces merges.\n</details>\n\n<details>\n<summary><strong>Can I use this with private repositories?</strong></summary>\n\nYes! As long as your Git credentials are properly configured (SSH keys or credential helper), Gitty Up will work seamlessly with private repos.\n</details>\n\n<details>\n<summary><strong>How do I exclude specific directories?</strong></summary>\n\nUse the `--exclude` option (multiple times if needed):\n```bash\ngittyup --exclude archive --exclude temp --exclude old-projects\n```\n</details>\n\n<details>\n<summary><strong>Does it work with Git submodules?</strong></summary>\n\nGitty Up treats the parent repository as a single unit and doesn't traverse into submodules. This prevents confusion and duplicate updates.\n</details>\n\n<details>\n<summary><strong>Can I run this on a schedule?</strong></summary>\n\nAbsolutely! Set up a cron job (Unix) or Task Scheduler (Windows):\n```bash\n# Example: Daily at 9 AM\n0 9 * * * cd ~/projects && ~/.local/bin/gittyup --quiet\n```\n</details>\n\n<details>\n<summary><strong>What if one repository fails?</strong></summary>\n\nGitty Up continues processing all other repositories. Failures are clearly reported at the end, and you can address them individually.\n</details>\n\n<details>\n<summary><strong>Does it support SVN or Mercurial?</strong></summary>\n\nNo, Gitty Up is specifically designed for Git repositories. It's Git all the way down. \ud83d\udc34\n</details>\n\n<details>\n<summary><strong>What information does --explain show?</strong></summary>\n\nThink of `--explain` as your guardian's detailed report card. It shows:\n- **Every commit that was pulled**: Who wrote it, when they committed it, and the commit message\n- **Exactly which files changed**: File paths with insertion/deletion counts\n- **Why any repos were skipped**: Specific reasons like uncommitted changes or detached HEAD\n- **Full error details**: Complete diagnostics for debugging any issues\n- **Operation metadata**: When it ran, how long it took, versions used\n\nPerfect when you need to understand what happened, debug an issue, or provide accountability for automated runs. No need to re-run the operation\u2014your guardian remembers everything.\n</details>\n\n<details>\n<summary><strong>Where are logs stored and how much space do they use?</strong></summary>\n\nYour guardian stores logs in OS-specific cache directories using efficient key-value storage:\n- **macOS**: `~/Library/Caches/gittyup/logs`\n- **Linux**: `~/.cache/gittyup/logs`\n- **Windows**: `C:\\Users\\<user>\\AppData\\Local\\gittyup\\logs`\n\nStorage impact is minimal: each log is typically 10-50 KB. Even with 100 directories logged, total storage is only 1-5 MB. Each directory gets one log that's updated with each run, so space doesn't grow unbounded.\n</details>\n\n<details>\n<summary><strong>Do dry runs create logs?</strong></summary>\n\nNo, dry runs (`--dry-run`) do not save logs. Your guardian only records actual operations that modify repositories. This keeps your history clean and focused on real changes, not \"what if\" scenarios.\n</details>\n\n<details>\n<summary><strong>How does concurrent batch processing work?</strong></summary>\n\nBy default, Gitty Up updates repositories in batches of 3 simultaneously using async I/O operations. This dramatically improves performance when updating many repositories:\n\n```bash\n# Default: 3 repos at a time\ngittyup ~/projects\n\n# High performance: 5 repos at a time\ngittyup ~/projects --batch-size 5\n\n# Sequential (old behavior): 1 repo at a time\ngittyup ~/projects --sync\n```\n\n**Benefits:**\n- **Faster updates**: Network I/O happens concurrently while waiting for git operations\n- **Controlled resources**: Batch size prevents overwhelming your system\n- **Clear output**: Results are displayed in order after each batch completes\n\n**When to adjust batch size:**\n- **Increase** (`--batch-size 5-10`): Fast internet, powerful system, many repos\n- **Decrease** (`--batch-size 1` or `--sync`): Debugging issues, slow connection, conservative approach\n\nThe concurrent processing is safe and respects all the same safety checks as sequential mode.\n</details>\n\n---\n\n## \ud83d\udea8 Troubleshooting\n\n### Git Not Found\n```\nError: Git is not installed or not found in PATH\n```\n**Fix:** Install Git and ensure it's in your system PATH:\n```bash\n# macOS\nbrew install git\n\n# Linux (Debian/Ubuntu)  \nsudo apt-get install git\n\n# Verify\ngit --version\n```\n\n### Authentication Issues\n```\nError: Authentication failed\n```\n**Fix:** Configure your Git credentials:\n```bash\n# SSH keys (recommended)\nssh-keygen -t ed25519 -C \"your@email.com\"\n# Then add to GitHub/GitLab/etc.\n\n# Or use credential helper\ngit config --global credential.helper store\n```\n\n### Permission Denied\n```\nError: Permission denied\n```\n**Fix:** Ensure you have read access to the directories being scanned. Check file permissions or run with appropriate privileges.\n\n### Network Timeouts\n```\nError: Network error\n```\n**Fix:**\n- Check your internet connection\n- Verify remote URLs: `git remote -v`\n- Check firewall settings\n- Consider using `--max-depth` to reduce scope\n\n### Log History Not Found\n```\n\u26a0\ufe0f  No history found for: /path/to/directory\n```\n**Fix:**\n- Run `gittyup` in this directory first (your guardian needs something to record!)\n- Remember: logs are only created for actual operations (non-dry-run)\n- Verify you're in the same directory where you previously ran gittyup\n- Check that the cache directory has write permissions\n\n### Cache Permission Errors\n```\nError: Failed to save operation log\n```\n**Fix:**\n- Ensure write access to cache directory:\n  - macOS: `~/Library/Caches/gittyup/logs`\n  - Linux: `~/.cache/gittyup/logs`\n  - Windows: `C:\\Users\\<user>\\AppData\\Local\\gittyup\\logs`\n- Check directory permissions: `ls -la ~/.cache/gittyup` (Unix/macOS)\n- Create directory manually if needed: `mkdir -p ~/.cache/gittyup/logs`\n\n---\n\n## \ud83d\udd27 Development & Contributing\n\nInterested in contributing to Gitty Up or running it locally for development?\n\n**\ud83d\udcda See the [Development Guide](docs/development.md)** for:\n- Development setup instructions\n- Testing and code quality guidelines\n- Contributing guidelines and PR process\n- Project architecture and design decisions\n- Release process and versioning\n\nWe welcome contributions of all kinds\u2014bug reports, feature requests, documentation improvements, and code contributions!\n\n---\n\n## \ud83d\udcca Project Stats\n\n<div align=\"center\">\n\n| Metric | Value |\n|--------|-------|\n| **Test Coverage** | 91.93% |\n| **Total Tests** | 216 passing |\n| **Code Quality** | Zero linting issues |\n| **Python Version** | 3.13+ |\n| **Dependencies** | Minimal (click, colorama, platformdirs, diskcache) |\n| **Lines of Code** | ~2,100 |\n\n</div>\n\n---\n\n## \ud83d\udcc4 License\n\nThis project is licensed under the MIT License - see the [LICENSE](LICENSE) file for details.\n\n---\n\n## \ud83d\ude4f Acknowledgments\n\nBuilt with \u2764\ufe0f for developers who juggle too many projects and forget to `git pull`.\n\n**Powered by:**\n- [Click](https://click.palletsprojects.com/) - Command-line interface magic\n- [Colorama](https://github.com/tartley/colorama) - Cross-platform colored output\n- [platformdirs](https://github.com/platformdirs/platformdirs) - OS-specific directory paths\n- [diskcache](https://github.com/grantjenks/python-diskcache) - Fast persistent caching\n- [Ruff](https://github.com/astral-sh/ruff) - Lightning-fast Python linting\n\n---\n\n## \ud83d\udccc Version\n\n**Current Release:** `1.0.0`\n\nSee [change-log.md](change-log.md) for complete version history and release notes.\n\n---\n\n<div align=\"center\">\n\n**Made with \ud83d\udc34 by developers, for developers**\n\n[\u2b06 Back to Top](#-gitty-up)\n\n</div>\n",
    "bugtrack_url": null,
    "license": "MIT",
    "summary": "Automatically discover and update all git repositories in a directory tree",
    "version": "1.1.0",
    "project_urls": {
        "Homepage": "https://github.com/mikeckennedy/gittyup",
        "Issues": "https://github.com/mikeckennedy/gittyup/issues",
        "Repository": "https://github.com/mikeckennedy/gittyup"
    },
    "split_keywords": [
        "automation",
        " cli",
        " git",
        " repository",
        " update"
    ],
    "urls": [
        {
            "comment_text": null,
            "digests": {
                "blake2b_256": "02ed4629ca1ea2c7709218f12dc8da0abd0314240349d6bb11806ad8994a10bb",
                "md5": "e52404ac1bf897a4c8f919f38cd82de3",
                "sha256": "3b2d65b8fb105cab232636b173222c602b534cac671ffda9d1d21982cf84a384"
            },
            "downloads": -1,
            "filename": "gittyup-1.1.0-py3-none-any.whl",
            "has_sig": false,
            "md5_digest": "e52404ac1bf897a4c8f919f38cd82de3",
            "packagetype": "bdist_wheel",
            "python_version": "py3",
            "requires_python": ">=3.13",
            "size": 31822,
            "upload_time": "2025-10-25T17:30:10",
            "upload_time_iso_8601": "2025-10-25T17:30:10.422601Z",
            "url": "https://files.pythonhosted.org/packages/02/ed/4629ca1ea2c7709218f12dc8da0abd0314240349d6bb11806ad8994a10bb/gittyup-1.1.0-py3-none-any.whl",
            "yanked": false,
            "yanked_reason": null
        },
        {
            "comment_text": null,
            "digests": {
                "blake2b_256": "5a9e48548cbb2267e2090c956c105fde71ec2e121add0573df1158b0ea1145e6",
                "md5": "48e2a7e4acaa77c45e390d78246b338a",
                "sha256": "1b2abeeab9bb520a54462d1517c7c5eb46c6602ba619e5bc8aa625f6e1aabd39"
            },
            "downloads": -1,
            "filename": "gittyup-1.1.0.tar.gz",
            "has_sig": false,
            "md5_digest": "48e2a7e4acaa77c45e390d78246b338a",
            "packagetype": "sdist",
            "python_version": "source",
            "requires_python": ">=3.13",
            "size": 98837,
            "upload_time": "2025-10-25T17:30:11",
            "upload_time_iso_8601": "2025-10-25T17:30:11.345768Z",
            "url": "https://files.pythonhosted.org/packages/5a/9e/48548cbb2267e2090c956c105fde71ec2e121add0573df1158b0ea1145e6/gittyup-1.1.0.tar.gz",
            "yanked": false,
            "yanked_reason": null
        }
    ],
    "upload_time": "2025-10-25 17:30:11",
    "github": true,
    "gitlab": false,
    "bitbucket": false,
    "codeberg": false,
    "github_user": "mikeckennedy",
    "github_project": "gittyup",
    "travis_ci": false,
    "coveralls": false,
    "github_actions": false,
    "requirements": [
        {
            "name": "click",
            "specs": [
                [
                    "==",
                    "8.3.0"
                ]
            ]
        },
        {
            "name": "colorama",
            "specs": [
                [
                    "==",
                    "0.4.6"
                ]
            ]
        },
        {
            "name": "diskcache",
            "specs": [
                [
                    "==",
                    "5.6.3"
                ]
            ]
        },
        {
            "name": "platformdirs",
            "specs": [
                [
                    "==",
                    "4.5.0"
                ]
            ]
        }
    ],
    "lcname": "gittyup"
}
        
Elapsed time: 1.14301s