1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
|
package difftree
import (
"bytes"
"os"
"srcd.works/go-git.v4/plumbing/object"
"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 *object.Tree) ([]*Change, 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(object.FileMode)
fileDeprecated = modeToBytes(object.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)
}
|