0
# Git Operations
1
2
Comprehensive git integration for working with staged files, status checking, and repository operations within hooks. This API provides all necessary functionality for plugins to interact with git repositories and manage file staging.
3
4
## Capabilities
5
6
### Git Status Operations
7
8
Retrieve and analyze git status information for files in the repository with support for filtering and status type checking.
9
10
```python { .api }
11
def get_status(files: Optional[Iterable[PathLike]] = None) -> List[StatusEntry]:
12
"""
13
Get information about the current git status.
14
15
Args:
16
files: (optional) specify an iterable of PathLike and exclude all other paths
17
18
Returns:
19
A list of StatusEntry instances that contain the status of the specific files
20
"""
21
22
def get_staged_status(files: Optional[Iterable[PathLike]] = None) -> List[StatusEntry]:
23
"""
24
Get a list of StatusEntry instances containing only staged files.
25
26
Args:
27
files: (optional) specify an iterable of files and exclude all other paths
28
29
Returns:
30
A list of StatusEntry instances with files that are staged
31
"""
32
33
def is_staged_status(status: StatusEntry) -> bool:
34
"""
35
Returns true, if the status of the given StatusEntry is staged.
36
37
Args:
38
status: A StatusEntry object that contains the filename, path and git status
39
40
Returns:
41
True if file is staged, False else
42
"""
43
44
def is_partially_staged_status(status: StatusEntry) -> bool:
45
"""
46
Returns true, if the status of the given StatusEntry is partially staged.
47
48
Args:
49
status: A StatusEntry object that contains the filename, path and git status
50
51
Returns:
52
True if file is partially staged, False else
53
"""
54
```
55
56
**Usage Examples:**
57
58
```python
59
from autohooks.api.git import get_status, get_staged_status, is_staged_status
60
61
def precommit(config, report_progress, **kwargs):
62
# Get all file status
63
all_status = get_status()
64
65
# Get only staged files
66
staged_files = get_staged_status()
67
68
# Filter for specific file types
69
python_files = []
70
for status_entry in staged_files:
71
if status_entry.path.suffix == '.py':
72
python_files.append(status_entry)
73
74
# Check if specific files are staged
75
for status_entry in all_status:
76
if is_staged_status(status_entry):
77
print(f"Staged: {status_entry.path}")
78
```
79
80
### File Staging Operations
81
82
Add files to the git staging index with support for different input types and batch operations.
83
84
```python { .api }
85
def stage_files(files: Iterable[PathLike]) -> None:
86
"""
87
Add the passed PathLike to git staging index.
88
89
Args:
90
files: An iterable of PathLike to add to the index
91
"""
92
93
def stage_files_from_status_list(status_list: Iterable[StatusEntry]) -> None:
94
"""
95
Add the passed files from the status list to git staging index.
96
97
Deprecated. Please use stage_files instead.
98
99
Args:
100
status_list: A List of StatusEntry instances that should be added
101
"""
102
```
103
104
**Usage Examples:**
105
106
```python
107
from autohooks.api.git import get_staged_status, stage_files
108
from pathlib import Path
109
110
def precommit(config, report_progress, **kwargs):
111
# Get staged files
112
staged_files = get_staged_status()
113
114
# Process and potentially modify files
115
modified_files = []
116
for status_entry in staged_files:
117
if process_file(status_entry.absolute_path()):
118
modified_files.append(status_entry.path)
119
120
# Re-stage modified files
121
if modified_files:
122
stage_files(modified_files)
123
```
124
125
### Git Command Execution
126
127
Execute git commands directly with error handling and output capture.
128
129
```python { .api }
130
def exec_git(*args: str, ignore_errors: bool = False) -> str:
131
"""
132
Execute git command.
133
134
Args:
135
*args: Variable length argument list passed to git
136
ignore_errors: Ignore errors if git command fails. Default: False
137
138
Returns:
139
Command output as string
140
141
Raises:
142
GitError: A GitError is raised if the git commit fails and ignore_errors is False
143
"""
144
145
def get_diff(files: Optional[Iterable[StatusEntry]] = None) -> str:
146
"""
147
Get the diff of the passed files.
148
149
Args:
150
files: A List of StatusEntry instances that should be diffed
151
152
Returns:
153
String containing the diff of the given files
154
"""
155
156
class GitError(subprocess.CalledProcessError):
157
"""
158
Error raised if a git command fails.
159
"""
160
```
161
162
**Usage Examples:**
163
164
```python
165
from autohooks.api.git import exec_git, get_diff, GitError
166
167
def precommit(config, report_progress, **kwargs):
168
try:
169
# Get current branch
170
branch = exec_git("rev-parse", "--abbrev-ref", "HEAD").strip()
171
172
# Get diff for staged files
173
diff_output = get_diff()
174
175
if "TODO" in diff_output:
176
warning("Found TODO comments in staged changes")
177
178
except GitError as e:
179
error(f"Git command failed: {e}")
180
return 1
181
```
182
183
### Unstaged Changes Management
184
185
Context manager for temporarily stashing unstaged changes during plugin execution to avoid conflicts.
186
187
```python { .api }
188
class stash_unstaged_changes:
189
"""
190
A context manager that stashes changes that:
191
- are not staged, and
192
- affect files that are partially staged.
193
194
Changes that are made before the context manager exits, are added to the index.
195
The stashed changes are restored when the context manager exits.
196
"""
197
198
def __init__(self, files: Optional[Iterable[PathLike]] = None) -> None:
199
"""
200
Args:
201
files: Optional iterable of path like objects to consider for being staged.
202
By default all files in the git status are considered.
203
"""
204
```
205
206
**Usage Examples:**
207
208
```python
209
from autohooks.api.git import stash_unstaged_changes, get_staged_status
210
211
def precommit(config, report_progress, **kwargs):
212
staged_files = get_staged_status()
213
214
# Stash unstaged changes while processing
215
with stash_unstaged_changes():
216
# Format staged files - unstaged changes are temporarily stashed
217
for status_entry in staged_files:
218
format_file(status_entry.absolute_path())
219
220
# Stage the formatted changes
221
stage_files([entry.path for entry in staged_files])
222
223
# Unstaged changes are restored here
224
return 0
225
```
226
227
### Status Entry Information
228
229
Detailed information about file status in git with path resolution and status checking.
230
231
```python { .api }
232
class StatusEntry:
233
"""
234
Status of a file in the git index and working tree.
235
Implements the os.PathLike protocol.
236
237
Attributes:
238
index: Status in the index
239
working_tree: Status in the working tree
240
path: Path to the file
241
root_path: An optional path to a root directory
242
old_path: Set for renamed files
243
"""
244
245
def __init__(self, status_string: str, root_path: Optional[Path] = None) -> None:
246
"""
247
Create StatusEntry from git status string.
248
249
Args:
250
status_string: Git status format string
251
root_path: Optional root path for resolution
252
"""
253
254
def absolute_path(self) -> Path:
255
"""
256
Returns the absolute path of the file of this StatusEntry.
257
"""
258
259
def __str__(self) -> str:
260
"""String representation showing status and path."""
261
262
def __fspath__(self):
263
"""PathLike protocol implementation."""
264
265
class Status(Enum):
266
"""
267
Status of a file in git.
268
"""
269
UNMODIFIED = " "
270
MODIFIED = "M"
271
ADDED = "A"
272
DELETED = "D"
273
RENAMED = "R"
274
COPIED = "C"
275
UPDATED = "U"
276
UNTRACKED = "?"
277
IGNORED = "!"
278
```
279
280
**Usage Examples:**
281
282
```python
283
from autohooks.api.git import get_staged_status, Status
284
285
def precommit(config, report_progress, **kwargs):
286
staged_files = get_staged_status()
287
288
for status_entry in staged_files:
289
print(f"File: {status_entry.path}")
290
print(f"Absolute path: {status_entry.absolute_path()}")
291
print(f"Index status: {status_entry.index}")
292
print(f"Working tree status: {status_entry.working_tree}")
293
294
# Check for specific status
295
if status_entry.index == Status.MODIFIED:
296
print("File is modified in index")
297
elif status_entry.index == Status.ADDED:
298
print("File is newly added")
299
300
# Handle renamed files
301
if hasattr(status_entry, 'old_path'):
302
print(f"Renamed from: {status_entry.old_path}")
303
```
304
305
## Types
306
307
```python { .api }
308
from pathlib import Path
309
from typing import Iterable, List, Optional
310
from os import PathLike
311
from enum import Enum
312
import subprocess
313
```