|
1 | | -# gclone |
| 1 | +# 📁 gclone |
2 | 2 |
|
3 | | -I like to store repositories in a specific directory, where I create subdirectories in the format of the full |
4 | | -repository address. |
| 3 | +> **🚀 Smart Git Repository Cloner** - Clone repositories into organized directory structures with parallel processing |
5 | 4 |
|
6 | | -For example, the repository github.com/juev/gclone it will be cloned to the ~/src directory along the way: |
| 5 | +[](https://golang.org) |
| 6 | +[](LICENSE) |
| 7 | +[](https://goreportcard.com/report/github.com/juev/gclone) |
7 | 8 |
|
8 | | -```sh |
9 | | -~/src/github.com/juev/gclone |
10 | | -``` |
| 9 | +## ✨ Why gclone? |
11 | 10 |
|
12 | | -In order not to manually create directories and then clone the repository, I created this small program that allows |
13 | | -you to do this with one command. |
| 11 | +Ever tired of manually creating nested directories for your Git repositories? **gclone** automatically organizes your repos into a clean, predictable structure that mirrors the repository's URL path, **with blazing-fast parallel processing**. |
14 | 12 |
|
15 | | -```sh |
16 | | -GIT_PROJECT_DIR="~/src" gclone https://github.com/juev/gclone.git |
| 13 | +```text |
| 14 | +~/src/ |
| 15 | +├── github.com/ |
| 16 | +│ ├── golang/go/ |
| 17 | +│ ├── kubernetes/kubernetes/ |
| 18 | +│ └── juev/gclone/ |
| 19 | +├── gitlab.com/ |
| 20 | +│ └── company/project/ |
| 21 | +└── bitbucket.org/ |
| 22 | + └── team/service/ |
17 | 23 | ``` |
18 | 24 |
|
19 | | -## Install |
| 25 | +## 🚀 Key Features |
| 26 | + |
| 27 | +- **⚡ Parallel Processing** - Clone multiple repositories simultaneously with configurable workers |
| 28 | +- **🎯 Zero Configuration** - Works out of the box with sensible defaults |
| 29 | +- **📂 Organized Structure** - Mirrors repository URLs in your filesystem |
| 30 | +- **🔒 Security First** - Comprehensive URL validation and path sanitization |
| 31 | +- **💾 Smart Caching** - Intelligent directory existence checking with LRU cache |
| 32 | +- **🌊 Shallow Clones** - Optional `--depth=1` for faster clones |
| 33 | +- **🛡️ Graceful Shutdown** - Handles interrupts cleanly with signal handling |
| 34 | +- **🤫 Quiet Mode** - Suppress output when needed |
| 35 | +- **🐚 Shell Integration** - Perfect for scripts and aliases |
20 | 36 |
|
21 | | -Just: |
| 37 | +## 📦 Installation |
22 | 38 |
|
23 | | -```sh |
| 39 | +```bash |
24 | 40 | go install github.com/juev/gclone@latest |
25 | 41 | ``` |
26 | 42 |
|
27 | | -## Usage |
| 43 | +## 🔧 Quick Start |
| 44 | + |
| 45 | +### Basic Usage |
| 46 | + |
| 47 | +```bash |
| 48 | +# Set your preferred projects directory |
| 49 | +export GIT_PROJECT_DIR="$HOME/src" |
| 50 | + |
| 51 | +# Clone a single repository |
| 52 | +gclone https://github.com/golang/go.git |
| 53 | +# Result: ~/src/github.com/golang/go/ |
| 54 | + |
| 55 | +# Clone multiple repositories in parallel |
| 56 | +gclone https://github.com/golang/go.git \ |
| 57 | + https://github.com/kubernetes/kubernetes.git \ |
| 58 | + https://gitlab.com/company/project.git |
| 59 | + |
| 60 | +# Fast shallow clone |
| 61 | +gclone --shallow https://github.com/large/repository.git |
| 62 | +``` |
| 63 | + |
| 64 | +### Advanced Usage |
| 65 | + |
| 66 | +```bash |
| 67 | +# Use 8 parallel workers for faster cloning |
| 68 | +gclone -w 8 \ |
| 69 | + https://github.com/repo1/project.git \ |
| 70 | + https://github.com/repo2/project.git \ |
| 71 | + https://github.com/repo3/project.git |
| 72 | + |
| 73 | +# Quiet mode for scripts |
| 74 | +gclone --quiet --shallow https://github.com/user/repo.git |
| 75 | + |
| 76 | +# Chain with other commands |
| 77 | +cd "$(gclone https://github.com/user/repo.git)" |
| 78 | +code "$(gclone --quiet https://github.com/user/repo.git)" |
| 79 | +``` |
28 | 80 |
|
29 | | -The location for repositories is determined using the environment variable `GIT_PROJECT_DIR`. |
| 81 | +## 💡 Command Line Options |
30 | 82 |
|
31 | | -You can set it in the system. Or transfer it when the program starts. If the variable is not set, the current |
32 | | -directory will be used as the main one. |
| 83 | +```bash |
| 84 | +gclone [-h] [-v] [-q] [-s] [-w WORKERS] [REPOSITORY...] |
33 | 85 |
|
34 | | -At the output of the program, we will receive either an error in Stderr, or the resulting directory into which |
35 | | -the repository was cloned. |
| 86 | +Options: |
| 87 | + -h, --help Show this help message and exit |
| 88 | + -v, --version Show the version number and exit |
| 89 | + -q, --quiet Suppress output |
| 90 | + -s, --shallow Perform shallow clone with --depth=1 |
| 91 | + -w, --workers Number of parallel workers (default: 4, max: 32) |
36 | 92 |
|
37 | | -We can use the output in a command like: |
| 93 | +Environment Variables: |
| 94 | + GIT_PROJECT_DIR Directory to clone repositories (default: current dir) |
38 | 95 |
|
39 | | -```sh |
40 | | -cd $(gclone $1) |
| 96 | +Examples: |
| 97 | + GIT_PROJECT_DIR="$HOME/src" gclone https://github.com/user/repo |
| 98 | + gclone -w 8 https://github.com/user/repo1 https://github.com/user/repo2 |
41 | 99 | ``` |
42 | 100 |
|
43 | | -### Fish shell |
| 101 | +## 🎨 Shell Integration |
44 | 102 |
|
45 | | -Personally I use these functions: |
| 103 | +### Bash/Zsh Functions |
| 104 | + |
| 105 | +```bash |
| 106 | +# Clone and cd into repository |
| 107 | +gcd() { |
| 108 | + cd "$(gclone "$1")" |
| 109 | +} |
| 110 | + |
| 111 | +# Clone and open in VS Code |
| 112 | +gcode() { |
| 113 | + code "$(gclone "$1")" |
| 114 | +} |
| 115 | + |
| 116 | +# Clone and open in your editor |
| 117 | +gedit() { |
| 118 | + $EDITOR "$(gclone "$1")" |
| 119 | +} |
| 120 | + |
| 121 | +# Bulk clone with parallel processing |
| 122 | +gbulk() { |
| 123 | + gclone -w 8 "$@" |
| 124 | +} |
| 125 | +``` |
| 126 | + |
| 127 | +### Fish Shell Functions |
46 | 128 |
|
47 | 129 | ```fish |
48 | 130 | function gcd --argument repo |
49 | | - if test "$argv[1]" = "" |
50 | | - echo "argument is empty" |
51 | | - return |
52 | | - end |
53 | | - cd $(gclone $argv[1]) |
| 131 | + test -n "$repo"; or return 1 |
| 132 | + cd (gclone $repo) |
54 | 133 | end |
55 | | -``` |
56 | 134 |
|
57 | | -```fish |
58 | 135 | function gcode --argument repo |
59 | | - if test "$argv[1]" = "" |
60 | | - echo "argument is empty" |
61 | | - return |
62 | | - end |
63 | | - code $(gclone $argv[1]) |
| 136 | + test -n "$repo"; or return 1 |
| 137 | + code (gclone $repo) |
| 138 | +end |
| 139 | +
|
| 140 | +function gbulk |
| 141 | + gclone -w 8 $argv |
64 | 142 | end |
65 | 143 | ``` |
66 | 144 |
|
67 | | -Enjoy! |
| 145 | +### PowerShell Functions |
| 146 | + |
| 147 | +```powershell |
| 148 | +function gcd($repo) { |
| 149 | + Set-Location (gclone $repo) |
| 150 | +} |
| 151 | +
|
| 152 | +function gcode($repo) { |
| 153 | + code (gclone $repo) |
| 154 | +} |
| 155 | +
|
| 156 | +function gbulk { |
| 157 | + gclone -w 8 @args |
| 158 | +} |
| 159 | +``` |
| 160 | + |
| 161 | +## 🏗️ How It Works |
| 162 | + |
| 163 | +1. **Parse & Validate** - Security validation of repository URLs |
| 164 | +2. **Normalize** - Convert URLs to filesystem paths (with caching) |
| 165 | +3. **Parallel Process** - Distribute work across configurable workers |
| 166 | +4. **Smart Check** - Cache-optimized directory existence checking |
| 167 | +5. **Secure Clone** - Timeout-protected git operations |
| 168 | +6. **Signal Handling** - Graceful shutdown on interrupts |
| 169 | + |
| 170 | +## 🔒 Security Features |
| 171 | + |
| 172 | +- **URL Validation** - Comprehensive security checks against malicious URLs |
| 173 | +- **Path Sanitization** - Protection against directory traversal attacks |
| 174 | +- **Command Safety** - No shell interpretation, direct git execution |
| 175 | +- **Timeout Protection** - 10-minute timeout per repository |
| 176 | +- **Safe Defaults** - Conservative permissions (0750) for created directories |
| 177 | + |
| 178 | +## ⚡ Performance Features |
| 179 | + |
| 180 | +- **Parallel Workers** - Configurable concurrent cloning (1-32 workers) |
| 181 | +- **Smart Caching** - LRU cache for directory existence checks |
| 182 | +- **Regex Pooling** - Optimized URL parsing with pattern-specific regex |
| 183 | +- **Sequential Fallback** - Automatic optimization for single repositories |
| 184 | +- **Memory Efficient** - Streaming directory reads, minimal allocations |
| 185 | + |
| 186 | +## 🎯 Use Cases |
| 187 | + |
| 188 | +- **📚 Learning** - Quickly clone course materials and tutorials |
| 189 | +- **🔧 Development** - Maintain consistent project structure across teams |
| 190 | +- **🤖 CI/CD** - Bulk repository setup in automation pipelines |
| 191 | +- **🔍 Research** - Rapidly explore multiple open source projects |
| 192 | +- **📋 Backup** - Mirror repositories locally with organized structure |
| 193 | +- **🏢 Enterprise** - Standardized repository organization |
| 194 | + |
| 195 | +## 📊 Status & Monitoring |
| 196 | + |
| 197 | +The tool provides detailed feedback during operation: |
| 198 | + |
| 199 | +```bash |
| 200 | +# Progress indicators for multiple repositories |
| 201 | +gclone repo1.git repo2.git repo3.git |
| 202 | +# processed 3 repositories: 2 successful, 1 failed |
| 203 | + |
| 204 | +# Existing repositories are detected |
| 205 | +gclone https://github.com/existing/repo.git |
| 206 | +# repository already exists: /home/user/src/github.com/existing/repo |
| 207 | + |
| 208 | +# Graceful interrupt handling |
| 209 | +^C Received signal interrupt, initiating graceful shutdown... |
| 210 | +Graceful shutdown completed. |
| 211 | +``` |
| 212 | + |
| 213 | +## 🤝 Contributing |
| 214 | + |
| 215 | +Contributions are welcome! The codebase features: |
| 216 | + |
| 217 | +- **Dependency Injection** - Clean interfaces for testability |
| 218 | +- **Comprehensive Testing** - Full test coverage with mocks |
| 219 | +- **Security Focus** - Multiple layers of validation |
| 220 | +- **Performance Optimization** - Caching, pooling, and parallelization |
| 221 | + |
| 222 | +## 📄 License |
| 223 | + |
| 224 | +MIT License - see [LICENSE](LICENSE) file for details. |
| 225 | + |
| 226 | +--- |
| 227 | + |
| 228 | +Made with ❤️ by developers, for developers |
| 229 | + |
| 230 | +⭐ **Star this repo if it helps you stay organized and productive!** |
0 commit comments