<?xml version="1.0" encoding="UTF-8"?>
<commit>
  <added type="array">
    <added>
      <filename>README</filename>
    </added>
    <added>
      <filename>git-addremove</filename>
    </added>
    <added>
      <filename>git-all-commits</filename>
    </added>
    <added>
      <filename>git-apply-feature</filename>
    </added>
    <added>
      <filename>git-build</filename>
    </added>
    <added>
      <filename>git-changelog</filename>
    </added>
    <added>
      <filename>git-children-of</filename>
    </added>
    <added>
      <filename>git-current</filename>
    </added>
    <added>
      <filename>git-diff-directory</filename>
    </added>
    <added>
      <filename>git-empty-branch</filename>
    </added>
    <added>
      <filename>git-erase-reflog</filename>
    </added>
    <added>
      <filename>git-external-ediff</filename>
    </added>
    <added>
      <filename>git-find</filename>
    </added>
    <added>
      <filename>git-find-blob</filename>
    </added>
    <added>
      <filename>git-find-children</filename>
    </added>
    <added>
      <filename>git-find-fetch</filename>
    </added>
    <added>
      <filename>git-flush</filename>
    </added>
    <added>
      <filename>git-full-reset</filename>
    </added>
    <added>
      <filename>git-hunt-and-seek</filename>
    </added>
    <added>
      <filename>git-maxpack</filename>
    </added>
    <added>
      <filename>git-opendiff</filename>
    </added>
    <added>
      <filename>git-publish</filename>
    </added>
    <added>
      <filename>git-publish-repo</filename>
    </added>
    <added>
      <filename>git-push-branch</filename>
    </added>
    <added>
      <filename>git-record</filename>
    </added>
    <added>
      <filename>git-remove-empty-commits</filename>
    </added>
    <added>
      <filename>git-retrack</filename>
    </added>
    <added>
      <filename>git-rm-conflicts</filename>
    </added>
    <added>
      <filename>git-sh</filename>
    </added>
    <added>
      <filename>git-signed-tag</filename>
    </added>
    <added>
      <filename>git-snapshot</filename>
    </added>
    <added>
      <filename>git-sync</filename>
    </added>
    <added>
      <filename>git-trash</filename>
    </added>
    <added>
      <filename>git-unpack</filename>
    </added>
    <added>
      <filename>git-unwip</filename>
    </added>
    <added>
      <filename>git-wip</filename>
    </added>
  </added>
  <modified type="array">
    <modified>
      <diff>@@ -1,4 +1,2 @@
 #!/bin/sh
-for REMOTE in $(git remote); do
-  git push $REMOTE $*
-done
+for remote in $(git remote); do git push $remote; done</diff>
      <filename>git-push-all</filename>
    </modified>
    <modified>
      <diff>@@ -24,17 +24,15 @@
 
 class String
   def obfuscate; gsub(/@/, &quot; at the &quot;).gsub(/\.(\w+)(&gt;|$)/, ' dot \1s\2') end
-  def htmlize; gsub(&quot;&amp;&quot;, &quot;&amp;amp;&quot;).gsub(&quot;&lt;&quot;, &quot;&amp;lt;&quot;).gsub(&quot;&gt;&quot;, &quot;&amp;gt;&quot;) end
 end
 
 lines = {}
 verbose = ARGV.delete(&quot;-v&quot;)
 obfuscate = ARGV.delete(&quot;-o&quot;)
-htmlize = ARGV.delete(&quot;-h&quot;)
 
 author = nil
 state = :pre_author
-`git log -M -C -C -p --no-color`.each do |l|
+`git log -p --no-color`.each do |l|
   case
   when (state == :pre_author || state == :post_author) &amp;&amp; l =~ /Author: (.*)$/
     author = $1
@@ -51,7 +49,6 @@ end
 
 lines.sort_by { |a, c| -c }.each do |a, c|
   a = a.obfuscate if obfuscate
-  a = a.htmlize if htmlize
   if verbose
     puts &quot;#{a}: #{c} lines of diff&quot;
   else</diff>
      <filename>git-rank-contributors</filename>
    </modified>
    <modified>
      <diff>@@ -1,223 +1,195 @@
 #!/usr/bin/env ruby
 
