Skip to content

Instantly share code, notes, and snippets.

@Thibauth
Created April 6, 2016 00:40
Show Gist options
  • Save Thibauth/93e996c5fd0a87f7fa8b3c3cf0abaff3 to your computer and use it in GitHub Desktop.
Save Thibauth/93e996c5fd0a87f7fa8b3c3cf0abaff3 to your computer and use it in GitHub Desktop.
package main
import (
"bufio"
"fmt"
"log"
"os"
"os/exec"
"runtime/pprof"
"strings"
"time"
"gopkg.in/libgit2/git2go.v24"
)
func ago(t time.Time) string {
hours := time.Since(t).Hours()
var ago string
if hours > 24 {
ago = fmt.Sprintf("%d days ago", int(hours/24))
} else {
ago = fmt.Sprintf("%d hours ago", int(hours))
}
return ago
}
func short(s string) string {
scanner := bufio.NewScanner(strings.NewReader(s))
scanner.Scan()
title := fmt.Sprintf("%.50s", scanner.Text())
return title
}
func hasParent(child *git.Commit, father *git.Oid) bool {
for parent := uint(0); parent < child.ParentCount(); parent++ {
if *child.ParentId(parent) == *father {
return true
}
}
return false
}
func info1(r *git.Repository) map[string]*git.Commit {
walker, err := r.Walk()
if err != nil {
panic(err)
}
walker.Sorting(git.SortTime | git.SortTopological)
walker.PushHead()
head, err := r.Head()
if err != nil {
panic(err)
}
curId := head.Target()
commit, _ := r.LookupCommit(curId)
tree, _ := commit.Tree()
n := tree.EntryCount()
ids := make(map[string]git.Oid, n)
commits := make(map[string]*git.Commit, n)
times := make(map[string]time.Time, n)
for i := uint64(0); i < n; i++ {
entry := tree.EntryByIndex(i)
ids[entry.Name] = *entry.Id
commits[entry.Name] = commit
times[entry.Name] = commit.Author().When
}
for {
err := walker.Next(curId)
if err != nil {
break
}
commit, _ := r.LookupCommit(curId)
commitTime := commit.Author().When
tree, _ := commit.Tree()
for name, id := range ids {
entry := tree.EntryByName(name)
if entry != nil && *entry.Id == id {
commits[name] = commit
times[name] = commitTime
} else if commitTime.Before(times[name]) &&
hasParent(commits[name], curId) {
delete(ids, name)
n--
}
}
if commit.ParentCount() > 1 {
for j := uint(0); j < commit.ParentCount(); j++ {
parent := commit.Parent(j)
parentTime := parent.Author().When
tree, _ := parent.Tree()
for name, id := range ids {
entry := tree.EntryByName(name)
if entry != nil && *entry.Id == id {
if parentTime.Before(times[name]) {
commits[name] = parent
times[name] = parentTime
}
}
}
}
}
if n == 0 {
break
}
}
return commits
}
func info2(r *git.Repository) map[string]*git.Commit {
head, err := r.Head()
if err != nil {
panic(err)
}
commit, _ := r.LookupCommit(head.Target())
tree, _ := commit.Tree()
n := tree.EntryCount()
commits := make(map[string]*git.Commit, n)
for i := uint64(0); i < n; i++ {
entry := tree.EntryByIndex(i)
out, _ := exec.Command("git", "log", "-1", "--pretty=format:%H", "--", entry.Name).Output()
id, _ := git.NewOid(string(out))
commit, _ := r.LookupCommit(id)
commits[entry.Name] = commit
}
return commits
}
func main() {
f, err := os.Create("test.prof")
if err != nil {
log.Fatal(err)
}
pprof.StartCPUProfile(f)
defer pprof.StopCPUProfile()
r, err := git.OpenRepositoryExtended(os.Args[1], git.RepositoryOpenBare, "")
if err != nil {
panic(err)
}
os.Chdir(os.Args[1])
t1 := time.Now()
commits := info2(r)
fmt.Println(time.Since(t1).Seconds())
for key, commit := range commits {
fmt.Println(key, ago(commit.Author().When), short(commit.Message()),
commit.Id().String())
}
t1 = time.Now()
commits = info1(r)
fmt.Println(time.Since(t1).Seconds())
for key, commit := range commits {
fmt.Println(key, ago(commit.Author().When), short(commit.Message()),
commit.Id().String())
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment