1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
from enum import Enum
from typing import Optional
import pygit2
class HookResult(Enum):
SUCCESS = 0
FAILURE = 1
class Hook(object):
def __init__(self, repo: pygit2.Repository):
self.repo = repo
"""
Pre-Commit Hook (Client-side)
Runs before a commit is made, before a commit message is written (if not supplied by -m).
Use this hook to:
- Check for uncommitted changes
- Run tests, lints, security checks, etc.
This can be bypassed with --no-verify by the user.
"""
class PreCommit(Hook):
def __init__(self, repo: pygit2.Repository):
super().__init__(repo)
def run(self) -> HookResult:
return HookResult.SUCCESS
"""
Prepare-Commit-Msg Hook (Client-side)
Runs right after the default log message is prepared and before the editor is started.
Use this hook to:
- Edit the message file in place (e.g. strip template comments)
- Insert a standard prefix/suffix (e.g. branch name, ticket ID)
- Add Signed-off-by from a template
Takes 1–3 parameters: message file path, source (message|template|merge|squash|commit), and optionally commit hash for amend.
"""
class PrepareCommitMsg(Hook):
def __init__(self, repo: pygit2.Repository):
super().__init__(repo)
def run(
self,
message_file: str,
source: str = "",
commit_hash: Optional[str] = None,
) -> HookResult:
return HookResult.SUCCESS
"""
Commit-Msg Hook (Client-side)
Runs after the commit message is prepared; can be bypassed with --no-verify.
Use this hook to:
- Enforce a project standard format (e.g. conventional commits)
- Validate or normalize the message in place
- Reject the commit (e.g. duplicate Signed-off-by, missing ticket reference)
Takes one parameter: the path to the file holding the proposed commit log message.
"""
class CommitMsg(Hook):
def __init__(self, repo: pygit2.Repository):
super().__init__(repo)
def run(self, message_file: str) -> HookResult:
return HookResult.SUCCESS
"""
Post-Commit Hook (Client-side)
Runs after a commit is made. Cannot affect the outcome of git commit.
Use this hook to:
- Notify (e.g. log, webhook, chat)
- Run post-commit checks or backups
- Update external metadata or caches
"""
class PostCommit(Hook):
def __init__(self, repo: pygit2.Repository):
super().__init__(repo)
def run(self) -> HookResult:
return HookResult.SUCCESS
"""
Pre-Merge-Commit Hook (Client-side)
Runs after a merge has been carried out successfully and before the merge commit message is finalized; can be bypassed with --no-verify.
Use this hook to:
- Validate the merged tree (e.g. run tests on the result)
- Inspect or adjust the merge commit message
- Abort the merge commit if checks fail
Takes no parameters.
"""
class PreMergeCommit(Hook):
def __init__(self, repo: pygit2.Repository):
super().__init__(repo)
def run(self) -> HookResult:
return HookResult.SUCCESS
"""
Pre-Rebase Hook (Client-side)
Called by git rebase; can be used to prevent a branch from being rebased.
Use this hook to:
- Block rebasing certain branches (e.g. main)
- Run checks before rewriting history
Takes one or two parameters: upstream ref, and optionally the branch being rebased (absent when rebasing the current branch).
"""
class PreRebase(Hook):
def __init__(self, repo: pygit2.Repository):
super().__init__(repo)
def run(self, upstream: str, branch: Optional[str] = None) -> HookResult:
return HookResult.SUCCESS
"""
Post-Checkout Hook (Client-side)
Runs after git checkout, git switch, or git clone (when a worktree is updated).
Use this hook to:
- Restore working tree metadata (e.g. permissions, ACLs)
- Auto-display differences from the previous HEAD
- Run repository validity checks or refresh generated files
Takes three parameters: previous HEAD ref, new HEAD ref, and a flag (1 = branch checkout, 0 = file checkout).
"""
class PostCheckout(Hook):
def __init__(self, repo: pygit2.Repository):
super().__init__(repo)
def run(self, prev_head: str, new_head: str, branch_checkout: str) -> HookResult:
return HookResult.SUCCESS
"""
Post-Merge Hook (Client-side)
Runs after a successful git merge (e.g. after git pull). Cannot affect the outcome.
Use this hook to:
- Restore working tree metadata in conjunction with pre-commit
- Run post-merge checks or notifications
Takes one parameter: a status flag indicating whether the merge was a squash merge.
"""
class PostMerge(Hook):
def __init__(self, repo: pygit2.Repository):
super().__init__(repo)
def run(self, squash: str) -> HookResult:
return HookResult.SUCCESS
"""
Pre-Push Hook (Client-side)
Called by git push; can be used to prevent a push.
Use this hook to:
- Run tests or lint before pushing
- Enforce branch naming or ref permissions
- Validate commits being pushed
Takes two parameters: remote name and remote URL. Ref updates are provided on stdin.
"""
class PrePush(Hook):
def __init__(self, repo: pygit2.Repository):
super().__init__(repo)
def run(self, remote_name: str, remote_url: str) -> HookResult:
return HookResult.SUCCESS
# -----------------------------------------------------------------------------
# Server-side hooks (run in $GIT_DIR on receive-pack / push)
# -----------------------------------------------------------------------------
"""
Update Hook (Server-side)
Invoked by git-receive-pack once per ref being updated, before the ref is updated.
Use this hook to:
- Enforce fast-forward only (reject non-FF updates)
- Implement per-ref access control
- Log or validate old → new for specific refs
Takes three parameters: ref name, old object name, new object name.
"""
class Update(Hook):
def __init__(self, repo: pygit2.Repository):
super().__init__(repo)
def run(self, ref_name: str, old_oid: str, new_oid: str) -> HookResult:
return HookResult.SUCCESS
"""
Post-Update Hook (Server-side)
Invoked by git-receive-pack once after all refs have been updated.
Use this hook to:
- Notify or trigger CI for updated refs
- Run git update-server-info for dumb transports (e.g. HTTP)
- Update caches or derived data
Takes a variable number of parameters: the name of each ref that was updated.
"""
class PostUpdate(Hook):
def __init__(self, repo: pygit2.Repository):
super().__init__(repo)
def run(self, *ref_names: str) -> HookResult:
return HookResult.SUCCESS
"""
Push-To-Checkout Hook (Server-side)
Invoked when a push updates the currently checked-out branch and receive.denyCurrentBranch is updateInstead.
Use this hook to:
- Override how the working tree and index are updated to match the new commit
- Run git read-tree -u -m to emulate a reverse fetch
- Refuse the push by exiting non-zero (without modifying index or worktree)
Takes one parameter: the commit object name the tip of the current branch will be updated to.
"""
class PushToCheckout(Hook):
def __init__(self, repo: pygit2.Repository):
super().__init__(repo)
def run(self, new_commit: str) -> HookResult:
return HookResult.SUCCESS
"""
Pre-Auto-GC Hook
Invoked by git gc --auto before automatic garbage collection runs.
Use this hook to:
- Prevent or delay gc when the repo is busy (e.g. long-running operations)
- Run housekeeping or consistency checks before gc
- Notify or log that auto-gc is about to run
Takes no parameters. Exiting with non-zero status prevents gc from running.
"""
class PreAutoGc(Hook):
def __init__(self, repo: pygit2.Repository):
super().__init__(repo)
def run(self) -> HookResult:
return HookResult.SUCCESS
# -----------------------------------------------------------------------------
# Hooks skipped (not implemented in this module)
# -----------------------------------------------------------------------------
#
# E-mail / git-am hooks (skipped by design):
# - applypatch-msg (message file; used by git am)
# - pre-applypatch (no params; used by git am)
# - post-applypatch (no params; used by git am)
#
# Stdin-only or protocol hooks (skipped: no string parameters to pass to run()):
# - pre-receive (no args; ref updates on stdin)
# - post-receive (no args; ref updates on stdin)
# - reference-transaction (state string + ref updates on stdin)
# - proc-receive (pkt-line protocol on stdin/stdout)