Add git implementation
Change-Id: I3bb5986fe244b310038b7b2ec4359d8439a158de
diff --git a/server/git/README.md b/server/git/README.md
new file mode 100644
index 0000000..18ccc1f
--- /dev/null
+++ b/server/git/README.md
@@ -0,0 +1,331 @@
+# Git Interface for Go
+
+A comprehensive Go interface for Git operations that provides a clean, type-safe API for interacting with Git repositories.
+
+## Features
+
+- **Complete Git Operations**: Supports all major Git operations including repository management, commits, branches, remotes, tags, and more
+- **Type-Safe API**: Strongly typed interfaces and structs for better code safety
+- **Context Support**: All operations support context for cancellation and timeouts
+- **Error Handling**: Comprehensive error handling with detailed error messages
+- **Flexible Configuration**: Configurable timeouts and environment variables
+- **Easy to Use**: Simple and intuitive API design
+
+## Installation
+
+The Git interface is part of the `github.com/iomodo/staff` module. No additional dependencies are required beyond the standard library.
+
+## Quick Start
+
+```go
+package main
+
+import (
+ "context"
+ "fmt"
+ "log"
+
+ "github.com/iomodo/staff/git"
+)
+
+func main() {
+ ctx := context.Background()
+
+ // Create a Git instance
+ git := git.DefaultGit("/path/to/your/repo")
+
+ // Open an existing repository
+ if err := git.Open(ctx, "/path/to/your/repo"); err != nil {
+ log.Fatalf("Failed to open repository: %v", err)
+ }
+
+ // Get repository status
+ status, err := git.Status(ctx)
+ if err != nil {
+ log.Fatalf("Failed to get status: %v", err)
+ }
+
+ fmt.Printf("Current branch: %s\n", status.Branch)
+ fmt.Printf("Repository is clean: %t\n", status.IsClean)
+}
+```
+
+## Core Interface
+
+### GitInterface
+
+The main interface that defines all Git operations:
+
+```go
+type GitInterface interface {
+ // Repository operations
+ Init(ctx context.Context, path string) error
+ Clone(ctx context.Context, url, path string) error
+ IsRepository(ctx context.Context, path string) (bool, error)
+
+ // Status and information
+ Status(ctx context.Context) (*Status, error)
+ Log(ctx context.Context, options LogOptions) ([]Commit, error)
+ Show(ctx context.Context, ref string) (*Commit, error)
+
+ // Branch operations
+ ListBranches(ctx context.Context) ([]Branch, error)
+ CreateBranch(ctx context.Context, name string, startPoint string) error
+ Checkout(ctx context.Context, ref string) error
+ DeleteBranch(ctx context.Context, name string, force bool) error
+ GetCurrentBranch(ctx context.Context) (string, error)
+
+ // Commit operations
+ Add(ctx context.Context, paths []string) error
+ AddAll(ctx context.Context) error
+ Commit(ctx context.Context, message string, options CommitOptions) error
+
+ // Remote operations
+ ListRemotes(ctx context.Context) ([]Remote, error)
+ AddRemote(ctx context.Context, name, url string) error
+ RemoveRemote(ctx context.Context, name string) error
+ Fetch(ctx context.Context, remote string, options FetchOptions) error
+ Pull(ctx context.Context, remote, branch string) error
+ Push(ctx context.Context, remote, branch string, options PushOptions) error
+
+ // Merge operations
+ Merge(ctx context.Context, ref string, options MergeOptions) error
+ MergeBase(ctx context.Context, ref1, ref2 string) (string, error)
+
+ // Configuration
+ GetConfig(ctx context.Context, key string) (string, error)
+ SetConfig(ctx context.Context, key, value string) error
+ GetUserConfig(ctx context.Context) (*UserConfig, error)
+ SetUserConfig(ctx context.Context, config UserConfig) error
+}
+```
+
+## Data Structures
+
+### Status
+
+Represents the current state of the repository:
+
+```go
+type Status struct {
+ Branch string
+ IsClean bool
+ Staged []FileStatus
+ Unstaged []FileStatus
+ Untracked []string
+ Conflicts []string
+}
+```
+
+### Commit
+
+Represents a Git commit:
+
+```go
+type Commit struct {
+ Hash string
+ Author Author
+ Committer Author
+ Message string
+ Parents []string
+ Timestamp time.Time
+ Files []CommitFile
+}
+```
+
+### Branch
+
+Represents a Git branch:
+
+```go
+type Branch struct {
+ Name string
+ IsCurrent bool
+ IsRemote bool
+ Commit string
+ Message string
+}
+```
+
+## Usage Examples
+
+### Repository Management
+
+```go
+// Initialize a new repository
+git := git.DefaultGit("/path/to/new/repo")
+if err := git.Init(ctx, "/path/to/new/repo"); err != nil {
+ log.Fatal(err)
+}
+
+// Clone a repository
+if err := git.Clone(ctx, "https://github.com/user/repo.git", "/path/to/clone"); err != nil {
+ log.Fatal(err)
+}
+```
+
+### Basic Git Workflow
+
+```go
+// Stage files
+if err := git.Add(ctx, []string{"file1.txt", "file2.txt"}); err != nil {
+ log.Fatal(err)
+}
+
+// Or stage all changes
+if err := git.AddAll(ctx); err != nil {
+ log.Fatal(err)
+}
+
+// Commit changes
+commitOptions := git.CommitOptions{
+ AllowEmpty: false,
+}
+if err := git.Commit(ctx, "Add new feature", commitOptions); err != nil {
+ log.Fatal(err)
+}
+```
+
+### Branch Operations
+
+```go
+// List all branches
+branches, err := git.ListBranches(ctx)
+if err != nil {
+ log.Fatal(err)
+}
+
+for _, branch := range branches {
+ fmt.Printf("Branch: %s (current: %t)\n", branch.Name, branch.IsCurrent)
+}
+
+// Create a new branch
+if err := git.CreateBranch(ctx, "feature/new-feature", ""); err != nil {
+ log.Fatal(err)
+}
+
+// Switch to a branch
+if err := git.Checkout(ctx, "feature/new-feature"); err != nil {
+ log.Fatal(err)
+}
+
+// Get current branch
+currentBranch, err := git.GetCurrentBranch(ctx)
+if err != nil {
+ log.Fatal(err)
+}
+fmt.Printf("Current branch: %s\n", currentBranch)
+```
+
+### Remote Operations
+
+```go
+// Add a remote
+if err := git.AddRemote(ctx, "origin", "https://github.com/user/repo.git"); err != nil {
+ log.Fatal(err)
+}
+
+// List remotes
+remotes, err := git.ListRemotes(ctx)
+if err != nil {
+ log.Fatal(err)
+}
+
+for _, remote := range remotes {
+ fmt.Printf("Remote: %s -> %s\n", remote.Name, remote.URL)
+}
+
+// Fetch from remote
+fetchOptions := git.FetchOptions{
+ All: true,
+ Tags: true,
+}
+if err := git.Fetch(ctx, "", fetchOptions); err != nil {
+ log.Fatal(err)
+}
+
+// Push to remote
+pushOptions := git.PushOptions{
+ SetUpstream: true,
+}
+if err := git.Push(ctx, "origin", "main", pushOptions); err != nil {
+ log.Fatal(err)
+}
+```
+
+### Configuration
+
+```go
+// Get user configuration
+userConfig, err := git.GetUserConfig(ctx)
+if err != nil {
+ log.Fatal(err)
+}
+fmt.Printf("User: %s <%s>\n", userConfig.Name, userConfig.Email)
+
+// Set user configuration
+newConfig := git.UserConfig{
+ Name: "John Doe",
+ Email: "john@example.com",
+}
+if err := git.SetUserConfig(ctx, newConfig); err != nil {
+ log.Fatal(err)
+}
+
+// Get/set custom config
+value, err := git.GetConfig(ctx, "core.editor")
+if err != nil {
+ log.Fatal(err)
+}
+
+if err := git.SetConfig(ctx, "core.editor", "vim"); err != nil {
+ log.Fatal(err)
+}
+```
+
+## Error Handling
+
+The Git interface provides detailed error information through the `GitError` type:
+
+```go
+if err := git.Commit(ctx, "Invalid commit", git.CommitOptions{}); err != nil {
+ if gitErr, ok := err.(*git.GitError); ok {
+ fmt.Printf("Git command '%s' failed: %v\n", gitErr.Command, gitErr.Err)
+ fmt.Printf("Output: %s\n", gitErr.Output)
+ }
+}
+```
+
+## Configuration
+
+You can customize the Git instance with specific configuration:
+
+```go
+config := git.GitConfig{
+ Timeout: 60 * time.Second,
+ Env: map[string]string{
+ "GIT_AUTHOR_NAME": "Custom Author",
+ "GIT_AUTHOR_EMAIL": "author@example.com",
+ },
+}
+
+git := git.NewGit("/path/to/repo", config)
+```
+
+## Thread Safety
+
+The Git interface is not thread-safe. If you need to use it from multiple goroutines, you should either:
+
+1. Use separate Git instances for each goroutine
+2. Use a mutex to synchronize access
+3. Use channels to serialize operations
+
+## Requirements
+
+- Go 1.24.4 or later
+- Git installed and available in PATH
+- Appropriate permissions to access the repository
+
+## License
+
+This code is part of the `github.com/iomodo/staff` project and follows the same license terms.
\ No newline at end of file