package object
import (
"bytes"
"os"
"srcd.works/go-git.v4/utils/merkletrie"
"srcd.works/go-git.v4/utils/merkletrie/noder"
)
// DiffTree compares the content and mode of the blobs found via two
// tree objects.
func DiffTree(a, b *Tree) (Changes, error) {
from := newTreeNoder(a)
to := newTreeNoder(b)
merkletrieChanges, err := merkletrie.DiffTree(from, to, hashEqual)
if err != nil {
return nil, err
}
return newChanges(merkletrieChanges)
}
// check if the hash of the contents is different, if not, check if
// the permissions are different (but taking into account deprecated
// file modes). On a treenoder, the hash of the contents is codified
// in the first 20 bytes of the data returned by Hash() and the last
// 4 bytes is the mode.
func hashEqual(a, b noder.Hasher) bool {
hashA, hashB := a.Hash(), b.Hash()
contentsA, contentsB := hashA[:20], hashB[:20]
sameContents := bytes.Equal(contentsA, contentsB)
if !sameContents {
return false
}
modeA, modeB := hashA[20:], hashB[20:]
return equivalentMode(modeA, modeB)
}
func equivalentMode(a, b []byte) bool {
if isFilish(a) && isFilish(b) {
return true
}
return bytes.Equal(a, b)
}
var (
file = modeToBytes(FileMode)
fileDeprecated = modeToBytes(FileModeDeprecated)
// remove this by fixing plumbing.Object mode ASAP
fileGoGit = modeToBytes(os.FileMode(0644))
)
func isFilish(b []byte) bool {
return bytes.Equal(b, file) ||
bytes.Equal(b, fileDeprecated) ||
bytes.Equal(b, fileGoGit)
}