github.com/driusan/dgit@v0.0.0-20221118233547-f39f0c15edbb/git/difftree.go (about) 1 package git 2 3 import ( 4 "fmt" 5 "regexp" 6 "sort" 7 ) 8 9 // Describes the options that may be specified on the command line for 10 // "git diff-index". Note that only raw mode is currently supported, even 11 // though all the other options are parsed/set in this struct. 12 type DiffTreeOptions struct { 13 Patch bool 14 15 // The 0 value implies 3. 16 NumContextLines int 17 18 Raw bool 19 20 // Unimplemented. Probably never will be. 21 CompactionHeuristic bool 22 23 // Can be "default", "myers", "minimal", "patience", or "histogram" 24 DiffAlgorithm string 25 26 StatWidth, StatNameWidth, StatCount int 27 NumStat bool 28 ShortStat bool 29 30 DirStat string 31 32 Summary bool 33 34 NullTerminate bool 35 36 NameOnly, NameStatus bool 37 38 Submodule string 39 40 // Colour can have three states: "always" (true), "never" (false), or "auto" (nil) 41 Color *bool 42 43 // "color", "plain", "porcelain", or "none" 44 WordDiff string 45 46 WordDiffRegex *regexp.Regexp 47 48 NoRenames bool 49 50 // Warn if changes introduce conflict markers or whitespace errors. 51 Check bool 52 53 // Valid options in the []string are "old", "new", or "context" 54 WhitespaceErrorHighlight []string 55 56 FullIndex, Binary bool 57 58 // Number of characters to abbreviate the hexadecimal object name to. 59 Abbrev int 60 61 // Recurse into subtrees. 62 Recurse bool 63 64 // Diff the initial commit against the empty tree 65 Root bool 66 67 // And 6 million more options, which are mostly for the unsupported patch 68 // format anyways. 69 } 70 71 func DiffTree(c *Client, opt *DiffTreeOptions, tree1, tree2 Treeish, paths []string) ([]HashDiff, error) { 72 t1, err := tree1.TreeID(c) 73 if err != nil { 74 return nil, err 75 } 76 77 var t2 TreeID 78 if tree2 != nil { 79 t, err := tree2.TreeID(c) 80 if err != nil { 81 return nil, err 82 } 83 t2 = t 84 } else { 85 // No tree, use tree 1's parent 86 if c1, ok := tree1.(Commitish); ok { 87 c1a, err := c1.CommitID(c) 88 if err != nil { 89 return nil, err 90 } 91 parents, err := c1a.Parents(c) 92 if err != nil { 93 return nil, err 94 } 95 if len(parents) > 1 { 96 return nil, fmt.Errorf("Parent is a merge commit") 97 } else if len(parents) == 0 { 98 if !opt.Root { 99 return nil, nil 100 } 101 t2 = TreeID{} 102 } else { 103 ptree, err := parents[0].TreeID(c) 104 if err != nil { 105 return nil, err 106 } 107 t2 = ptree 108 } 109 110 } else { 111 return nil, fmt.Errorf("Can not determine parent of tree") 112 } 113 } 114 115 tree1Objects, err := t1.GetAllObjects(c, "", opt.Recurse, opt.Recurse) 116 if err != nil { 117 return nil, err 118 } 119 if opt.Root && t2 == (TreeID{}) { 120 // There is no parent to check against and we --root was 121 // passed, so just include everything from tree1 122 var val []HashDiff = make([]HashDiff, 0, len(tree1Objects)) 123 for name, sha := range tree1Objects { 124 val = append(val, HashDiff{name, TreeEntry{}, sha, 0, 0}) 125 } 126 sort.Sort(ByName(val)) 127 128 return val, nil 129 } 130 tree2Objects, err := t2.GetAllObjects(c, "", opt.Recurse, opt.Recurse) 131 if err != nil { 132 return nil, err 133 } 134 135 var val []HashDiff 136 137 for name, sha := range tree1Objects { 138 if osha := tree2Objects[name]; sha != osha { 139 val = append(val, HashDiff{name, sha, osha, 0, 0}) 140 } 141 } 142 143 // Check for files that were added in tree2 but missing in tree1, which 144 // would have gotten caught by the above ranging. 145 for name, sha := range tree2Objects { 146 if _, ok := tree1Objects[name]; !ok { 147 val = append(val, HashDiff{name, TreeEntry{Sha1{}, 0}, sha, 0, 0}) 148 } 149 } 150 151 sort.Sort(ByName(val)) 152 153 return val, nil 154 }