Files
gitlocal/internal/git/git.go
Daniel Tomlinson b5f1495680 Adds initial gitlocal CLI and core functionality
Introduces the `gitlocal` command-line tool for managing nested Git repositories.

Includes the following main commands:
- `convert`: Renames `.git` to `.gitlocal`, allowing a parent repository to ignore the converted child repository. Supports recursive scanning and dry-run options. Tracks converted repositories in a global configuration.
- `revert`: Restores `.gitlocal` to `.git`. Includes an option to revert all tracked repositories.
- `status`: Displays a list of all repositories currently tracked by `gitlocal`, showing their path, conversion time, and original remote/branch.

Establishes internal modules for Git operations, configuration management, and recursive repository scanning.
Adds a comprehensive test suite covering core command logic and utility functions.
Initializes Go module and basic project `.gitignore`.
2026-04-11 14:48:01 +01:00

95 lines
2.1 KiB
Go

package git
import (
"fmt"
"os"
"os/exec"
"path/filepath"
"strings"
)
const (
GitDir = ".git"
GitLocalDir = ".gitlocal"
)
// IsGitRepo checks if the path contains a .git directory
func IsGitRepo(path string) bool {
gitPath := filepath.Join(path, GitDir)
info, err := os.Stat(gitPath)
if err != nil {
return false
}
return info.IsDir()
}
// IsGitLocalRepo checks if the path contains a .gitlocal directory
func IsGitLocalRepo(path string) bool {
gitLocalPath := filepath.Join(path, GitLocalDir)
info, err := os.Stat(gitLocalPath)
if err != nil {
return false
}
return info.IsDir()
}
// GetRemoteURL returns the remote URL for the git repo
func GetRemoteURL(gitDir string) string {
cmd := exec.Command("git", "--git-dir", gitDir, "remote", "get-url", "origin")
output, err := cmd.Output()
if err != nil {
return ""
}
return strings.TrimSpace(string(output))
}
// GetCurrentBranch returns the current branch for the git repo
func GetCurrentBranch(gitDir string) string {
cmd := exec.Command("git", "--git-dir", gitDir, "branch", "--show-current")
output, err := cmd.Output()
if err != nil {
return ""
}
return strings.TrimSpace(string(output))
}
// Convert renames .git to .gitlocal
func Convert(path string) error {
gitPath := filepath.Join(path, GitDir)
gitLocalPath := filepath.Join(path, GitLocalDir)
if !IsGitRepo(path) {
return fmt.Errorf("no .git directory found at %s", path)
}
if IsGitLocalRepo(path) {
return fmt.Errorf(".gitlocal already exists at %s", path)
}
if err := os.Rename(gitPath, gitLocalPath); err != nil {
return fmt.Errorf("failed to rename .git to .gitlocal: %w", err)
}
return nil
}
// Revert renames .gitlocal back to .git
func Revert(path string) error {
gitPath := filepath.Join(path, GitDir)
gitLocalPath := filepath.Join(path, GitLocalDir)
if !IsGitLocalRepo(path) {
return fmt.Errorf("no .gitlocal directory found at %s", path)
}
if IsGitRepo(path) {
return fmt.Errorf(".git already exists at %s", path)
}
if err := os.Rename(gitLocalPath, gitPath); err != nil {
return fmt.Errorf("failed to rename .gitlocal to .git: %w", err)
}
return nil
}