-## git-wtf: display the state of your repository in a readable and easy-to-scan
-## format.
-##
-## git-wtf tries to ease the task of having many git branches. It's also useful
-## for getting a summary of how tracking branches relate to a remote server.
-##
-## git-wtf shows you:
-## - How your branch relates to the remote repo, if it's a tracking branch.
-## - How your branch relates to non-feature (&quot;version&quot;) branches, if it's a
-##   feature branch.
-## - How your branch relates to the feature branches, if it's a version branch.
-##
-## For each of these relationships, git-wtf displays the commits pending on
-## either side, if any. It displays checkboxes along the side for easy scanning
-## of merged/non-merged branches.
-##
-## If you're working against a remote repo, git-wtf is best used between a 'git
-## fetch' and a 'git merge' (or 'git pull' if you don't mind the redundant
-## network access).
-##
-## Usage: git wtf [branch+] [-l|--long] [-a|--all] [--dump-config]
-##
-## If [branch] is not specified, git-wtf will use the current branch.  With
-## --long, you'll see author info and date for each commit. With --all, you'll
-## see all commits, not just the first 5. With --dump-config, git-wtf will
-## print out its current configuration in YAML format and exit.
-##
-## git-wtf uses some heuristics to determine which branches are version
-## branches, and which are feature branches. (Specifically, it assumes the
-## version branches are named &quot;master&quot;, &quot;next&quot; and &quot;edge&quot;.) If it guesses
-## incorrectly, you will have to create a .git-wtfrc file.
-##
-## git-wtf looks for a .git-wtfrc file starting in the current directory, and
-## recursively up to the root. The config file is a YAML file that specifies
-## the version branches, any branches to ignore, and the max number of commits
-## to display when --all isn't used. To start building a configuration file,
-## run &quot;git-wtf --dump-config &gt; .git-wtfrc&quot; and edit it.
-##
-## IMPORTANT NOTE: all local branches referenced in .git-wtfrc must be prefixed
-## with heads/, e.g. &quot;heads/master&quot;. Remote branches must be of the form
-## remotes/&lt;remote&gt;/&lt;branch&gt;.
-##
-## git-wtf Copyright 2008 William Morgan &lt;wmorgan-git-wt-add@masanjin.net&gt;.
-## This program is free software: you can redistribute it and/or modify it
-## under the terms of the GNU General Public License as published by the Free
-## Software Foundation, either version 3 of the License, or (at your option)
-## any later version.
-##
-## This program is distributed in the hope that it will be useful, but WITHOUT
-## ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
-## FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
-## more details.
-##
-## You can find the GNU General Public License at: http://www.gnu.org/licenses/
-
+$debug = false
 
 require 'yaml'
-CONFIG_FN = &quot;.git-wtfrc&quot;
+CONFIG_FILENAME = &quot;.git-wtf&quot;
+
+begin
+  require 'rubygems'
+  require 'term/ansicolor'
+  HAS_COLOR=true
+  include Term::ANSIColor
+rescue LoadError
+  HAS_COLOR=false
+end
 
 class Numeric; def pluralize s; &quot;#{to_s} #{s}&quot; + (self != 1 ? &quot;s&quot; : &quot;&quot;) end end
 
-$long = ARGV.delete(&quot;--long&quot;) || ARGV.delete(&quot;-l&quot;)
-$all = ARGV.delete(&quot;--all&quot;) || ARGV.delete(&quot;-a&quot;)
-$dump_config = ARGV.delete(&quot;--dump-config&quot;)
-
-## find config file
-$config = { &quot;versions&quot; =&gt; %w(heads/master heads/next heads/edge), &quot;ignore&quot; =&gt; [], &quot;max_commits&quot; =&gt; 5 }.merge begin
-  p = File.expand_path &quot;.&quot;
-  fn = while true
-    fn = File.join p, CONFIG_FN
-    break fn if File.exist? fn
-    pp = File.expand_path File.join(p, &quot;..&quot;)
-    break if p == pp
-    p = pp
+class Hash
+  def leaves
+    children = values.select { |v| v.is_a?(Hash) }
+    children.length &gt; 0 ? children.map { |c| c.leaves }.flatten : self
   end
-
-  (fn &amp;&amp; YAML::load_file(fn)) || {} # YAML turns empty files into false
-end
-
-if $dump_config
-  puts $config.to_yaml
-  exit(0)
 end
 
-## the set of commits in 'to' that aren't in 'from'.
-## if empty, 'to' has been merged into 'from'.
-def commits_between from, to
-  if $long
-    `git log --pretty=format:&quot;- %s [%h] (%ae; %ar)&quot; #{from}..#{to}`
-  else
-    `git log --pretty=format:&quot;- %s [%h]&quot; #{from}..#{to}`
-  end.split(/[\r\n]+/)
+def die s
+  $stderr.puts &quot;Error: #{s}&quot;
+  exit(-1)
 end
 
