44from __future__ import annotations
55
66from functools import cached_property
7+ from typing import TYPE_CHECKING
78
89from dda .tools .base import Tool
910from dda .utils .git .changeset import ChangeSet
10- from dda .utils .git .commit import Commit , CommitDetails , SHA1Hash
11+
12+ if TYPE_CHECKING :
13+ from dda .utils .git .commit import Commit , CommitDetails
1114
1215
1316class Git (Tool ):
@@ -95,22 +98,21 @@ def get_head_commit(self) -> Commit:
9598 """
9699 Get the current HEAD commit of the Git repository in the current working directory.
97100 """
98- from dda .utils .git .commit import Commit , SHA1Hash
101+ from dda .utils .git .commit import Commit
99102
100- sha1_str = self .capture (["rev-parse" , "HEAD" ]).strip ()
101- sha1 = SHA1Hash (sha1_str )
103+ sha1 = self .capture (["rev-parse" , "HEAD" ]).strip ()
102104
103105 # Get the org/repo from the remote URL
104106 org , repo , _ = self .get_remote_details ()
105107 return Commit (org = org , repo = repo , sha1 = sha1 )
106108
107- def get_commit_details (self , sha1 : SHA1Hash ) -> CommitDetails :
109+ def get_commit_details (self , sha1 : str ) -> CommitDetails :
108110 """
109111 Get the details of the given commit in the Git repository in the current working directory.
110112 """
111113 from datetime import datetime
112114
113- from dda .utils .git .commit import CommitDetails , SHA1Hash
115+ from dda .utils .git .commit import CommitDetails
114116
115117 raw_details = self .capture ([
116118 "show" ,
@@ -119,7 +121,7 @@ def get_commit_details(self, sha1: SHA1Hash) -> CommitDetails:
119121 # fmt: author name, author email, author date, parent SHAs, commit message body
120122 "--format=%an%n%ae%n%ad%n%P%n%B" ,
121123 "--date=iso-strict" ,
122- str ( sha1 ) ,
124+ sha1 ,
123125 ])
124126 author_name , author_email , date_str , parents_str , * message_lines = raw_details .splitlines ()
125127
@@ -128,31 +130,37 @@ def get_commit_details(self, sha1: SHA1Hash) -> CommitDetails:
128130 author_email = author_email ,
129131 datetime = datetime .fromisoformat (date_str ),
130132 message = "\n " .join (message_lines ).strip ().strip ('"' ),
131- parent_shas = [ SHA1Hash ( parent_sha ) for parent_sha in parents_str .split ()] ,
133+ parent_shas = list ( parents_str .split ()) ,
132134 )
133135
134136 def _capture_diff_lines (self , * args : str ) -> list [str ]:
135- diff_args = ["diff" , "-U0" , "--no-color" , "--no-prefix" , "--no-renames" ]
137+ diff_args = [
138+ "-c" ,
139+ "core.quotepath=false" ,
140+ "diff" ,
141+ "-U0" ,
142+ "--no-color" ,
143+ "--no-prefix" ,
144+ "--no-renames" ,
145+ "--no-ext-diff" ,
146+ # "-z",
147+ ]
136148 return self .capture ([* diff_args , * args ], check = False ).strip ().splitlines ()
137149
138150 def _compare_refs (self , ref1 : str , ref2 : str ) -> ChangeSet :
139- return ChangeSet .generate_from_diff_output (self ._capture_diff_lines (str ( ref1 ), str ( ref2 ) ))
151+ return ChangeSet .generate_from_diff_output (self ._capture_diff_lines (ref1 , ref2 ))
140152
141- def get_commit_changes (self , sha1 : SHA1Hash ) -> ChangeSet :
153+ def get_commit_changes (self , sha1 : str ) -> ChangeSet :
142154 """
143155 Get the changes of the given commit in the Git repository in the current working directory.
144156 """
145- return self ._compare_refs (f"{ sha1 } ^" , str ( sha1 ) )
157+ return self ._compare_refs (f"{ sha1 } ^" , sha1 )
146158
147- def get_changes_between_commits (self , a : SHA1Hash | Commit , b : SHA1Hash | Commit ) -> ChangeSet :
159+ def get_changes_between_commits (self , a : str , b : str ) -> ChangeSet :
148160 """
149- Get the changes between two commits.
161+ Get the changes between two commits, identified by their SHA-1 hashes .
150162 """
151- if isinstance (a , Commit ):
152- a = a .sha1
153- if isinstance (b , Commit ):
154- b = b .sha1
155- return self ._compare_refs (str (a ), str (b ))
163+ return self ._compare_refs (a , b )
156164
157165 def get_working_tree_changes (self ) -> ChangeSet :
158166 """
@@ -166,26 +174,31 @@ def get_working_tree_changes(self) -> ChangeSet:
166174 tracked_changes = ChangeSet .generate_from_diff_output (self ._capture_diff_lines ("HEAD" ))
167175
168176 # Capture changes to untracked files
169- untracked_files = self .capture (["ls-files" , "--others" , "--exclude-standard" ]).strip ().splitlines ()
177+ other_files_output = self .capture (["ls-files" , "--others" , "--exclude-standard" , "-z" ]).strip ()
178+ untracked_files = [x .strip () for x in other_files_output .split ("\0 " ) if x ] # Remove empty strings
179+
180+ if not untracked_files :
181+ return tracked_changes
182+
170183 diffs = list (chain .from_iterable (self ._capture_diff_lines ("/dev/null" , file ) for file in untracked_files ))
171184 untracked_changes = ChangeSet .generate_from_diff_output (diffs )
172185
173186 # Combine the changes
174187 return tracked_changes | untracked_changes
175188
176- def get_merge_base (self , remote_name : str = "origin" ) -> SHA1Hash | str :
189+ def get_merge_base (self , remote_name : str = "origin" ) -> str :
177190 """
178191 Get the merge base of the current branch.
179192 """
180- res = self .capture (["merge-base" , "HEAD" , remote_name ]).strip ()
193+ res = self .capture (["merge-base" , "HEAD" , remote_name ], check = False ).strip ()
181194 if not res :
182195 self .app .display_warning ("Could not determine merge base for current branch. Using `main` instead." )
183196 return "main"
184- return SHA1Hash ( res )
197+ return res
185198
186199 def get_changes_with_base (
187200 self ,
188- base : SHA1Hash | Commit | str | None = None ,
201+ base : str | None = None ,
189202 * ,
190203 include_working_tree : bool = True ,
191204 remote_name : str = "origin" ,
@@ -200,12 +213,9 @@ def get_changes_with_base(
200213 """
201214 if base is None :
202215 base = self .get_merge_base (remote_name )
203- if isinstance (base , Commit ):
204- base = base .sha1
205- base = str (base )
206216
207217 head = self .get_head_commit ()
208- changes = self ._compare_refs (base , head .sha1 )
218+ changes = ChangeSet . generate_from_diff_output ( self ._capture_diff_lines (base , "..." , head .sha1 ) )
209219 if include_working_tree :
210220 changes |= self .get_working_tree_changes ()
211221 return changes
0 commit comments