@@ -172,3 +172,74 @@ def _mode_str_to_int(cls, modestr):
172172 return mode
173173
174174
175+ class Diffable (object ):
176+ """
177+ Common interface for all object that can be diffed against another object of compatible type.
178+
179+ NOTE:
180+ Subclasses require a repo member as it is the case for Object instances, for practical
181+ reasons we do not derive from Object.
182+ """
183+ __slots__ = tuple ()
184+
185+ # subclasses provide additional arguments to the git-diff comamnd by supplynig
186+ # them in this tuple
187+ _diff_args = tuple ()
188+
189+ def diff (self , other = None , paths = None , create_patch = False , ** kwargs ):
190+ """
191+ Creates diffs between two items being trees, trees and index or an
192+ index and the working tree.
193+
194+ ``other``
195+ Is the item to compare us with.
196+ If None, we will be compared to the working tree.
197+
198+ ``paths``
199+ is a list of paths or a single path to limit the diff to.
200+ It will only include at least one of the givne path or paths.
201+
202+ ``create_patch``
203+ If True, the returned Diff contains a detailed patch that if applied
204+ makes the self to other. Patches are somwhat costly as blobs have to be read
205+ and diffed.
206+
207+ ``kwargs``
208+ Additional arguments passed to git-diff, such as
209+ R=True to swap both sides of the diff.
210+
211+ Returns
212+ git.DiffIndex
213+
214+ Note
215+ Rename detection will only work if create_patch is True
216+ """
217+ args = list (self ._diff_args [:])
218+ args .append ( "--abbrev=40" ) # we need full shas
219+ args .append ( "--full-index" ) # get full index paths, not only filenames
220+
221+ if create_patch :
222+ args .append ("-p" )
223+ args .append ("-M" ) # check for renames
224+ else :
225+ args .append ("--raw" )
226+
227+ paths = paths or []
228+ if paths :
229+ paths .insert (0 , "--" )
230+
231+ if other is not None :
232+ args .insert (0 , other )
233+
234+ args .insert (0 ,self )
235+ args .extend (paths )
236+
237+ kwargs ['as_process' ] = True
238+ proc = self .repo .git .diff (* args , ** kwargs )
239+
240+ diff_method = diff .Diff ._index_from_raw_format
241+ if create_patch :
242+ diff_method = diff .Diff ._index_from_patch_format (self .repo , proc .stdout )
243+ return diff_method (self .repo , proc .stdout )
244+
245+
0 commit comments