aboutsummaryrefslogblamecommitdiffstats
path: root/plumbing/object/difftree.go
blob: e6e0cb0d957a84efa511ac911fb8b7eb559b59fa (plain) (tree)
1
2
3
4
5
6
7
8
9
10
              


               
            
 

                                                     

 

                                                                    
                                            

                               
 
                                                                          
                       
                               

         
                                            
 
 




                                                                     
                                        




















                                                         

                                                        







                                                          
 
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)
}