Fix structural API issues in git package wrapper types

copilot-swe-agent[bot] and andreynering created

Co-authored-by: andreynering <7011819+andreynering@users.noreply.github.com>

Change summary

.gitignore       |  1 +
git/patch.go     | 46 +++++++++++++++++++++++-----------------------
git/reference.go |  6 +++---
git/repo.go      | 16 ++++++++++++----
git/tree.go      | 14 +++++++-------
git/utils.go     |  6 +++---
soft             |  0 
7 files changed, 49 insertions(+), 40 deletions(-)

Detailed changes

.gitignore 🔗

@@ -7,3 +7,4 @@ data/
 completions/
 manpages/
 soft_serve_ed25519*
+**/soft

git/patch.go 🔗

@@ -28,7 +28,7 @@ func (s *DiffSection) diffFor(line *git.DiffLine) string {
 	var diff1, diff2 string
 	switch line.Type {
 	case git.DiffLineAdd:
-		compareLine := s.Line(git.DiffLineDelete, line.RightLine)
+		compareLine := s.DiffSection.Line(git.DiffLineDelete, line.RightLine)
 		if compareLine == nil {
 			return fallback
 		}
@@ -37,7 +37,7 @@ func (s *DiffSection) diffFor(line *git.DiffLine) string {
 		diff2 = line.Content
 
 	case git.DiffLineDelete:
-		compareLine := s.Line(git.DiffLineAdd, line.LeftLine)
+		compareLine := s.DiffSection.Line(git.DiffLineAdd, line.LeftLine)
 		if compareLine == nil {
 			return fallback
 		}
@@ -115,18 +115,18 @@ func (f *DiffFileChange) Mode() git.EntryMode {
 
 // Files returns the diff files.
 func (f *DiffFile) Files() (from *DiffFileChange, to *DiffFileChange) {
-	if f.OldIndex != ZeroID {
+	if f.DiffFile.OldIndex != git.EmptyID {
 		from = &DiffFileChange{
-			hash: f.OldIndex,
-			name: f.OldName(),
-			mode: f.OldMode(),
+			hash: f.DiffFile.OldIndex,
+			name: f.DiffFile.OldName(),
+			mode: f.DiffFile.OldMode(),
 		}
 	}
-	if f.Index != ZeroID {
+	if f.DiffFile.Index != git.EmptyID {
 		to = &DiffFileChange{
-			hash: f.Index,
-			name: f.Name,
-			mode: f.Mode(),
+			hash: f.DiffFile.Index,
+			name: f.DiffFile.Name,
+			mode: f.DiffFile.Mode(),
 		}
 	}
 	return
@@ -153,10 +153,10 @@ func printStats(stats FileStats) string {
 	var longestLength float64
 	var longestTotalChange float64
 	for _, fs := range stats {
-		if int(longestLength) < len(fs.Name) {
-			longestLength = float64(len(fs.Name))
+		if int(longestLength) < len(fs.DiffFile.Name) {
+			longestLength = float64(len(fs.DiffFile.Name))
 		}
-		totalChange := fs.NumAdditions() + fs.NumDeletions()
+		totalChange := fs.DiffFile.NumAdditions() + fs.DiffFile.NumDeletions()
 		if int(longestTotalChange) < totalChange {
 			longestTotalChange = float64(totalChange)
 		}
@@ -189,10 +189,10 @@ func printStats(stats FileStats) string {
 	tdelc := 0
 	output := strings.Builder{}
 	for _, fs := range stats {
-		taddc += fs.NumAdditions()
-		tdelc += fs.NumDeletions()
-		addn := float64(fs.NumAdditions())
-		deln := float64(fs.NumDeletions())
+		taddc += fs.DiffFile.NumAdditions()
+		tdelc += fs.DiffFile.NumDeletions()
+		addn := float64(fs.DiffFile.NumAdditions())
+		deln := float64(fs.DiffFile.NumDeletions())
 		addc := int(math.Floor(addn / scaleFactor))
 		delc := int(math.Floor(deln / scaleFactor))
 		if addc < 0 {
@@ -203,10 +203,10 @@ func printStats(stats FileStats) string {
 		}
 		adds := strings.Repeat("+", addc)
 		dels := strings.Repeat("-", delc)
-		diffLines := fmt.Sprint(fs.NumAdditions() + fs.NumDeletions())
+		diffLines := fmt.Sprint(fs.DiffFile.NumAdditions() + fs.DiffFile.NumDeletions())
 		totalDiffLines := fmt.Sprint(int(longestTotalChange))
 		fmt.Fprintf(&output, "%s | %s %s%s\n",
-			fs.Name+strings.Repeat(" ", int(longestLength)-len(fs.Name)),
+			fs.DiffFile.Name+strings.Repeat(" ", int(longestLength)-len(fs.DiffFile.Name)),
 			strings.Repeat(" ", len(totalDiffLines)-len(diffLines))+diffLines,
 			adds,
 			dels)
@@ -260,7 +260,7 @@ func writeFilePatchHeader(sb *strings.Builder, filePatch *DiffFile) {
 	if from == nil && to == nil {
 		return
 	}
-	isBinary := filePatch.IsBinary()
+	isBinary := filePatch.DiffFile.IsBinary()
 
 	var lines []string
 	switch {
@@ -298,14 +298,14 @@ func writeFilePatchHeader(sb *strings.Builder, filePatch *DiffFile) {
 		lines = append(lines,
 			fmt.Sprintf("diff --git %s %s", srcPrefix+to.Name(), dstPrefix+to.Name()),
 			fmt.Sprintf("new file mode %o", to.Mode()),
-			fmt.Sprintf("index %s..%s", ZeroID, to.Hash()),
+			fmt.Sprintf("index %s..%s", git.EmptyID, to.Hash()),
 		)
 		lines = appendPathLines(lines, "/dev/null", dstPrefix+to.Name(), isBinary)
 	case to == nil:
 		lines = append(lines,
 			fmt.Sprintf("diff --git %s %s", srcPrefix+from.Name(), dstPrefix+from.Name()),
 			fmt.Sprintf("deleted file mode %o", from.Mode()),
-			fmt.Sprintf("index %s..%s", from.Hash(), ZeroID),
+			fmt.Sprintf("index %s..%s", from.Hash(), git.EmptyID),
 		)
 		lines = appendPathLines(lines, srcPrefix+from.Name(), "/dev/null", isBinary)
 	}
@@ -324,7 +324,7 @@ func (d *Diff) Patch() string {
 	for _, f := range d.Files {
 		writeFilePatchHeader(&p, f)
 		for _, s := range f.Sections {
-			for _, l := range s.Lines {
+			for _, l := range s.DiffSection.Lines {
 				p.WriteString(s.diffFor(l))
 				p.WriteString("\n")
 			}

git/reference.go 🔗

@@ -36,15 +36,15 @@ func (r ReferenceName) Short() string {
 
 // Name returns the reference name i.e. refs/heads/master.
 func (r *Reference) Name() ReferenceName {
-	return ReferenceName(r.Refspec)
+	return ReferenceName(r.Reference.Refspec)
 }
 
 // IsBranch returns true if the reference is a branch.
 func (r *Reference) IsBranch() bool {
-	return strings.HasPrefix(r.Refspec, git.RefsHeads)
+	return strings.HasPrefix(r.Reference.Refspec, git.RefsHeads)
 }
 
 // IsTag returns true if the reference is a tag.
 func (r *Reference) IsTag() bool {
-	return strings.HasPrefix(r.Refspec, git.RefsTags)
+	return strings.HasPrefix(r.Reference.Refspec, git.RefsTags)
 }

git/repo.go 🔗

@@ -68,7 +68,7 @@ func (r *Repository) HEAD() (*Reference, error) {
 	if err != nil {
 		return nil, err
 	}
-	hash, err := r.ShowRefVerify(rn)
+	hash, err := r.Repository.ShowRefVerify(rn)
 	if err != nil {
 		return nil, err
 	}
@@ -83,7 +83,7 @@ func (r *Repository) HEAD() (*Reference, error) {
 
 // References returns the references for a repository.
 func (r *Repository) References() ([]*Reference, error) {
-	refs, err := r.ShowRef()
+	refs, err := r.Repository.ShowRef()
 	if err != nil {
 		return nil, err
 	}
@@ -119,7 +119,15 @@ func (r *Repository) Tree(ref *Reference) (*Tree, error) {
 		}
 		ref = rref
 	}
-	return r.LsTree(ref.ID)
+	tree, err := r.Repository.LsTree(ref.Reference.ID)
+	if err != nil {
+		return nil, err
+	}
+	return &Tree{
+		Tree:       tree,
+		Path:       "",
+		Repository: r,
+	}, nil
 }
 
 // TreePath returns the tree for the given path.
@@ -162,7 +170,7 @@ func (r *Repository) Patch(commit *Commit) (string, error) {
 
 // CountCommits returns the number of commits in the repository.
 func (r *Repository) CountCommits(ref *Reference) (int64, error) {
-	return r.RevListCount([]string{ref.Name().String()})
+	return r.Repository.RevListCount([]string{ref.Name().String()})
 }
 
 // CommitsByPage returns the commits for a given page and size.

git/tree.go 🔗

@@ -30,10 +30,10 @@ type Entries []*TreeEntry
 
 var sorters = []func(t1, t2 *TreeEntry) bool{
 	func(t1, t2 *TreeEntry) bool {
-		return (t1.IsTree() || t1.IsCommit()) && !t2.IsTree() && !t2.IsCommit()
+		return (t1.TreeEntry.IsTree() || t1.TreeEntry.IsCommit()) && !t2.TreeEntry.IsTree() && !t2.TreeEntry.IsCommit()
 	},
 	func(t1, t2 *TreeEntry) bool {
-		return t1.Name() < t2.Name()
+		return t1.TreeEntry.Name() < t2.TreeEntry.Name()
 	},
 }
 
@@ -72,7 +72,7 @@ type File struct {
 
 // Name returns the name of the file.
 func (f *File) Name() string {
-	return f.Entry.Name()
+	return f.Entry.TreeEntry.Name()
 }
 
 // Path returns the full path of the file.
@@ -82,7 +82,7 @@ func (f *File) Path() string {
 
 // SubTree returns the sub-tree at the given path.
 func (t *Tree) SubTree(path string) (*Tree, error) {
-	tree, err := t.Subtree(path)
+	tree, err := t.Tree.Subtree(path)
 	if err != nil {
 		return nil, err
 	}
@@ -155,7 +155,7 @@ func IsBinary(r io.Reader) (bool, error) {
 func (f *File) IsBinary() (bool, error) {
 	stdout := new(bytes.Buffer)
 	stderr := new(bytes.Buffer)
-	err := f.Pipeline(stdout, stderr)
+	err := f.Blob.Pipeline(stdout, stderr)
 	if err != nil {
 		return false, err
 	}
@@ -165,7 +165,7 @@ func (f *File) IsBinary() (bool, error) {
 
 // Mode returns the mode of the file in fs.FileMode format.
 func (e *TreeEntry) Mode() fs.FileMode {
-	m := e.Blob().Mode()
+	m := e.TreeEntry.Blob().Mode()
 	switch m {
 	case git.EntryTree:
 		return fs.ModeDir | fs.ModePerm
@@ -176,7 +176,7 @@ func (e *TreeEntry) Mode() fs.FileMode {
 
 // File returns the file for the TreeEntry.
 func (e *TreeEntry) File() *File {
-	b := e.Blob()
+	b := e.TreeEntry.Blob()
 	return &File{
 		Blob:  b,
 		Entry: e,

git/utils.go 🔗

@@ -28,12 +28,12 @@ func LatestFile(repo *Repository, ref *Reference, pattern string) (string, strin
 	}
 	for _, e := range ents {
 		te := e
-		fp := filepath.Join(dir, te.Name())
-		if te.IsTree() {
+		fp := filepath.Join(dir, te.TreeEntry.Name())
+		if te.TreeEntry.IsTree() {
 			continue
 		}
 		if g.Match(fp) {
-			if te.IsSymlink() {
+			if te.TreeEntry.IsSymlink() {
 				bts, err := te.Contents()
 				if err != nil {
 					return "", "", err