parent
6ce4454ff7
commit
dfe3113910
1 changed files with 149 additions and 0 deletions
@ -0,0 +1,149 @@ |
|||||||
|
#!/usr/bin/env ruby |
||||||
|
|
||||||
|
# A small ruby script to extract a git history to a tikz picture |
||||||
|
# Author: Michael Hauspie <Michael.Hauspie@lifl.fr> |
||||||
|
# |
||||||
|
# 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() |
Loading…
Reference in new issue