go-git
go-git copied to clipboard
Question: diff --name-only command implementation
Hey-hey,
I tried to create following git command with go-git: git diff --name-only --diff-filter=AM HEAD~5 HEAD -- .
At some point in my code I have a Patch
and iterate over stats:
patch, _ := lastCommit.Patch(&firstCommit)
for i := 0; i < len(patch.Stats()); i++ {
changedFiles = append(changedFiles, patch.Stats()[i].Name)
}
but all binaries files are missing. I guess because of https://github.com/src-d/go-git/blob/3bd5e82b2512d85becae9677fa06b5a973fd4cfb/plumbing/object/patch.go#L302
Perhaps I don't need Patch
object and can do it differently?
Thanks for pointing me in the "right" direction.
@nerro Do you still have an example of your code?
Do you still have your code? I assume something like this:
currentTree, err := commit.Tree()
if err != nil {
return err
}
prevTree, err := prevCommit.Tree()
if err != nil {
return err
}
changes, err := currentTree.Diff(prevTree)
if err != nil {
return err
}
for _, c := range changes {
...
}
@StevenACoffman, it's already about 1 year and I solved it different way. If you're interested I can check the code.
Yeah, I would still really appreciate your code, if you can find it. Thanks very much!
func main() {
fmt.Println("git ")
CheckArgs("<revision1>")
var hash plumbing.Hash
prevSha := os.Args[1] //prevSha
dir, err := os.Getwd()
CheckIfError(err)
repo, err := git.PlainOpen(dir)
CheckIfError(err)
if len(os.Args) < 3 {
headRef, err := repo.Head()
CheckIfError(err)
// ... retrieving the head commit object
hash = headRef.Hash()
CheckIfError(err)
} else {
arg2 := os.Args[2] //optional descendent sha
hash = plumbing.NewHash(arg2)
}
prevHash := plumbing.NewHash(prevSha)
prevCommit, err := repo.CommitObject(prevHash)
CheckIfError(err)
commit, err := repo.CommitObject(hash)
CheckIfError(err)
fmt.Println("Comparing from:"+ prevCommit.Hash.String() + " to:"+ commit.Hash.String())
isAncestor, err := commit.IsAncestor(prevCommit)
CheckIfError(err)
fmt.Printf("Is the prevCommit an ancestor of commit? : %v %v\n",isAncestor)
currentTree, err := commit.Tree()
CheckIfError(err)
prevTree, err := prevCommit.Tree()
CheckIfError(err)
patch, err := currentTree.Patch(prevTree)
CheckIfError(err)
fmt.Println("Got here"+ strconv.Itoa(len(patch.Stats())))
var changedFiles []string
for _, fileStat := range patch.Stats() {
fmt.Println(fileStat.Name)
changedFiles = append(changedFiles,fileStat.Name)
}
changes, err := currentTree.Diff(prevTree)
CheckIfError(err)
fmt.Println("Got here!")
for _, change := range changes {
// Ignore deleted files
action, err := change.Action()
CheckIfError(err)
if action == merkletrie.Delete {
//fmt.Println("Skipping delete")
continue
}
// Get list of involved files
name := getChangeName(change)
fmt.Println(name)
}
}
func getChangeName(change *object.Change) string {
var empty = object.ChangeEntry{}
if change.From != empty {
return change.From.Name
}
return change.To.Name
}
The change.Files() gives only the names of the files with to.Name
, with no paths inside the repository, however the change.toString() gives the full path.
@StevenACoffman this was an immensely helpful snippet of code to find. Do you think it could be moved into a test to ensure it doesn't bitrot?
Thanks! I have prototyped in bash and then usually convert to go, so I often search these issues for some equivalent. It would be nice to make a single page that is a translation between common git cheatsheet / cookbook and having go-git code snippets that did the same thing. Making them tests would keep ensure they are kept working though.
godoc has a nifty thing called a "testable example" which you could use if you would like the test to run on a regular basis. I ended up reading a bunch of src-d/hercules
code last night and they have an interesting thing where their test cases are based on the first 100 commits of the hercules
repo. You could load the root of the git repo and use that as your testbed.
Go for it! I think you have a great idea, and I'd love to see it!