Source File
rename.go
Belonging Package
github.com/go-git/go-git/v5/plumbing/object
package object
import (
)
func (
Changes,
*DiffTreeOptions,
) (Changes, error) {
if == nil {
= DefaultDiffTreeOptions
}
:= &renameDetector{
renameScore: int(.RenameScore),
renameLimit: int(.RenameLimit),
onlyExact: .OnlyExactRenames,
}
for , := range {
, := .Action()
if != nil {
return nil,
}
switch {
case merkletrie.Insert:
.added = append(.added, )
case merkletrie.Delete:
.deleted = append(.deleted, )
default:
.modified = append(.modified, )
}
}
return .detect()
}
type renameDetector struct {
added []*Change
deleted []*Change
modified []*Change
renameScore int
renameLimit int
onlyExact bool
}
func ( *renameDetector) () {
:= groupChangesByHash(.added)
:= groupChangesByHash(.deleted)
var []*Change
var [][]*Change
var []*Change
for , := range {
if len() == 1 {
= append(, [0])
} else {
= append(, )
}
}
for , := range {
:= changeHash()
:= []
if len() == 1 {
if sameMode(, [0]) {
.modified = append(.modified, &Change{From: [0].From, To: .To})
delete(, )
} else {
= append(, )
}
} else if len() > 1 {
:= bestNameMatch(, )
if != nil && sameMode(, ) {
.modified = append(.modified, &Change{From: .From, To: .To})
delete(, )
var = make([]*Change, 0, len()-1)
for , := range {
if != {
= append(, )
}
}
[] =
}
} else {
= append(, )
}
}
for , := range {
:= changeHash([0])
:= []
if len() == 1 {
:= [0]
:= bestNameMatch(, )
if != nil && sameMode(, ) {
.modified = append(.modified, &Change{From: .From, To: .To})
delete(, )
for , := range {
if != {
= append(, )
}
}
} else {
= append(, ...)
}
} else if len() > 1 {
:= len() * len()
if .renameLimit > 0 && .renameLimit < {
= .renameLimit
}
:= make(similarityMatrix, 0, )
for , := range {
:= changeName()
for , := range {
:= changeName()
:= nameSimilarityScore(, )
= append(, similarityPair{added: , deleted: , score: })
if len() >= {
break
}
}
if len() >= {
break
}
}
sort.Stable()
:= make(map[*Change]struct{})
:= make(map[*Change]struct{})
for := len() - 1; >= 0; -- {
:= [[].deleted]
:= [[].added]
continue
}
[] = struct{}{}
[] = struct{}{}
.modified = append(.modified, &Change{From: .From, To: .To})
[[].added] = nil
[[].deleted] = nil
}
for , := range {
if , := []; ! && != nil {
= append(, )
}
}
var = make([]*Change, 0, len()-len())
for , := range {
if , := []; ! && != nil {
= append(, )
}
}
[] =
} else {
= append(, ...)
}
}
.added =
.deleted = nil
for , := range {
.deleted = append(.deleted, ...)
}
}
func ( *renameDetector) () error {
:= max(len(.added), len(.deleted))
if .renameLimit > 0 && > .renameLimit {
return nil
}
, := .deleted, .added
, := buildSimilarityMatrix(, , .renameScore)
if != nil {
return
}
:= make([]*Change, 0, min(len(), len()))
[.added] = nil
[.deleted] = nil
}
.modified = append(.modified, ...)
.added = compactChanges()
.deleted = compactChanges()
return nil
}
func ( *renameDetector) () (Changes, error) {
if len(.added) > 0 && len(.deleted) > 0 {
.detectExactRenames()
if !.onlyExact {
if := .detectContentRenames(); != nil {
return nil,
}
}
}
:= make(Changes, 0, len(.added)+len(.deleted)+len(.modified))
= append(, .added...)
= append(, .deleted...)
= append(, .modified...)
sort.Stable()
return , nil
}
func ( *Change, []*Change) *Change {
var *Change
var int
:= changeName()
for , := range {
:= nameSimilarityScore(, changeName())
if > {
=
=
}
}
return
}
func (, string) int {
:= strings.LastIndexByte(, '/') + 1
:= strings.LastIndexByte(, '/') + 1
:= min(, )
:= max(, )
var , int
if == 0 {
= 100
= 100
} else {
var int
for ; < ; ++ {
if [] != [] {
break
}
}
= * 100 /
if == 100 {
= 100
} else {
for = 0; < ; ++ {
if [-1-] != [-1-] {
break
}
}
= * 100 /
}
}
:= min(len()-, len()-)
:= max(len()-, len()-)
:= 0
for ; < ; ++ {
if [len()-1-] != [len()-1-] {
break
}
}
:= * 100 /
return ((( + ) * 25) + ( * 50)) / 100
}
func ( *Change) string {
if .To != empty {
return .To.Name
}
return .From.Name
}
func ( *Change) plumbing.Hash {
if .To != empty {
return .To.TreeEntry.Hash
}
return .From.TreeEntry.Hash
}
func ( *Change) filemode.FileMode {
if .To != empty {
return .To.TreeEntry.Mode
}
return .From.TreeEntry.Mode
}
func (, *Change) bool {
return changeMode() == changeMode()
}
func ( []*Change) map[plumbing.Hash][]*Change {
var = make(map[plumbing.Hash][]*Change)
for , := range {
:= changeHash()
[] = append([], )
}
return
}
type similarityMatrix []similarityPair
func ( similarityMatrix) () int { return len() }
func ( similarityMatrix) (, int) { [], [] = [], [] }
func ( similarityMatrix) (, int) bool {
if [].score == [].score {
if [].added == [].added {
return [].deleted < [].deleted
}
return [].added < [].added
}
return [].score < [].score
}
:
for , := range {
if changeMode() != filemode.Regular {
continue
}
var *File
var *similarityIndex
var error
for , := range {
if changeMode() != filemode.Regular {
continue
}
if [] {
continue
}
var *File
:= []
if == 0 {
, _, = .Files()
if != nil {
return nil,
}
= .Size + 1
[] =
}
:= []
if == 0 {
_, , = .Files()
if != nil {
return nil,
}
= .Size + 1
[] =
}
, := ,
if < {
=
=
}
continue
}
if == nil {
, = fileSimilarityIndex()
if != nil {
if == errIndexFull {
continue
}
return nil,
}
}
if == nil {
_, , = .Files()
if != nil {
return nil,
}
}
, := fileSimilarityIndex()
if != nil {
if == errIndexFull {
[] = true
}
return nil,
}
:= nameSimilarityScore(.From.Name, .To.Name) * 100
:= (*99 + *1) / 10000
if < {
continue
}
= append(, similarityPair{added: , deleted: , score: })
}
}
sort.Stable()
return , nil
}
func ( []*Change) []*Change {
var []*Change
for , := range {
if != nil {
= append(, )
}
}
return
}
const (
keyShift = 32
maxCountValue = (1 << keyShift) - 1
)
var errIndexFull = errors.New("index is full")
type similarityIndex struct {
numHashes int
growAt int
hashes []keyCountPair
hashBits int
}
func ( *File) (*similarityIndex, error) {
:= newSimilarityIndex()
if := .hash(); != nil {
return nil,
}
sort.Stable(keyCountPairs(.hashes))
return , nil
}
func () *similarityIndex {
return &similarityIndex{
hashBits: 8,
hashes: make([]keyCountPair, 1<<8),
growAt: shouldGrowAt(8),
}
}
func ( *similarityIndex) ( *File) error {
, := .IsBinary()
if != nil {
return
}
, := .Reader()
if != nil {
return
}
defer ioutil.CheckClose(, &)
return .hashContent(, .Size, )
}
func ( *similarityIndex) ( io.Reader, int64, bool) error {
var = make([]byte, 4096)
var , int
:=
for 0 < {
:= 5381
var uint64
func ( *similarityIndex) ( *similarityIndex, int) int {
var = .hashed
if < .hashed {
= .hashed
}
if == 0 {
return
}
return int(.common() * uint64() / )
}
func ( *similarityIndex) ( *similarityIndex) uint64 {
, := 0, 0
if .numHashes == 0 || .numHashes == 0 {
return 0
}
var uint64
, := .hashes[].key(), .hashes[].key()
for {
if == {
, := .hashes[].count(), .hashes[].count()
if < {
+=
} else {
+=
}
++
if == len(.hashes) {
break
}
= .hashes[].key()
++
if == len(.hashes) {
break
}
= .hashes[].key()
var error
.hashes[], = newKeyCountPair(, .count()+)
if != nil {
return
}
return nil
} else if +1 >= len(.hashes) {
= 0
} else {
++
}
}
}
type keyCountPair uint64
func ( int, uint64) (keyCountPair, error) {
if > maxCountValue {
return 0, errIndexFull
}
return keyCountPair((uint64() << keyShift) | ), nil
}
func ( keyCountPair) () int {
return int( >> keyShift)
}
func ( keyCountPair) () uint64 {
return uint64() & maxCountValue
}
.hashes = make([]keyCountPair, 1<<uint(.hashBits))
for , := range {
if != 0 {
:= .slot(.key())
for .hashes[] != 0 {
++
if >= len(.hashes) {
= 0
}
}
.hashes[] =
}
}
return nil
}
type keyCountPairs []keyCountPair
func ( keyCountPairs) () int { return len() }
func ( keyCountPairs) (, int) { [], [] = [], [] }
![]() |
The pages are generated with Golds v0.3.2-preview. (GOOS=darwin GOARCH=amd64) Golds is a Go 101 project developed by Tapir Liu. PR and bug reports are welcome and can be submitted to the issue list. Please follow @Go100and1 (reachable from the left QR code) to get the latest news of Golds. |