-def show_commits commits, prefix=&quot;    &quot;
-  if commits.empty?
-    puts &quot;#{prefix} none&quot;
+COLOR_ATTRIBUTES = {
+  0 =&gt; black,
+  1 =&gt; red,
+  2 =&gt; green,
+  3 =&gt; yellow,
+  4 =&gt; blue,
+  5 =&gt; magenta,
+  6 =&gt; cyan,
+  7 =&gt; dark,
+  8 =&gt; bold,
+  9 =&gt; reset
+} if HAS_COLOR
+
+def cputs(string='')
+  if HAS_COLOR
+    COLOR_ATTRIBUTES.each { |num, color| string.gsub!(&quot;&amp;|#{num}&quot;, color) }
   else
-    max = $all ? commits.size : $config[&quot;max_commits&quot;]
-    max -= 1 if max == commits.size - 1 # never show &quot;and 1 more&quot;
-    commits[0 ... max].each { |c| puts &quot;#{prefix}#{c}&quot; }
-    puts &quot;#{prefix}... and #{commits.size - max} more.&quot; if commits.size &gt; max
+    string.gsub!(/&amp;\|\d/, '')
   end
+  puts string
 end
 
-def ahead_behind_string ahead, behind
-  [ahead.empty? ? nil : &quot;#{ahead.size.pluralize 'commit'} ahead&quot;,
-   behind.empty? ? nil : &quot;#{behind.size.pluralize 'commit'} behind&quot;].
-   compact.join(&quot;; &quot;)
-end
+def run_command(command)
+  output = IO.popen(command, 'r').read
 
-def show b, all_branches
-  puts &quot;Local branch: #{b[:local_branch]}&quot;
-  both = false
-
-  if b[:remote_branch]
-    pushc = commits_between b[:remote_branch], b[:local_branch]
-    pullc = commits_between b[:local_branch], b[:remote_branch]
-
-    both = !pushc.empty? &amp;&amp; !pullc.empty?
-    if pushc.empty?
-      puts &quot;[x] in sync with remote&quot;
-    else
-      action = both ? &quot;push after rebase / merge&quot; : &quot;push&quot;
-      puts &quot;[ ] NOT in sync with remote (needs #{action})&quot;
-      show_commits pushc
-    end
-
-    puts &quot;\nRemote branch: #{b[:remote_branch]} (#{b[:remote_url]})&quot;
+  if $debug
+    cputs &quot;-- begin run_command --&quot;
+    cputs &quot;executing: #{command}&quot;
+    cputs &quot;output:&quot;
+    cputs output
+    cputs &quot;-- end run_command --&quot;
+  end
 
-    if pullc.empty?
-      puts &quot;[x] in sync with local&quot;
-    else
-      action = pushc.empty? ? &quot;merge&quot; : &quot;rebase / merge&quot;
-      puts &quot;[ ] NOT in sync with local (needs #{action})&quot;
-      show_commits pullc
+  output
+end
 
-      both = !pushc.empty? &amp;&amp; !pullc.empty?
-    end
+def commits_between from, to
+  commits = run_command(%{ git log --pretty=format:&quot;%h-%ae-%s&quot; #{from}..#{to} }).split(/[\r\n]+/).map do |raw_commit|
+    raw_commit_parts = raw_commit.split('-')
+
+    {
+      :hash    =&gt; raw_commit_parts.shift,
+      :author  =&gt; raw_commit_parts.shift.split('@').first,
+      :message =&gt; raw_commit_parts.join('-')
+    }
   end
-
-  vbs, fbs = all_branches.partition { |name, br| $config[&quot;versions&quot;].include? br[:local_branch] }
-  if $config[&quot;versions&quot;].include? b[:local_branch]
-    puts &quot;\nFeature branches:&quot; unless fbs.empty?
-    fbs.each do |name, br|
-      remote_ahead = b[:remote_branch] ? commits_between(b[:remote_branch], br[:local_branch]) : []
-      local_ahead = commits_between b[:local_branch], br[:local_branch]
-      if local_ahead.empty? &amp;&amp; remote_ahead.empty?
-        puts &quot;[x] #{br[:name]} is merged in&quot;
-      elsif local_ahead.empty? &amp;&amp; b[:remote_branch]
-        puts &quot;(x) #{br[:name]} merged in (only locally)&quot;
-      else
-        behind = commits_between br[:local_branch], b[:local_branch]
-        puts &quot;[ ] #{br[:name]} is NOT merged in (#{ahead_behind_string local_ahead, behind})&quot;
-        show_commits local_ahead
-      end
-    end
-  else
-    puts &quot;\nVersion branches:&quot; unless vbs.empty? # unlikely
-    vbs.each do |v, br|
-      ahead = commits_between v, b[:local_branch]
-      if ahead.empty?
-        puts &quot;[x] merged into #{v}&quot;
-      else
-        #behind = commits_between b[:local_branch], v
-        puts &quot;[ ] NOT merged into #{v} (#{ahead.size.pluralize 'commit'} ahead)&quot;
-        show_commits ahead
-      end
-    end
+  
+  max_author_size = commits.map { |c| c[:author].length }.sort.last
+  
+  commits.map do |commit|
+    &quot;[&amp;|2%s&amp;|9] &amp;|8&amp;|4%#{max_author_size}s&amp;|9 %s&quot; % [commit[:hash], commit[:author], commit[:message]]
   end
+end
 
-  puts &quot;\nWARNING: local and remote branches have diverged. A merge will occur unless you rebase.&quot; if both
+begin
+  $config = YAML::load_file(CONFIG_FILENAME)
+  raise 'invalid configuration format' unless $config[&quot;version_branches&quot;].length &gt; 0
+rescue
+  # cputs &lt;&lt;-CONFIG.gsub(/^  /, '')
+  # Create a .git-wtf in your git repository directory that looks like:
+  # --
+  # version_branches:
+  #   - stable-2.0
+  # CONFIG
+  # exit 1
+  $config = { 'version_branches' =&gt; [] }
 end
 
-branches = `git show-ref`.inject({}) do |hash, l|
-  sha1, ref = l.chomp.split &quot; refs/&quot;
-  next hash if $config[&quot;ignore&quot;].member? ref
-  next hash unless ref =~ /^heads\/(.+)/
-  name = $1
-  hash[name] = { :name =&gt; name, :local_branch =&gt; ref }
-  hash
+current_branch = File.read(File.join('.git', 'HEAD')).chomp.split('/').last
+
+$branches = Dir[File.join('.git', 'refs', 'heads', '*')].inject({}) do |hash, ref|
+  name    = File.basename(ref)
+  rev     = File.read(ref).chomp
+  current = (name == current_branch)
+  version = $config[&quot;version_branches&quot;].include?(name)
+  remote  = run_command(&quot;git config --get branch.#{name}.remote&quot;).chomp
+  merge   = run_command(&quot;git config --get branch.#{name}.merge&quot;).chomp.split('/').last
+
+  hash.update({ name =&gt; {
+    :name    =&gt; name,
+    :rev     =&gt; rev,
+    :current =&gt; current,
+    :version =&gt; version,
+    :merge   =&gt; { :remote =&gt; remote, :branch =&gt; merge }
+  }})
 end
 
-remotes = `git config --get-regexp ^remote\.\*\.url`.inject({}) do |hash, l|
-  l =~ /^remote\.(.+?)\.url (.+)$/ or next hash
-  hash[$1] ||= $2
+$remotes = Dir[File.join('.git', 'refs', 'remotes', '*', '*')].inject({}) do |hash, ref|
+  ref_parts = ref.split('/')
+  name   = ref_parts.pop
+  remote = ref_parts.pop
+  rev    = File.read(ref).chomp
+  hash[remote] ||= {}
+  hash[remote][name] = { :name =&gt; name, :remote =&gt; remote, :rev =&gt; rev }
   hash
 end
 
-`git config --get-regexp ^branch\.`.each do |l|
-  case l
-  when /branch\.(.*?)\.remote (.+)/
-    branches[$1] ||= {}
-    branches[$1][:remote] = $2
-    branches[$1][:remote_url] = remotes[$2]
-  when /branch\.(.*?)\.merge ((refs\/)?heads\/)?(.+)/
-    branches[$1] ||= {}
-    branches[$1][:remote_mergepoint] = $4
+$branches.each do |name, branch|
+  $branches[name][:parent] = begin
+    merge  = branch[:merge] 
+    remote = merge[:remote] == '.' ? $branches : $remotes[merge[:remote]]
+    remote ? remote[merge[:branch]] : nil
   end
 end
 
-branches.each { |k, v| v[:remote_branch] = &quot;#{v[:remote]}/#{v[:remote_mergepoint]}&quot; if v[:remote] &amp;&amp; v[:remote_mergepoint] }
-
-show_dirty = ARGV.empty?
-targets = if ARGV.empty?
-  [`git symbolic-ref HEAD`.chomp.sub(/^refs\/heads\//, &quot;&quot;)]
-else
-  ARGV
-end.map { |t| branches[t] or abort &quot;Error: can't find branch #{t.inspect}.&quot; }
+repo = {
+  :master   =&gt; ($branches.values + $remotes['origin'].values).detect { |b| b[:name] == 'master' },
+  :current  =&gt; $branches.values.detect { |b| b[:current] },
+  :versions =&gt; $branches.values.select { |b| b[:version] },
+  :features =&gt; $branches.values.select { |b| !(b[:version] || b[:name] == 'master') },
+  :remotes  =&gt; $remotes
+}
+
+def branch_sync_status(local, remote, show_outgoing=true, show_incoming=true, good=&quot;in sync&quot;, bad=&quot;out of sync&quot;)
+  outgoing = show_outgoing ? commits_between(remote[:rev], local[:rev])  : []
+  incoming = show_incoming ? commits_between(local[:rev],  remote[:rev]) : []
+
+  sync = (incoming.length == 0 &amp;&amp; outgoing.length == 0)
+
+  verb = case
+    when incoming.length &gt; 0 &amp;&amp;
+         outgoing.length &gt; 0 then 'merge'
+    when incoming.length &gt; 0 then 'pull'
+    when outgoing.length &gt; 0 then 'push'
+    else nil
+  end
 
-targets.each { |t| show t, branches }
+  cputs sync ? &quot;[x] #{good}&quot; : &quot;[ ] #{bad}&quot;
+  incoming.each { |c| cputs &quot;    &amp;|8&amp;|3&lt;&amp;|9 #{c}&quot; }
+  outgoing.each { |c| cputs &quot;    &amp;|8&amp;|3&gt;&amp;|9 #{c}&quot; }
+end
 
-modified = show_dirty &amp;&amp; `git ls-files -m` != &quot;&quot;
-uncommitted = show_dirty &amp;&amp;  `git diff-index --cached HEAD` != &quot;&quot;
+def name(branch)
+  if $remotes.leaves.include?(branch)
+    &quot;#{branch[:remote]}/#{branch[:name]}&quot;
+  else
+    &quot;#{branch[:name]}&quot;
+  end
+end
 
-puts if modified || uncommitted
-puts &quot;NOTE: working directory contains modified files&quot; if modified
-puts &quot;NOTE: staging area contains staged but uncommitted files&quot; if uncommitted
+cputs &quot;Local Branch: #{name(repo[:current])}&quot;
+branch_sync_status(repo[:current], repo[:current][:parent], true, true, &quot;in sync with remote&quot;, &quot;out of sync with remote (#{repo[:current][:parent][:remote]}/#{repo[:current][:parent][:name]})&quot;) if repo[:current][:parent]
+cputs
 
-# the end!
+if repo[:current] == repo[:master]
+  if repo[:versions].length &gt; 0
+    cputs &quot;Version branches:&quot;
+    repo[:versions].each do |branch|
+      branch_sync_status(repo[:current], branch, false, true, &quot;#{branch[:name]} is merged in&quot;, &quot;#{branch[:name]} needs to be merged in&quot;)
+    end
+    cputs
+  end
+elsif repo[:versions].include?(repo[:current])
+  master = repo[:master]
+  cputs &quot;Master Branch: #{name(master)}&quot;
+  branch_sync_status(repo[:current], master, true, false, &quot;in sync&quot;, &quot;#{name(repo[:current])} needs to be merged into master&quot;)
+  cputs
+end
 
+if repo[:features].length &gt; 0
+  cputs &quot;Feature branches:&quot;
+  repo[:features].each do |branch|
+    branch_sync_status(repo[:current], branch, false, true, &quot;#{branch[:name]} is merged in&quot;, &quot;#{branch[:name]} needs to be merged in&quot;)
+  end
+end
\ No newline at end of file</diff>
      <filename>git-wtf</filename>
    </modified>
  </modified>
  <removed type="array">
    <removed>
      <filename>git-branch-status</filename>
    </removed>
    <removed>
      <filename>git-diff</filename>
    </removed>
  </removed>
  <parents type="array">
    <parent>
      <id>b07501100370ec5813b11fe56bcac9c37fa213a4</id>
    </parent>
  </parents>
  <author>
    <name>Carlos Villela</name>
    <email>cv@lixo.org</email>
  </author>
  <url>http://github.com/cv/git-utils/commit/5322b45051291dd65fd69d1b6871a6801cc2d907</url>
  <id>5322b45051291dd65fd69d1b6871a6801cc2d907</id>
  <committed-date>2009-03-05T16:58:42-08:00</committed-date>
  <authored-date>2009-03-05T16:58:42-08:00</authored-date>
  <message>merged with ddollar</message>
  <tree>e730981f7c1070e72dd0565029052668b3c5d094</tree>
  <committer>
    <name>Carlos Villela</name>
    <email>cv@lixo.org</email>
  </committer>
</commit>
