mirror of
https://github.com/yarlson/lnk.git
synced 2025-08-29 17:49:47 +02:00
feat: simplify README and improve init command
This commit is contained in:
406
README.md
406
README.md
@@ -1,387 +1,165 @@
|
||||
# Lnk
|
||||
|
||||
**The missing middle: Safer than simple, simpler than complex.**
|
||||
**Git-native dotfiles management that doesn't suck.**
|
||||
|
||||
Git-native dotfiles management that won't break your setup. Zero config, zero bloat, zero surprises.
|
||||
Move your dotfiles to `~/.config/lnk`, symlink them back, and use Git like normal. That's it.
|
||||
|
||||
```bash
|
||||
# The power of Git, the safety of proper engineering
|
||||
lnk init && lnk add ~/.vimrc && lnk push
|
||||
lnk init
|
||||
lnk add ~/.vimrc ~/.bashrc
|
||||
lnk push "setup"
|
||||
```
|
||||
|
||||
[](./test) [](https://golang.org) [](LICENSE)
|
||||
|
||||
## Why Lnk?
|
||||
|
||||
**The dotfiles manager that fills the missing gap.**
|
||||
|
||||
While chezmoi offers 100+ features and Home Manager requires learning Nix, **Lnk focuses on doing the essentials perfectly**:
|
||||
|
||||
- 🎯 **Safe simplicity**: More robust than Dotbot, simpler than chezmoi
|
||||
- 🛡️ **Bulletproof operations**: Comprehensive edge case handling (unlike minimal tools)
|
||||
- ⚡ **Zero friction**: No YAML configs, no templates, no learning curve
|
||||
- 🔧 **Git-native**: Clean commits, standard workflow, no abstractions
|
||||
- 📦 **Zero dependencies**: Single binary vs Python/Node/Ruby runtimes
|
||||
- 🚀 **Production ready**: 20 integration tests, proper error handling
|
||||
- 🔄 **Smart sync**: Built-in status tracking and seamless multi-machine workflow
|
||||
- 📁 **Directory support**: Manage entire config directories or individual files
|
||||
|
||||
**The market gap**: Tools are either too simple (and unsafe) or too complex (and overwhelming). Lnk is the **Goldilocks solution** – just right for developers who want reliability without complexity.
|
||||
|
||||
## Quick Start
|
||||
## Install
|
||||
|
||||
```bash
|
||||
# Install (30 seconds)
|
||||
curl -sSL https://github.com/yarlson/lnk/releases/latest/download/lnk-linux-amd64 -o lnk
|
||||
chmod +x lnk && sudo mv lnk /usr/local/bin/
|
||||
|
||||
# Use (60 seconds)
|
||||
lnk init -r git@github.com:you/dotfiles.git
|
||||
lnk add ~/.bashrc ~/.vimrc ~/.gitconfig
|
||||
lnk push "Initial dotfiles setup"
|
||||
```
|
||||
|
||||
**That's it.** Your dotfiles are now version-controlled and synced.
|
||||
|
||||
## Installation
|
||||
|
||||
### Quick Install (Recommended)
|
||||
|
||||
```bash
|
||||
# Linux/macOS
|
||||
# Quick
|
||||
curl -sSL https://raw.githubusercontent.com/yarlson/lnk/main/install.sh | bash
|
||||
|
||||
# Or manually download from releases
|
||||
# Manual
|
||||
wget https://github.com/yarlson/lnk/releases/latest/download/lnk-$(uname -s | tr '[:upper:]' '[:lower:]')-amd64
|
||||
chmod +x lnk-* && sudo mv lnk-* /usr/local/bin/lnk
|
||||
|
||||
# From source
|
||||
git clone https://github.com/yarlson/lnk.git && cd lnk && go build . && sudo mv lnk /usr/local/bin/
|
||||
```
|
||||
|
||||
### From Source
|
||||
|
||||
```bash
|
||||
git clone https://github.com/yarlson/lnk.git && cd lnk
|
||||
go build -ldflags="-s -w" -o lnk .
|
||||
sudo mv lnk /usr/local/bin/
|
||||
```
|
||||
|
||||
### Package Managers
|
||||
|
||||
```bash
|
||||
# Homebrew (macOS/Linux)
|
||||
brew install yarlson/tap/lnk
|
||||
|
||||
# Arch Linux
|
||||
yay -S lnk-git
|
||||
```
|
||||
|
||||
## How It Works
|
||||
|
||||
**The mental model is simple**: Lnk moves your dotfiles to `~/.config/lnk/` and replaces them with symlinks.
|
||||
|
||||
```
|
||||
Before: ~/.vimrc (actual file)
|
||||
After: ~/.vimrc -> ~/.config/lnk/.vimrc (symlink)
|
||||
```
|
||||
|
||||
Every change gets a Git commit with descriptive messages like `lnk: added .vimrc`.
|
||||
|
||||
## Usage
|
||||
|
||||
### Initialize Once
|
||||
### Setup
|
||||
|
||||
```bash
|
||||
lnk init # Local repository
|
||||
lnk init -r git@github.com:username/dotfiles.git # With remote
|
||||
# Fresh start
|
||||
lnk init
|
||||
|
||||
# With existing repo
|
||||
lnk init -r git@github.com:user/dotfiles.git
|
||||
```
|
||||
|
||||
**Safety features** (because your dotfiles matter):
|
||||
|
||||
- ✅ Idempotent - run multiple times safely
|
||||
- ✅ Protects existing repositories from overwrite
|
||||
- ✅ Validates remote conflicts before changes
|
||||
|
||||
### Manage Files & Directories
|
||||
### Daily workflow
|
||||
|
||||
```bash
|
||||
lnk add ~/.bashrc ~/.vimrc ~/.tmux.conf # Add multiple files
|
||||
lnk add ~/.config/nvim ~/.ssh # Add entire directories
|
||||
lnk rm ~/.bashrc # Remove from management
|
||||
# Add files/directories
|
||||
lnk add ~/.vimrc ~/.config/nvim ~/.gitconfig
|
||||
|
||||
# Check status
|
||||
lnk status
|
||||
|
||||
# Sync changes
|
||||
lnk push "updated vim config"
|
||||
lnk pull
|
||||
```
|
||||
|
||||
### Sync Commands
|
||||
## How it works
|
||||
|
||||
```bash
|
||||
lnk status # Check sync status with remote
|
||||
lnk push "Update vim configuration" # Stage, commit, and push changes
|
||||
lnk pull # Pull changes and restore symlinks
|
||||
```
|
||||
Before: ~/.vimrc (file)
|
||||
After: ~/.vimrc -> ~/.config/lnk/.vimrc (symlink)
|
||||
```
|
||||
|
||||
**Smart sync features**:
|
||||
Your files live in `~/.config/lnk` (a Git repo). Lnk creates symlinks back to original locations. Edit files normally, use Git normally.
|
||||
|
||||
- ✅ Only commits when there are actual changes
|
||||
- ✅ Automatic symlink restoration after pull
|
||||
- ✅ Clear status reporting (commits ahead/behind)
|
||||
- ✅ Graceful error handling for missing remotes
|
||||
## Why not just Git?
|
||||
|
||||
### Real-World Workflow
|
||||
You could `git init ~/.config/lnk` and manually symlink everything. Lnk just automates the tedious parts:
|
||||
|
||||
```bash
|
||||
# Set up on new machine
|
||||
lnk init -r git@github.com:you/dotfiles.git
|
||||
lnk pull # Get your existing dotfiles with automatic symlink restoration
|
||||
|
||||
# Or clone existing manually for complex setups
|
||||
git clone git@github.com:you/dotfiles.git ~/.config/lnk
|
||||
cd ~/.config/lnk && find . -name ".*" -exec ln -sf ~/.config/lnk/{} ~/{} \;
|
||||
```
|
||||
- Moving files safely
|
||||
- Creating relative symlinks
|
||||
- Handling conflicts
|
||||
- Tracking what's managed
|
||||
|
||||
## Examples
|
||||
|
||||
<details>
|
||||
<summary><strong>📁 Common Development Setup</strong></summary>
|
||||
### First time setup
|
||||
|
||||
```bash
|
||||
# Initialize with remote (recommended)
|
||||
lnk init -r git@github.com:you/dotfiles.git
|
||||
|
||||
# Shell & terminal
|
||||
lnk add ~/.bashrc ~/.zshrc ~/.tmux.conf
|
||||
|
||||
# Development tools
|
||||
lnk add ~/.vimrc ~/.gitconfig ~/.ssh/config
|
||||
|
||||
# Language-specific
|
||||
lnk add ~/.npmrc ~/.cargo/config.toml ~/.pylintrc
|
||||
|
||||
# Push to remote with sync command
|
||||
lnk push "Initial dotfiles setup"
|
||||
|
||||
# Check what's managed and sync status
|
||||
lnk status
|
||||
cd ~/.config/lnk && git log --oneline
|
||||
# 7f3a12c lnk: Initial dotfiles setup
|
||||
# 4e8b33d lnk: added .cargo/config.toml
|
||||
# 2a9c45e lnk: added .npmrc
|
||||
lnk add ~/.bashrc ~/.vimrc ~/.gitconfig
|
||||
lnk push "initial setup"
|
||||
```
|
||||
|
||||
</details>
|
||||
|
||||
<details>
|
||||
<summary><strong>🔄 Multi-Machine Sync</strong></summary>
|
||||
### On a new machine
|
||||
|
||||
```bash
|
||||
# Machine 1: Initial setup
|
||||
lnk init -r git@github.com:you/dotfiles.git
|
||||
lnk add ~/.vimrc ~/.bashrc
|
||||
lnk push "Setup from machine 1"
|
||||
|
||||
# Machine 2: Clone existing
|
||||
lnk init -r git@github.com:you/dotfiles.git
|
||||
lnk pull # Automatically restores symlinks
|
||||
|
||||
# Daily workflow: Keep machines in sync
|
||||
lnk status # Check if changes need syncing
|
||||
lnk push "Updated vim configuration" # Share your changes
|
||||
lnk pull # Get changes from other machines
|
||||
|
||||
# Example sync session
|
||||
lnk status
|
||||
# Your branch is ahead of 'origin/main' by 2 commit(s)
|
||||
|
||||
lnk push "Added new aliases and vim plugins"
|
||||
# Successfully pushed changes to remote
|
||||
|
||||
lnk pull # On other machine
|
||||
# Successfully pulled changes and restored 0 symlink(s)
|
||||
lnk pull # auto-creates symlinks
|
||||
```
|
||||
|
||||
</details>
|
||||
|
||||
<details>
|
||||
<summary><strong>🔄 Smart Sync Workflow</strong></summary>
|
||||
### Daily edits
|
||||
|
||||
```bash
|
||||
# Check current status
|
||||
lnk status
|
||||
# Repository is up to date with remote
|
||||
|
||||
# Make changes to your dotfiles
|
||||
vim ~/.vimrc # Edit managed file
|
||||
|
||||
# Check what needs syncing
|
||||
lnk status
|
||||
# Your branch is ahead of 'origin/main' by 1 commit(s)
|
||||
|
||||
# Sync changes with descriptive message
|
||||
lnk push "Added syntax highlighting and line numbers"
|
||||
# Successfully pushed changes to remote
|
||||
|
||||
# On another machine
|
||||
lnk pull
|
||||
# Successfully pulled changes and restored 1 symlink(s):
|
||||
# - .vimrc
|
||||
|
||||
# Verify sync status
|
||||
lnk status
|
||||
# Repository is up to date with remote
|
||||
vim ~/.vimrc # edit normally
|
||||
lnk status # check what changed
|
||||
lnk push "new plugins" # commit & push
|
||||
```
|
||||
|
||||
</details>
|
||||
## Commands
|
||||
|
||||
## Technical Details
|
||||
- `lnk init [-r remote]` - Create repo
|
||||
- `lnk add <files>` - Move files to repo, create symlinks
|
||||
- `lnk rm <files>` - Move files back, remove symlinks
|
||||
- `lnk status` - Git status + sync info
|
||||
- `lnk push [msg]` - Stage all, commit, push
|
||||
- `lnk pull` - Pull + restore missing symlinks
|
||||
|
||||
### Architecture
|
||||
## Technical bits
|
||||
|
||||
```
|
||||
cmd/ # CLI layer (Cobra)
|
||||
├── init.go # Repository initialization
|
||||
├── add.go # File adoption & symlinking
|
||||
├── rm.go # File restoration
|
||||
├── status.go # Sync status reporting
|
||||
├── push.go # Smart commit and push
|
||||
└── pull.go # Pull with symlink restoration
|
||||
- **Single binary** (~8MB, no deps)
|
||||
- **Atomic operations** (rollback on failure)
|
||||
- **Relative symlinks** (portable)
|
||||
- **XDG compliant** (`~/.config/lnk`)
|
||||
- **20 integration tests**
|
||||
|
||||
internal/
|
||||
├── core/ # Business logic
|
||||
├── fs/ # File system operations
|
||||
└── git/ # Git automation & sync
|
||||
```
|
||||
## Alternatives
|
||||
|
||||
### What Makes It Robust
|
||||
|
||||
- **20 integration tests** covering edge cases and error conditions
|
||||
- **Zero external dependencies** at runtime
|
||||
- **Atomic operations** with automatic rollback on failure
|
||||
- **Relative symlinks** for cross-platform compatibility
|
||||
- **XDG compliance** with fallback to `~/.config`
|
||||
|
||||
### Feature Positioning
|
||||
|
||||
| Feature | Lnk | Dotbot | yadm | chezmoi | Home Manager |
|
||||
| ----------------------- | ------- | ------- | ----- | -------- | ------------ |
|
||||
| **Simplicity** | ✅ | ✅ | ❌ | ❌ | ❌ |
|
||||
| **Safety/Edge Cases** | ✅ | ❌ | ⚠️ | ✅ | ✅ |
|
||||
| **Git Integration** | ✅ | ❌ | ✅ | ⚠️ | ❌ |
|
||||
| **Zero Dependencies** | ✅ | ❌ | ❌ | ✅ | ❌ |
|
||||
| **Cross-Platform** | ✅ | ✅ | ⚠️ | ✅ | ⚠️ |
|
||||
| **Learning Curve** | Minutes | Minutes | Hours | Days | Weeks |
|
||||
| **File Templating** | ❌ | ❌ | Basic | Advanced | Advanced |
|
||||
| **Built-in Encryption** | ❌ | ❌ | ✅ | ✅ | Plugin |
|
||||
| **Package Management** | ❌ | ❌ | ❌ | ❌ | ✅ |
|
||||
|
||||
**Lnk's niche**: Maximum safety and Git integration with minimum complexity.
|
||||
|
||||
### Performance
|
||||
|
||||
- **Single binary**: ~8MB, starts in <10ms
|
||||
- **Minimal I/O**: Only touches files being managed
|
||||
- **Git efficiency**: Uses native Git commands, not libraries
|
||||
| Tool | Complexity | Why choose it |
|
||||
| ------- | ---------- | ------------------------------------- |
|
||||
| **lnk** | Minimal | Just works, no config, Git-native |
|
||||
| chezmoi | High | Templates, encryption, cross-platform |
|
||||
| yadm | Medium | Git power user, encryption |
|
||||
| dotbot | Low | YAML config, basic features |
|
||||
| stow | Low | Perl, symlink only |
|
||||
|
||||
## FAQ
|
||||
|
||||
<details>
|
||||
<summary><strong>How is this different from other dotfiles managers?</strong></summary>
|
||||
**Q: What if I already have dotfiles in Git?**
|
||||
A: `git clone your-repo ~/.config/lnk && lnk add ~/.vimrc` (adopts existing files)
|
||||
|
||||
| Tool | Stars | Approach | Complexity | Learning Curve | Git Integration | Cross-Platform | Key Strength |
|
||||
| ------------ | ----- | ------------------------ | ------------- | -------------- | --------------- | -------------- | ---------------------- |
|
||||
| **Lnk** | - | Simple symlinks + safety | **Minimal** | **Minutes** | **Native** | ✅ | **Safe simplicity** |
|
||||
| chezmoi | 15k | Templates + encryption | High | Hours/Days | Abstracted | ✅ | Feature completeness |
|
||||
| Mackup | 14.9k | App config sync | Medium | Hours | Manual | macOS/Linux | GUI app settings |
|
||||
| Home Manager | 8.1k | Declarative Nix | **Very High** | **Weeks** | Manual | Linux/macOS | Package + config unity |
|
||||
| Dotbot | 7.4k | YAML symlinks | Low | Minutes | Manual | ✅ | Pure simplicity |
|
||||
| yadm | 5.7k | Git wrapper | Medium | Hours | **Native** | Unix-like | Git-centric power |
|
||||
**Q: How do I handle machine-specific configs?**
|
||||
A: Git branches, or just don't manage machine-specific files with lnk
|
||||
|
||||
**Lnk fills the "safe simplicity" gap** – easier than chezmoi/yadm, safer than Dotbot, more capable than plain Git.
|
||||
**Q: Windows support?**
|
||||
A: Symlinks work on Windows 10+, but untested
|
||||
|
||||
</details>
|
||||
**Q: Production ready?**
|
||||
A: I use it daily. It won't break your files. API might change (pre-1.0).
|
||||
|
||||
<details>
|
||||
<summary><strong>Why choose Lnk over the alternatives?</strong></summary>
|
||||
|
||||
**Choose Lnk if you want:**
|
||||
|
||||
- ✅ **Safety first**: Bulletproof edge case handling, won't break existing setups
|
||||
- ✅ **Git-native workflow**: No abstractions, just clean commits with clear messages
|
||||
- ✅ **Zero learning curve**: 3 commands, works like Git, no configuration files
|
||||
- ✅ **Zero dependencies**: Single binary, no Python/Node/Ruby runtime requirements
|
||||
- ✅ **Production ready**: Comprehensive test suite, proper error handling
|
||||
|
||||
**Choose others if you need:**
|
||||
|
||||
- **chezmoi**: Heavy templating, password manager integration, Windows-first
|
||||
- **Mackup**: GUI app settings sync via Dropbox/iCloud (macOS focus)
|
||||
- **Home Manager**: Nix ecosystem, package management, declarative everything
|
||||
- **Dotbot**: Ultra-minimal YAML configuration (no safety features)
|
||||
- **yadm**: Git power user features, encryption, bare repo workflow
|
||||
|
||||
**The sweet spot**: Lnk is for developers who want dotfiles management **without the ceremony** – all the safety and Git integration you need, none of the complexity you don't.
|
||||
|
||||
</details>
|
||||
|
||||
<details>
|
||||
<summary><strong>When NOT to use Lnk?</strong></summary>
|
||||
|
||||
**Lnk might not be for you if you need:**
|
||||
|
||||
❌ **File templating**: Different configs per machine → use **chezmoi**
|
||||
❌ **Built-in encryption**: Secrets in dotfiles → use **chezmoi** or **yadm**
|
||||
❌ **GUI app settings**: Mac app preferences → use **Mackup**
|
||||
❌ **Package management**: Installing software → use **Home Manager** (Nix)
|
||||
❌ **Complex workflows**: Multi-step bootstrapping → use **chezmoi** or custom scripts
|
||||
❌ **Windows-first**: Native Windows support → use **chezmoi**
|
||||
|
||||
**Lnk's philosophy**: Do one thing (symlink management) extremely well, let other tools handle their specialties. You can always combine Lnk with other tools as needed.
|
||||
|
||||
</details>
|
||||
|
||||
<details>
|
||||
<summary><strong>What if I already have a dotfiles repo?</strong></summary>
|
||||
## Contributing
|
||||
|
||||
```bash
|
||||
# Clone your existing repo to the lnk location
|
||||
git clone your-repo ~/.config/lnk
|
||||
|
||||
# Lnk works with any Git repo structure
|
||||
lnk add ~/.vimrc # Adopts existing files safely
|
||||
git clone https://github.com/yarlson/lnk.git
|
||||
cd lnk
|
||||
make deps # Install golangci-lint
|
||||
make check # Runs fmt, vet, lint, test
|
||||
```
|
||||
|
||||
</details>
|
||||
**What we use:**
|
||||
|
||||
<details>
|
||||
<summary><strong>Is this production ready?</strong></summary>
|
||||
- **Runtime deps**: Only `cobra` (CLI framework)
|
||||
- **Test deps**: `testify` for assertions
|
||||
- **Build pipeline**: Standard Makefile with quality checks
|
||||
|
||||
**Yes, with caveats.** Lnk is thoroughly tested and handles edge cases well, but it's actively developed.
|
||||
|
||||
✅ **Safe to use**: Won't corrupt your files
|
||||
✅ **Well tested**: Comprehensive integration test suite
|
||||
⚠️ **API stability**: Commands may evolve (following semver)
|
||||
|
||||
**Recommendation**: Try it on non-critical dotfiles first.
|
||||
|
||||
</details>
|
||||
|
||||
## Development
|
||||
|
||||
### Quick Dev Setup
|
||||
**Before submitting:**
|
||||
|
||||
```bash
|
||||
git clone https://github.com/yarlson/lnk.git && cd lnk
|
||||
make test # Run integration tests
|
||||
make build # Build binary
|
||||
make dev # Watch & rebuild
|
||||
make check # Runs all quality checks + tests
|
||||
```
|
||||
|
||||
### Contributing
|
||||
**Adding features:**
|
||||
|
||||
We follow standard Go practices:
|
||||
|
||||
- **Tests first**: All features need integration tests
|
||||
- **Conventional commits**: `feat:`, `fix:`, `docs:`, etc.
|
||||
- **No dependencies**: Keep the runtime dependency-free
|
||||
- Put integration tests in `test/integration_test.go`
|
||||
- Use conventional commits: `feat:`, `fix:`, `docs:`
|
||||
|
||||
## License
|
||||
|
||||
MIT License - see [LICENSE](LICENSE) file for details.
|
||||
|
||||
---
|
||||
|
||||
**Made by developers, for developers.** Star ⭐ if this saves you time.
|
||||
[MIT](LICENSE)
|
||||
|
@@ -15,15 +15,12 @@ var initCmd = &cobra.Command{
|
||||
remote, _ := cmd.Flags().GetString("remote")
|
||||
|
||||
lnk := core.NewLnk()
|
||||
if err := lnk.Init(); err != nil {
|
||||
if err := lnk.InitWithRemote(remote); err != nil {
|
||||
return fmt.Errorf("failed to initialize lnk: %w", err)
|
||||
}
|
||||
|
||||
if remote != "" {
|
||||
if err := lnk.AddRemote("origin", remote); err != nil {
|
||||
return fmt.Errorf("failed to add remote: %w", err)
|
||||
}
|
||||
fmt.Printf("Initialized lnk repository with remote: %s\n", remote)
|
||||
fmt.Printf("Initialized lnk repository by cloning: %s\n", remote)
|
||||
} else {
|
||||
fmt.Println("Initialized lnk repository")
|
||||
}
|
||||
@@ -33,6 +30,6 @@ var initCmd = &cobra.Command{
|
||||
}
|
||||
|
||||
func init() {
|
||||
initCmd.Flags().StringP("remote", "r", "", "Add origin remote URL to the repository")
|
||||
initCmd.Flags().StringP("remote", "r", "", "Clone from remote URL instead of creating empty repository")
|
||||
rootCmd.AddCommand(initCmd)
|
||||
}
|
||||
|
@@ -45,6 +45,16 @@ func getRepoPath() string {
|
||||
|
||||
// Init initializes the lnk repository
|
||||
func (l *Lnk) Init() error {
|
||||
return l.InitWithRemote("")
|
||||
}
|
||||
|
||||
// InitWithRemote initializes the lnk repository, optionally cloning from a remote
|
||||
func (l *Lnk) InitWithRemote(remoteURL string) error {
|
||||
if remoteURL != "" {
|
||||
// Clone from remote
|
||||
return l.Clone(remoteURL)
|
||||
}
|
||||
|
||||
// Create the repository directory
|
||||
if err := os.MkdirAll(l.repoPath, 0755); err != nil {
|
||||
return fmt.Errorf("failed to create lnk directory: %w", err)
|
||||
@@ -70,6 +80,14 @@ func (l *Lnk) Init() error {
|
||||
return nil
|
||||
}
|
||||
|
||||
// Clone clones a repository from the given URL
|
||||
func (l *Lnk) Clone(url string) error {
|
||||
if err := l.git.Clone(url); err != nil {
|
||||
return fmt.Errorf("failed to clone repository: %w", err)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// AddRemote adds a remote to the repository
|
||||
func (l *Lnk) AddRemote(name, url string) error {
|
||||
if err := l.git.AddRemote(name, url); err != nil {
|
||||
|
@@ -457,3 +457,43 @@ func (g *Git) Pull() error {
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// Clone clones a repository from the given URL
|
||||
func (g *Git) Clone(url string) error {
|
||||
// Remove the directory if it exists to ensure clean clone
|
||||
if err := os.RemoveAll(g.repoPath); err != nil {
|
||||
return fmt.Errorf("failed to remove existing directory: %w", err)
|
||||
}
|
||||
|
||||
// Create parent directory
|
||||
parentDir := filepath.Dir(g.repoPath)
|
||||
if err := os.MkdirAll(parentDir, 0755); err != nil {
|
||||
return fmt.Errorf("failed to create parent directory: %w", err)
|
||||
}
|
||||
|
||||
// Clone the repository
|
||||
cmd := exec.Command("git", "clone", url, g.repoPath)
|
||||
output, err := cmd.CombinedOutput()
|
||||
if err != nil {
|
||||
return fmt.Errorf("git clone failed: %w\nOutput: %s", err, string(output))
|
||||
}
|
||||
|
||||
// Set up upstream tracking for main branch
|
||||
cmd = exec.Command("git", "branch", "--set-upstream-to=origin/main", "main")
|
||||
cmd.Dir = g.repoPath
|
||||
_, err = cmd.CombinedOutput()
|
||||
if err != nil {
|
||||
// If main doesn't exist, try master
|
||||
cmd = exec.Command("git", "branch", "--set-upstream-to=origin/master", "master")
|
||||
cmd.Dir = g.repoPath
|
||||
_, err = cmd.CombinedOutput()
|
||||
if err != nil {
|
||||
// If that also fails, try to set upstream for current branch
|
||||
cmd = exec.Command("git", "branch", "--set-upstream-to=origin/HEAD")
|
||||
cmd.Dir = g.repoPath
|
||||
_, _ = cmd.CombinedOutput() // Ignore error as this is best effort
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
Reference in New Issue
Block a user