TamaMcGlinn / git-forest

git-forest is a visual terminal tree viewer to replace `git log --graph`
3 stars 1 forks source link

Forest

Forest is a tool intended to replace git log --graph with something prettier. I made this repo because it was maddening to me that there are all these forks and copies of (git-)forest(a) and no clarity regarding their differences.

In order to integrate git-forest into vim-flog, I wanted to first be sure that I have all features and bugfixes merged into one repo.

Forks / Copies

Forest was originally created in 2008 Jan Engelhardt. His repository is still present here, but I have pushed this github mirror so that I can share http links to commits.

There are four forks that I am aware of, and vim-flog-forest is an attempt to reconcile all their improvements, while staying compatible with vim-flog.

Key differences

Fix hxtools git-forest

The original hxtools git-forest needs this modification to even run on modern perl versions:

@@ -12,7 +12,7 @@
 use Getopt::Long;
 use Git;
 use strict;
-use encoding "utf8";
+use utf8;
 my $Repo          = Git->repository($ENV{"GIT_DIR"} || ".");
 my $Pretty_fmt    = "format:%s";
 my $Reverse_order = 0;

Coloured branches with git-foresta

Git-foresta chooses a colour for each branch, and sticks with it, making it easier to see which commits belong to each.

But, git-foresta doesn't support vim-flog

As mentioned here, git-foresta does not accept a custom format, and hence vim-flog won't work.

Benchmark

Using hyperfine, I found the original hxtools git-forest is 10% faster than the git-scripts' version, and 15% faster than git-foresta.

Benchmark #1: ./git-foresta
  Time (mean ± σ):      73.2 ms ±   1.0 ms    [User: 60.0 ms, System: 16.1 ms]
  Range (min … max):    71.6 ms …  75.2 ms    40 runs

Benchmark #2: ../hxtools/sdevel/git-forest
  Time (mean ± σ):      63.4 ms ±   1.0 ms    [User: 52.5 ms, System: 13.1 ms]
  Range (min … max):    61.6 ms …  65.6 ms    46 runs

Benchmark #3: ../git-scripts/git-forest
  Time (mean ± σ):      70.0 ms ±   0.8 ms    [User: 61.2 ms, System: 10.9 ms]
  Range (min … max):    68.2 ms …  71.6 ms    42 runs

Summary
  '../hxtools/sdevel/git-forest' ran
    1.10 ± 0.02 times faster than '../git-scripts/git-forest'
    1.15 ± 0.02 times faster than './git-foresta'

Grafting repo's

In order to be able to reconcile these copies, I set out to find versions of each that correspond to each other, so that the version in one repo can be rebased onto the other. I found:

First, each repository is converted to only contain git-forest. Then, they can be merged.

extract_hxtools

For hxtools, we use git filter-branch --tree-filter '~/code/forest_forks/extract_hxtools' --prune-empty -f HEAD.

The following extract_hxtools script deletes everything but git-forest, and ensures it is called git-forest and in the root of the repo:

#!/usr/bin/env bash

find . -type d | grep -v '^\./\.git\|^\.$\|^\./sdevel$\|^\./bin$' | xargs rm -rf
find . -type f | grep -v '^\./\.git\|git-forest$' | xargs rm -f
rm -f .gitignore
rm -f NEWS.rst

if [[ -f "bin/git-forest" ]]; then
  mv bin/git-forest .
fi
if [[ -f "sdevel/git-forest" ]]; then
  mv sdevel/git-forest .
fi

rm -rf sdevel
rm -rf bin

The resulting filtered hxtools history of git-forest is available as hxtools_git_forest.

extract_git-scripts

Similarly for git-scripts, there is git filter-branch --tree-filter '~/code/forest_forks/extract_git-scripts' --prune-empty -f HEAD.

#!/usr/bin/env bash

find . -type d | grep -v '^\./\.git\|^\.$' | xargs rm -rf
find . -type f | grep -v '^\./\.git\|git-forest$' | xargs rm -f
find . -type l | xargs rm
rm -f .gitignore

Because the script was removed and then re-added, this leaves some noise commits near the root of the repo, which are removed by magic. Finally, the unnecessary merges are removed with a rebase without --preserve-merges onto the aforementioned corresponding commit in hxtools.

The resulting filtered git-scripts history of git-forest is available as git_scripts_forest.

extract_foresta

And for git-foresta, git filter-branch --tree-filter '~/code/forest_forks/extract_foresta' --prune-empty -f HEAD

#!/usr/bin/env bash

find . -type d | grep -v '^\./\.git\|^\.$\|^\./script$' | xargs rm -rf
find . -type f | grep -v '^\./\.git\|git-foresta$' | xargs rm -f
rm -f .gitignore

if [[ -f "script/git-foresta" ]]; then
  mv script/git-foresta git-forest
fi
if [[ -f "git-foresta" ]]; then
  mv git-foresta git-forest
fi

rm -rf script/

The resulting filtered git-foresta history of git-forest is available as git_foresta.