How can we use go-git to generate a list of all the files that have changed between two commits similar to git diff --name-only commit1 commit2
?
For context, we have a git monorepo that contains a single root go.mod
file but multiple Go applications. When developers push commits to a branch, we would like to get a list of all files that changed between two git commits (git diff --name-only
), and filter it down into a list of application directories while excluding some directories. Our ultimate goal is so we can build, deploy, and test just the applications that have changed inside our monorepo. We have a bash script similar to this one from shippable that does this, but we'd like to use pure go and go-git.
It appears that change.Files()
gives only the names of the files with to.Name
, without the paths inside the repository, however the change.toString()
gives the full path.
So if you want to use Tree.Diff, you have to get the paths like this:
func getChangeName(change *object.Change) string {
var empty = object.ChangeEntry{}
if change.From != empty {
return change.From.Name
}
return change.To.Name
}
So with that, it looks like you can choose either Tree.Diff or Patch.Stats depending on your needs:
currentTree, err := commit.Tree()
CheckIfError(err)
prevTree, err := prevCommit.Tree()
CheckIfError(err)
patch, err := currentTree.Patch(prevTree)
CheckIfError(err)
fmt.Println("----- 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("----- Changes -----")
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)
}
Patch.Stats will skip binary files, where Tree.Diff will let you ignore deletions.