@@ -265,6 +265,72 @@ func (b *Commit) Encode(o plumbing.EncodedObject) error {
265265 return err
266266}
267267
268+ // FileStat stores the status of changes in content of a file.
269+ type FileStat struct {
270+ Name string
271+ Addition int
272+ Deletion int
273+ }
274+
275+ func (fs FileStat ) String () string {
276+ totalChanges := fs .Addition + fs .Deletion
277+ adds := strings .Repeat ("+" , fs .Addition )
278+ dels := strings .Repeat ("-" , fs .Deletion )
279+ return fmt .Sprintf (" %s | %d %s%s" , fs .Name , totalChanges , adds , dels )
280+ }
281+
282+ // FileStats is a collection of FileStat.
283+ type FileStats []FileStat
284+
285+ // Stats shows the status
286+ func (c * Commit ) Stats () (FileStats , error ) {
287+ var fileStats FileStats
288+
289+ // Get the previous commit.
290+ ci := c .Parents ()
291+ parentCommit , err := ci .Next ()
292+ if err != nil {
293+ return nil , err
294+ }
295+
296+ patch , err := parentCommit .Patch (c )
297+ if err != nil {
298+ return nil , err
299+ }
300+
301+ filePatches := patch .FilePatches ()
302+ for _ , fp := range filePatches {
303+ cs := FileStat {}
304+ from , to := fp .Files ()
305+ if from == nil {
306+ // New File is created.
307+ cs .Name = to .Path ()
308+ } else if to == nil {
309+ // File is deleted.
310+ cs .Name = from .Path ()
311+ } else if from .Path () != to .Path () {
312+ // File is renamed.
313+ cs .Name = fmt .Sprintf ("%s => %s" , from .Path (), to .Path ())
314+ } else {
315+ // File is modified.
316+ cs .Name = from .Path ()
317+ }
318+
319+ for _ , chunk := range fp .Chunks () {
320+ switch chunk .Type () {
321+ case 1 :
322+ cs .Addition += strings .Count (chunk .Content (), "\n " )
323+ case 2 :
324+ cs .Deletion += strings .Count (chunk .Content (), "\n " )
325+ }
326+ }
327+
328+ fileStats = append (fileStats , cs )
329+ }
330+
331+ return fileStats , nil
332+ }
333+
268334func (c * Commit ) String () string {
269335 return fmt .Sprintf (
270336 "%s %s\n Author: %s\n Date: %s\n \n %s\n " ,
0 commit comments