Created
April 16, 2012 09:20
-
-
Save hauspie/2397222 to your computer and use it in GitHub Desktop.
Extract git history to tikz picture
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#!/usr/bin/env ruby | |
# A small ruby script to extract a git history to a tikz picture | |
# Author: Michael Hauspie <[email protected]> | |
# | |
# Not clean code, not always working well, but does its job in most of the cases I needed :) | |
# A commit object | |
class Commit | |
attr_accessor :hash | |
attr_accessor :children | |
attr_accessor :parents | |
attr_accessor :message | |
attr_reader :node_pos | |
# Construct a commit from a line | |
# A line is commit_hash [child1_hash ... childN_hash] message | |
def initialize() | |
@hash = nil | |
@children = Hash.new() | |
@parents = Hash.new() | |
@message = "" | |
@node_pos = 0 | |
@message_pos = 0 | |
end | |
def build(line) | |
# Parse each word to match a hash or the commmit message | |
pos=0 | |
line.split(" ").each do |word| | |
if word =~ /[a-f0-9]{7}/ && @message == "" # match a short sha-1 commit tag | |
if ! @hash | |
@hash = word | |
else | |
@parents[word] = nil | |
end | |
elsif word == '*' # Position of the node | |
@node_pos = pos | |
elsif word =~ /[^|\/\\]/ | |
@message_pos = pos | |
@message << " #{word}" | |
end | |
pos = pos + 1 | |
end | |
@message.delete!("!") | |
@message.lstrip!() | |
if !@hash | |
return false | |
end | |
return true | |
end | |
# sets a child object | |
def set_parent(c) | |
@parents[c.hash] = c | |
c.children[@hash] = self | |
end | |
def export_to_tikz(ypos) | |
puts "\\node[commit] (#{@hash}) at (#{0.5*@node_pos},#{ypos}) {};" | |
puts "\\node[right,xshift=#{@message_pos*0.5}] (label_#{@hash}) at (#{@hash}.east) {\\verb!#{@hash} #{@message}!};" | |
@children.each_value do |child| | |
puts "\\draw[->] (#{@hash}) -- (#{child.hash});" | |
end | |
end | |
def to_s() | |
"#{@hash}: #{@message} #{@node_pos} #{@message_pos}" | |
end | |
end | |
class Branch | |
attr_accessor :name | |
attr_accessor :hash | |
attr_accessor :commit | |
def initialize(line) | |
words = line.split(" ") | |
@name = words[0] | |
@hash = words[1] | |
@commit = nil | |
end | |
end | |
# A repository, which is a collection of commit objects and branches | |
class Repository | |
def initialize() | |
@commits = Hash.new() | |
@branches = Array.new() | |
end | |
def add_commit(commit) | |
@commits[commit.hash] = commit | |
end | |
def add_branch(branch) | |
if ! @commits.has_key?(branch.hash) | |
return false | |
end | |
c = @commits.fetch(branch.hash) | |
branch.commit = c | |
@branches << branch | |
return true | |
end | |
# This iterates other commits and resolves its parents | |
def resolve_parents() | |
@commits.each_value do |commit| | |
commit.parents.keys.each do |parent_hash| | |
c = @commits.fetch(parent_hash) | |
commit.set_parent(c) # Link the commit object to its parent | |
end | |
end | |
end | |
def export_to_tikz | |
puts "\\begin{tikzpicture}" | |
ypos=0 | |
ystep=-0.5 | |
@commits.each_value do |commit| | |
commit.export_to_tikz(ypos) | |
ypos = ypos + ystep | |
end | |
@branches.each do |branch| | |
puts "\\node[branch,right,xshift=.1] (#{branch.name}) at (label_#{branch.hash}.east) {\\texttt{#{branch.name}}};" | |
end | |
puts "\\end{tikzpicture}" | |
end | |
end | |
r = Repository.new() | |
# Extract commits | |
`git log --graph --branches --oneline --parents`.lines().each do |line| | |
c = Commit.new() | |
if c.build(line) | |
r.add_commit(c) | |
end | |
end | |
r.resolve_parents() | |
# Extract branches | |
`git branch -av | cut -b 3-`.lines().each do |line| | |
r.add_branch(Branch.new(line)) | |
end | |
r.export_to_tikz() |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment