blob: 18ccc1f15f30016fd10e6e5b628ba9ee048ea138 [file] [log] [blame] [view]
iomodo5a7e4e72025-07-25 13:21:41 +04001# Git Interface for Go
2
3A comprehensive Go interface for Git operations that provides a clean, type-safe API for interacting with Git repositories.
4
5## Features
6
7- **Complete Git Operations**: Supports all major Git operations including repository management, commits, branches, remotes, tags, and more
8- **Type-Safe API**: Strongly typed interfaces and structs for better code safety
9- **Context Support**: All operations support context for cancellation and timeouts
10- **Error Handling**: Comprehensive error handling with detailed error messages
11- **Flexible Configuration**: Configurable timeouts and environment variables
12- **Easy to Use**: Simple and intuitive API design
13
14## Installation
15
16The Git interface is part of the `github.com/iomodo/staff` module. No additional dependencies are required beyond the standard library.
17
18## Quick Start
19
20```go
21package main
22
23import (
24 "context"
25 "fmt"
26 "log"
27
28 "github.com/iomodo/staff/git"
29)
30
31func main() {
32 ctx := context.Background()
33
34 // Create a Git instance
35 git := git.DefaultGit("/path/to/your/repo")
36
37 // Open an existing repository
38 if err := git.Open(ctx, "/path/to/your/repo"); err != nil {
39 log.Fatalf("Failed to open repository: %v", err)
40 }
41
42 // Get repository status
43 status, err := git.Status(ctx)
44 if err != nil {
45 log.Fatalf("Failed to get status: %v", err)
46 }
47
48 fmt.Printf("Current branch: %s\n", status.Branch)
49 fmt.Printf("Repository is clean: %t\n", status.IsClean)
50}
51```
52
53## Core Interface
54
55### GitInterface
56
57The main interface that defines all Git operations:
58
59```go
60type GitInterface interface {
61 // Repository operations
62 Init(ctx context.Context, path string) error
63 Clone(ctx context.Context, url, path string) error
64 IsRepository(ctx context.Context, path string) (bool, error)
65
66 // Status and information
67 Status(ctx context.Context) (*Status, error)
68 Log(ctx context.Context, options LogOptions) ([]Commit, error)
69 Show(ctx context.Context, ref string) (*Commit, error)
70
71 // Branch operations
72 ListBranches(ctx context.Context) ([]Branch, error)
73 CreateBranch(ctx context.Context, name string, startPoint string) error
74 Checkout(ctx context.Context, ref string) error
75 DeleteBranch(ctx context.Context, name string, force bool) error
76 GetCurrentBranch(ctx context.Context) (string, error)
77
78 // Commit operations
79 Add(ctx context.Context, paths []string) error
80 AddAll(ctx context.Context) error
81 Commit(ctx context.Context, message string, options CommitOptions) error
82
83 // Remote operations
84 ListRemotes(ctx context.Context) ([]Remote, error)
85 AddRemote(ctx context.Context, name, url string) error
86 RemoveRemote(ctx context.Context, name string) error
87 Fetch(ctx context.Context, remote string, options FetchOptions) error
88 Pull(ctx context.Context, remote, branch string) error
89 Push(ctx context.Context, remote, branch string, options PushOptions) error
90
91 // Merge operations
92 Merge(ctx context.Context, ref string, options MergeOptions) error
93 MergeBase(ctx context.Context, ref1, ref2 string) (string, error)
94
95 // Configuration
96 GetConfig(ctx context.Context, key string) (string, error)
97 SetConfig(ctx context.Context, key, value string) error
98 GetUserConfig(ctx context.Context) (*UserConfig, error)
99 SetUserConfig(ctx context.Context, config UserConfig) error
100}
101```
102
103## Data Structures
104
105### Status
106
107Represents the current state of the repository:
108
109```go
110type Status struct {
111 Branch string
112 IsClean bool
113 Staged []FileStatus
114 Unstaged []FileStatus
115 Untracked []string
116 Conflicts []string
117}
118```
119
120### Commit
121
122Represents a Git commit:
123
124```go
125type Commit struct {
126 Hash string
127 Author Author
128 Committer Author
129 Message string
130 Parents []string
131 Timestamp time.Time
132 Files []CommitFile
133}
134```
135
136### Branch
137
138Represents a Git branch:
139
140```go
141type Branch struct {
142 Name string
143 IsCurrent bool
144 IsRemote bool
145 Commit string
146 Message string
147}
148```
149
150## Usage Examples
151
152### Repository Management
153
154```go
155// Initialize a new repository
156git := git.DefaultGit("/path/to/new/repo")
157if err := git.Init(ctx, "/path/to/new/repo"); err != nil {
158 log.Fatal(err)
159}
160
161// Clone a repository
162if err := git.Clone(ctx, "https://github.com/user/repo.git", "/path/to/clone"); err != nil {
163 log.Fatal(err)
164}
165```
166
167### Basic Git Workflow
168
169```go
170// Stage files
171if err := git.Add(ctx, []string{"file1.txt", "file2.txt"}); err != nil {
172 log.Fatal(err)
173}
174
175// Or stage all changes
176if err := git.AddAll(ctx); err != nil {
177 log.Fatal(err)
178}
179
180// Commit changes
181commitOptions := git.CommitOptions{
182 AllowEmpty: false,
183}
184if err := git.Commit(ctx, "Add new feature", commitOptions); err != nil {
185 log.Fatal(err)
186}
187```
188
189### Branch Operations
190
191```go
192// List all branches
193branches, err := git.ListBranches(ctx)
194if err != nil {
195 log.Fatal(err)
196}
197
198for _, branch := range branches {
199 fmt.Printf("Branch: %s (current: %t)\n", branch.Name, branch.IsCurrent)
200}
201
202// Create a new branch
203if err := git.CreateBranch(ctx, "feature/new-feature", ""); err != nil {
204 log.Fatal(err)
205}
206
207// Switch to a branch
208if err := git.Checkout(ctx, "feature/new-feature"); err != nil {
209 log.Fatal(err)
210}
211
212// Get current branch
213currentBranch, err := git.GetCurrentBranch(ctx)
214if err != nil {
215 log.Fatal(err)
216}
217fmt.Printf("Current branch: %s\n", currentBranch)
218```
219
220### Remote Operations
221
222```go
223// Add a remote
224if err := git.AddRemote(ctx, "origin", "https://github.com/user/repo.git"); err != nil {
225 log.Fatal(err)
226}
227
228// List remotes
229remotes, err := git.ListRemotes(ctx)
230if err != nil {
231 log.Fatal(err)
232}
233
234for _, remote := range remotes {
235 fmt.Printf("Remote: %s -> %s\n", remote.Name, remote.URL)
236}
237
238// Fetch from remote
239fetchOptions := git.FetchOptions{
240 All: true,
241 Tags: true,
242}
243if err := git.Fetch(ctx, "", fetchOptions); err != nil {
244 log.Fatal(err)
245}
246
247// Push to remote
248pushOptions := git.PushOptions{
249 SetUpstream: true,
250}
251if err := git.Push(ctx, "origin", "main", pushOptions); err != nil {
252 log.Fatal(err)
253}
254```
255
256### Configuration
257
258```go
259// Get user configuration
260userConfig, err := git.GetUserConfig(ctx)
261if err != nil {
262 log.Fatal(err)
263}
264fmt.Printf("User: %s <%s>\n", userConfig.Name, userConfig.Email)
265
266// Set user configuration
267newConfig := git.UserConfig{
268 Name: "John Doe",
269 Email: "john@example.com",
270}
271if err := git.SetUserConfig(ctx, newConfig); err != nil {
272 log.Fatal(err)
273}
274
275// Get/set custom config
276value, err := git.GetConfig(ctx, "core.editor")
277if err != nil {
278 log.Fatal(err)
279}
280
281if err := git.SetConfig(ctx, "core.editor", "vim"); err != nil {
282 log.Fatal(err)
283}
284```
285
286## Error Handling
287
288The Git interface provides detailed error information through the `GitError` type:
289
290```go
291if err := git.Commit(ctx, "Invalid commit", git.CommitOptions{}); err != nil {
292 if gitErr, ok := err.(*git.GitError); ok {
293 fmt.Printf("Git command '%s' failed: %v\n", gitErr.Command, gitErr.Err)
294 fmt.Printf("Output: %s\n", gitErr.Output)
295 }
296}
297```
298
299## Configuration
300
301You can customize the Git instance with specific configuration:
302
303```go
304config := git.GitConfig{
305 Timeout: 60 * time.Second,
306 Env: map[string]string{
307 "GIT_AUTHOR_NAME": "Custom Author",
308 "GIT_AUTHOR_EMAIL": "author@example.com",
309 },
310}
311
312git := git.NewGit("/path/to/repo", config)
313```
314
315## Thread Safety
316
317The Git interface is not thread-safe. If you need to use it from multiple goroutines, you should either:
318
3191. Use separate Git instances for each goroutine
3202. Use a mutex to synchronize access
3213. Use channels to serialize operations
322
323## Requirements
324
325- Go 1.24.4 or later
326- Git installed and available in PATH
327- Appropriate permissions to access the repository
328
329## License
330
331This code is part of the `github.com/iomodo/staff` project and follows the same license terms.