@@ -233,63 +233,72 @@ func parseDiffStat(stdout string) (numFiles, totalAdditions, totalDeletions int,
233233 return numFiles , totalAdditions , totalDeletions , err
234234}
235235
236- func parseCompareArgs ( compareArgs string ) ( args [] string ) {
237- parts := strings . Split ( compareArgs , "..." )
238- if len ( parts ) == 2 {
239- return [] string { compareArgs }
236+ // GetDiffOrPatch generates either diff or formatted patch data between given revisions
237+ func ( repo * Repository ) GetDiffOrPatch ( base , head string , w io. Writer , patch , binary bool ) error {
238+ if patch {
239+ return repo . GetPatch ( base , head , w )
240240 }
241- parts = strings .Split (compareArgs , ".." )
242- if len (parts ) == 2 {
243- return parts
241+ if binary {
242+ return repo .GetDiffBinary (base , head , w )
244243 }
245- parts = strings .Fields (compareArgs )
246- if len (parts ) == 2 {
247- return parts
248- }
249-
250- return nil
244+ return repo .GetDiff (base , head , w )
251245}
252246
253247// GetDiff generates and returns patch data between given revisions, optimized for human readability
254- func (repo * Repository ) GetDiff (compareArgs string , w io.Writer ) error {
255- args := parseCompareArgs (compareArgs )
256- if len (args ) == 0 {
257- return fmt .Errorf ("invalid compareArgs: %s" , compareArgs )
258- }
248+ func (repo * Repository ) GetDiff (base , head string , w io.Writer ) error {
259249 stderr := new (bytes.Buffer )
260- return NewCommand (repo .Ctx , "diff" , "-p" ).AddDynamicArguments (args ... ).
250+ err := NewCommand (repo .Ctx , "diff" , "-p" ).AddDynamicArguments (base + " ..." + head ).
261251 Run (& RunOpts {
262252 Dir : repo .Path ,
263253 Stdout : w ,
264254 Stderr : stderr ,
265255 })
256+ if err != nil && bytes .Contains (stderr .Bytes (), []byte ("no merge base" )) {
257+ return NewCommand (repo .Ctx , "diff" , "-p" ).AddDynamicArguments (base , head ).
258+ Run (& RunOpts {
259+ Dir : repo .Path ,
260+ Stdout : w ,
261+ })
262+ }
263+ return err
266264}
267265
268266// GetDiffBinary generates and returns patch data between given revisions, including binary diffs.
269- func (repo * Repository ) GetDiffBinary (compareArgs string , w io.Writer ) error {
270- args := parseCompareArgs (compareArgs )
271- if len (args ) == 0 {
272- return fmt .Errorf ("invalid compareArgs: %s" , compareArgs )
267+ func (repo * Repository ) GetDiffBinary (base , head string , w io.Writer ) error {
268+ stderr := new (bytes.Buffer )
269+ err := NewCommand (repo .Ctx , "diff" , "-p" , "--binary" , "--histogram" ).AddDynamicArguments (base + "..." + head ).
270+ Run (& RunOpts {
271+ Dir : repo .Path ,
272+ Stdout : w ,
273+ Stderr : stderr ,
274+ })
275+ if err != nil && bytes .Contains (stderr .Bytes (), []byte ("no merge base" )) {
276+ return NewCommand (repo .Ctx , "diff" , "-p" , "--binary" , "--histogram" ).AddDynamicArguments (base , head ).
277+ Run (& RunOpts {
278+ Dir : repo .Path ,
279+ Stdout : w ,
280+ })
273281 }
274- return NewCommand (repo .Ctx , "diff" , "-p" , "--binary" , "--histogram" ).AddDynamicArguments (args ... ).Run (& RunOpts {
275- Dir : repo .Path ,
276- Stdout : w ,
277- })
282+ return err
278283}
279284
280285// GetPatch generates and returns format-patch data between given revisions, able to be used with `git apply`
281- func (repo * Repository ) GetPatch (compareArgs string , w io.Writer ) error {
282- args := parseCompareArgs (compareArgs )
283- if len (args ) == 0 {
284- return fmt .Errorf ("invalid compareArgs: %s" , compareArgs )
285- }
286+ func (repo * Repository ) GetPatch (base , head string , w io.Writer ) error {
286287 stderr := new (bytes.Buffer )
287- return NewCommand (repo .Ctx , "format-patch" , "--binary" , "--stdout" ).AddDynamicArguments (args ... ).
288+ err := NewCommand (repo .Ctx , "format-patch" , "--binary" , "--stdout" ).AddDynamicArguments (base + " ..." + head ).
288289 Run (& RunOpts {
289290 Dir : repo .Path ,
290291 Stdout : w ,
291292 Stderr : stderr ,
292293 })
294+ if err != nil && bytes .Contains (stderr .Bytes (), []byte ("no merge base" )) {
295+ return NewCommand (repo .Ctx , "format-patch" , "--binary" , "--stdout" ).AddDynamicArguments (base , head ).
296+ Run (& RunOpts {
297+ Dir : repo .Path ,
298+ Stdout : w ,
299+ })
300+ }
301+ return err
293302}
294303
295304// GetFilesChangedBetween returns a list of all files that have been changed between the given commits
@@ -320,6 +329,21 @@ func (repo *Repository) GetFilesChangedBetween(base, head string) ([]string, err
320329 return split , err
321330}
322331
332+ // GetDiffFromMergeBase generates and return patch data from merge base to head
333+ func (repo * Repository ) GetDiffFromMergeBase (base , head string , w io.Writer ) error {
334+ stderr := new (bytes.Buffer )
335+ err := NewCommand (repo .Ctx , "diff" , "-p" , "--binary" ).AddDynamicArguments (base + "..." + head ).
336+ Run (& RunOpts {
337+ Dir : repo .Path ,
338+ Stdout : w ,
339+ Stderr : stderr ,
340+ })
341+ if err != nil && bytes .Contains (stderr .Bytes (), []byte ("no merge base" )) {
342+ return repo .GetDiffBinary (base , head , w )
343+ }
344+ return err
345+ }
346+
323347// ReadPatchCommit will check if a diff patch exists and return stats
324348func (repo * Repository ) ReadPatchCommit (prID int64 ) (commitSHA string , err error ) {
325349 // Migrated repositories download patches to "pulls" location
0 commit comments