package git

import (
	
	

	
	
	

	
)
References returns a slice of Commits for the file at "path", starting from the commit provided that contains the file from the provided path. The last commit into the returned slice is the commit where the file was created. If the provided commit does not contains the specified path, a nil slice is returned. The commits are sorted in commit order, newer to older. Caveats: - Moves and copies are not currently supported. - Cherry-picks are not detected unless there are no commits between them and therefore can appear repeated in the list. (see git path-id for hints on how to fix this).
func ( *object.Commit,  string) ([]*object.Commit, error) {
	var  []*object.Commit
	 := make(map[plumbing.Hash]struct{})
	if  := walkGraph(&, &, , );  != nil {
		return nil, 
	}
TODO result should be returned without ordering
	sortCommits()
for merges of identical cherry-picks
	return removeComp(, , equivalent)
}

type commitSorterer struct {
	l []*object.Commit
}

func ( commitSorterer) () int {
	return len(.l)
}

func ( commitSorterer) (,  int) bool {
	return .l[].Committer.When.Before(.l[].Committer.When) ||
		.l[].Committer.When.Equal(.l[].Committer.When) &&
			.l[].Author.When.Before(.l[].Author.When)
}

func ( commitSorterer) (,  int) {
	.l[], .l[] = .l[], .l[]
}
SortCommits sorts a commit list by commit date, from older to newer.
func ( []*object.Commit) {
	 := &commitSorterer{}
	sort.Sort()
}
Recursive traversal of the commit graph, generating a linear history of the path.
check and update seen
	if ,  := (*)[.Hash];  {
		return nil
	}
	(*)[.Hash] = struct{}{}
if the path is not in the current commit, stop searching.
	if ,  := .File();  != nil {
		return nil
	}
optimization: don't traverse branches that does not contain the path.
	,  := parentsContainingPath(, )
	if  != nil {
		return 
	}
if the path is not found in any of its parents, the path was created by this commit; we must add it to the revisions list and stop searching. This includes the case when current is the initial commit.
	case 0:
		* = append(*, )
		return nil
if the file contents has change, add the current commit
		,  := differentContents(, , )
		if  != nil {
			return 
		}
		if len() == 1 {
			* = append(*, )
in any case, walk the parent
		return (, , [0], )
TODO: detect merges that had a conflict, because they must be included in the result here.
		for ,  := range  {
			 := (, , , )
			if  != nil {
				return 
			}
		}
	}
	return nil
}

TODO: benchmark this method making git.object.Commit.parent public instead of using an iterator
	var  []*object.Commit
	 := .Parents()
	for {
		,  := .Next()
		if  == io.EOF {
			return , nil
		}
		if  != nil {
			return nil, 
		}
		if ,  := .File();  == nil {
			 = append(, )
		}
	}
}
Returns an slice of the commits in "cs" that has the file "path", but with different contents than what can be found in "c".
func ( string,  *object.Commit,  []*object.Commit) ([]*object.Commit, error) {
	 := make([]*object.Commit, 0, len())
	,  := blobHash(, )
	if ! {
		return nil, object.ErrFileNotFound
	}
	for ,  := range  {
		if ,  := blobHash(, );  &&  !=  {
			 = append(, )
		}
	}
	return , nil
}
blobHash returns the hash of a path in a commit
func ( string,  *object.Commit) ( plumbing.Hash,  bool) {
	,  := .File()
	if  != nil {
		var  plumbing.Hash
		return , 
	}
	return .Hash, true
}

type contentsComparatorFn func(path string, a, b *object.Commit) (bool, error)
Returns a new slice of commits, with duplicates removed. Expects a sorted commit list. Duplication is defined according to "comp". It will always keep the first commit of a series of duplicated commits.
func ( string,  []*object.Commit,  contentsComparatorFn) ([]*object.Commit, error) {
	 := make([]*object.Commit, 0, len())
	if len() == 0 {
		return , nil
	}
	 = append(, [0])
	for  := 1;  < len(); ++ {
		,  := (, [], [-1])
		if  != nil {
			return nil, 
		}
		if ! {
			 = append(, [])
		}
	}
	return , nil
}
Equivalent commits are commits whose patch is the same.
func ( string, ,  *object.Commit) (bool, error) {
	 := .NumParents()
	 := .NumParents()
the first commit is not equivalent to anyone and "I think" merges can not be equivalent to anything
	if  != 1 ||  != 1 {
		return false, nil
	}

	,  := patch(, )
	if  != nil {
		return false, 
	}
	,  := patch(, )
	if  != nil {
		return false, 
	}

	return sameDiffs(, ), nil
}

get contents of the file in the commit
	,  := .File()
	if  != nil {
		return nil, 
	}
	,  := .Contents()
	if  != nil {
		return nil, 
	}
get contents of the file in the first parent of the commit
	var  string
	 := .Parents()
	,  := .Next()
	if  != nil {
		return nil, 
	}
	,  = .File()
	if  != nil {
		 = ""
	} else {
		,  = .Contents()
		if  != nil {
			return nil, 
		}
	}
compare the contents of parent and child
	return diff.Do(, ), nil
}

func (,  []diffmatchpatch.Diff) bool {
	if len() != len() {
		return false
	}
	for  := range  {
		if !sameDiff([], []) {
			return false
		}
	}
	return true
}

func (,  diffmatchpatch.Diff) bool {
	if .Type != .Type {
		return false
	}
	switch .Type {
	case 0:
		return countLines(.Text) == countLines(.Text)
	case 1, -1:
		return .Text == .Text
	default:
		panic("unreachable")
	}