Coverage for src/features/git.py: 82.98%
47 statements
« prev ^ index » next coverage.py v7.17.2, created at 2026-11-08 13:49 +0000
« prev ^ index » next coverage.py v7.17.2, created at 2026-11-08 13:49 +0000
1#!/usr/bin/env python3
3# Standard libraries
4from pathlib import Path
5from typing import List
7# Components
8from ..system.commands import Commands
10# Git class
11class Git:
13 # Constants
14 BINARY: str = 'git'
16 # Commit exists
17 @staticmethod
18 def commit_exists(reference: str) -> bool:
20 # Check commit existance
21 return bool(
22 Commands.output(Git.BINARY, [
23 'rev-parse',
24 '--quiet',
25 '--verify',
26 reference,
27 ]))
29 # Diff
30 @staticmethod
31 def diff(files: List[str]) -> bool:
33 # Detect files differences
34 return not Commands.run(
35 Git.BINARY,
36 [
37 'diff',
38 '--quiet',
39 ] + files,
40 check=False,
41 )
43 # Hooks directory
44 @staticmethod
45 def hooks_dir() -> str:
47 # Result
48 return Commands.output(Git.BINARY, [
49 'rev-parse',
50 '--git-path',
51 'hooks',
52 ])
54 # Hooks files
55 @staticmethod
56 def hooks_files() -> List[str]:
58 # Variables
59 hooks_dir: Path = Path(Git.hooks_dir())
61 # Result
62 return [
63 hook.name for hook in Path(hooks_dir).iterdir()
64 if hook.is_file() and '.' not in hook.name
65 ]
67 # Intend
68 @staticmethod
69 def intend(files: List[str]) -> bool:
71 # Intend to add files
72 return Commands.run(
73 Git.BINARY,
74 [
75 'add',
76 '--intent-to-add',
77 ] + files,
78 check=False,
79 )
81 # Is repository
82 @staticmethod
83 def is_repository() -> bool:
85 # Check git repository
86 return Commands.run(
87 Git.BINARY,
88 [
89 'rev-parse',
90 '--is-inside-work-tree',
91 ],
92 check=False,
93 )
95 # Restore
96 @staticmethod
97 def restore(files: List[str]) -> bool:
99 # Restore files from the staging area
100 return Commands.run(Git.BINARY, [
101 'checkout',
102 '--quiet',
103 '--',
104 ] + files)
106 # Remotes
107 @staticmethod
108 def remotes() -> List[str]:
110 # Detect git repository
111 if not Git.is_repository():
112 return []
114 # List git remotes
115 return [
116 remote.lstrip('*').strip()
117 for remote in Commands.output(Git.BINARY, [
118 'remote',
119 ]).splitlines()
120 ]
122 # Staging empty
123 @staticmethod
124 def staging_empty() -> bool:
126 # Detect empty staging area
127 return Commands.run(
128 Git.BINARY,
129 [
130 'diff',
131 '--cached',
132 '--quiet',
133 ],
134 check=False,
135 )
137 # Status
138 @staticmethod
139 def status(untracked: bool) -> bool:
141 # Show git status
142 return Commands.run(Git.BINARY, [
143 'status',
144 ] + ([
145 '--untracked-files',
146 ] if untracked else []))
148 # Update remote head
149 @staticmethod
150 def update_remote_head(remote: str) -> bool:
152 # Fetch remote branches
153 Commands.run(Git.BINARY, [
154 'fetch',
155 f'{remote}',
156 ])
158 # Update remote head
159 return Commands.run(Git.BINARY, [
160 'remote',
161 'set-head',
162 f'{remote}',
163 '-a',
164 ])
166 # URLs
167 @staticmethod
168 def urls() -> List[str]:
170 # Detect git repository
171 if not Git.is_repository():
172 return []
174 # List git remotes URLs
175 return [
176 url.strip() for url in Commands.output(Git.BINARY, [
177 'ls-remote',
178 '--get-url',
179 ]).splitlines()
180 ]