Skip to content
This repository has been archived by the owner on Sep 11, 2020. It is now read-only.

How to get the line number of a diff? #806

Open
campoy opened this issue Apr 12, 2018 · 7 comments
Open

How to get the line number of a diff? #806

campoy opened this issue Apr 12, 2018 · 7 comments
Labels

Comments

@campoy
Copy link

campoy commented Apr 12, 2018

I'm currently trying to obtain the lines that are new code in a diff.
To do so I wrote the code below

func diffHeadAndPrevious(path, branch string) error {
	logrus.Infof("cloning")
	opts := &git.CloneOptions{
		URL:           path,
		ReferenceName: plumbing.ReferenceName("refs/heads/" + branch),
		SingleBranch:  true,
	}
	repo, err := git.PlainClone("repo", false, opts)
	if err != nil {
		return fmt.Errorf("could not clone repo: %v", err)
	}

	logrus.Infof("done cloning")
	headRef, err := repo.Head()
	if err != nil {
		return fmt.Errorf("could not fetch head: %v", err)
	}

	headCommit, err := repo.CommitObject(headRef.Hash())
	if err != nil {
		return fmt.Errorf("could not get commit for head: %v", err)
	}
	headTree, err := headCommit.Tree()
	if err != nil {
		return fmt.Errorf("could not fetch head tree: %v", err)
	}

	if headCommit.NumParents() > 1 {
		return fmt.Errorf("not sure how to handle merge commits yet")
	} else if headCommit.NumParents() == 0 {
		return nil
	}
	prevCommit, err := headCommit.Parent(0)
	if err != nil {
		return fmt.Errorf("could not fetch previous commit: %v", err)
	}
	prevTree, err := prevCommit.Tree()
	if err != nil {
		return fmt.Errorf("could not fetch previous tree: %v", err)
	}

	changes, err := object.DiffTree(headTree, prevTree)
	if err != nil {
		return fmt.Errorf("could not diff trees: %v", err)
	}

	patch, err := changes.Patch()
	if err != nil {
		return fmt.Errorf("could not get change patch: %v", err)
	}
	for _, p := range patch.FilePatches() {
		if p.IsBinary() {
			continue
		}
		for _, chunk := range p.Chunks() {
			if chunk.Type() != diff.Add {
				continue
			}
			fmt.Printf(chunk.Content())
		}
	}

	return nil
}

This works and if called with diffHeadAndPrevious("https://github.com/campoy/goodgopher", "pr") it will print the content of the lines that changed:

                        Body: &comment.message,
                        Path: &comment.path,
                        // CommitID: commits[len(commits)-1].SHA,

Unfortunately I'd like to know what lines are those in the destination file.
I spent a decent amount of time searching around the documentation but couldn't find anything.

Help, please.

@mcuadros
Copy link
Contributor

@ajnavarro

@ajnavarro
Copy link
Contributor

@campoy I think you can use the @@ -start,count +start,count @@ header to have this data.start represents the starting line number of each version of the file, and count represents how many lines are included, starting from the start point.

All the logic that creates that hunks is on unified_encoder.go file, the hunksGenerator struct, but right now is private. Maybe we can make it public. What do you think @mcuadros ?

@campoy
Copy link
Author

campoy commented Apr 13, 2018

We could make textChunk public, so I can transform from Chunk to TextChunk and obtain that data.

Another option is to create a new ChunkWithLines interface that textChunk satisfies.

@ajnavarro
Copy link
Contributor

But textChunk doesn't have the data you need:

type textChunk struct {
	content string
	op      fdiff.Operation
}

func (t *textChunk) Content() string {
	return t.content
}

func (t *textChunk) Type() fdiff.Operation {
	return t.op
}

We need to make hunk public, because is the output of hunkGenerator:

type Hunk struct {
	FromLine int
	ToLine   int

	FromCount int
	ToCount   int

	ctxPrefix string
	ops       []*op
}

With []Chunk you can create a []Hunk output:

func NewHunksGenerator(chunks []Chunk, ctxLines int) *HunksGenerator {

[...]

func (c *HunksGenerator) Generate() []*Hunk {

@campoy
Copy link
Author

campoy commented Apr 17, 2018

Oh, I had debugged this some time ago and got the types mixed up, clearly.

This seems quite complicated, but I have a pretty limited knowledge of the project, so I'll let @mcuadros and others decide on what the next move is.

@AlexAkulov
Copy link

I also try to rewrite the code on @ajnavarro's recommendations, but it's very difficult.
If you have a working way to get the number of the diff string, share it please.

@campoy
Copy link
Author

campoy commented Apr 19, 2018

I don't have it, no.
I ended up going a different way with my code, but this seems like something that should be easily doable with go-git.

Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
Projects
None yet
Development

No branches or pull requests

4 participants