Novice C
Novice C

Reputation: 1374

How to do alignment in git logs with graph

With something like git log --abbrev-commit --pretty=format:'%h %<(72,trunc)%s %d', you can get a fairly well aligned git commit message with a graph. It is completely aligned if you drop the --graph option. Here is roughly what the command looks like

*   40f1481 Commit title message        (HEAD, dev)
|\                                                                     
| * 9b5122d Commit title message        (debug)
| * fe7ddfe Commit title message               
| * 8e4d414 Commit title message      
| * 53affdd Commit title message    
| * a45fbaf Commit title message             
|/                                                                     
* 36b23c3 Commit title message                     
* 5b7bfe1 Commit title message        (master)

The issue is that with the graph symbols the alignment is messed up, as you can see in the first two commits. Here is what it should ideally look like

*   40f1481 Commit title message        (HEAD, dev)
|\                                                                     
| * 9b5122d Commit title message        (debug)
| * fe7ddfe Commit title message               
| * 8e4d414 Commit title message      
| * 53affdd Commit title message    
| * a45fbaf Commit title message             
|/                                                                     
*   36b23c3 Commit title message                     
*   5b7bfe1 Commit title message        (master)

My question is there an option for getting the correct alignment when using the graphing option? Or to get the width of the graph so that you can pad the log accordingly?


I know a quick hack would be to just pad the first option by tab (%x09), and it should work for probably most projects, but I'm wondering if their is a aesthetically superior, foolproof option that gets by with the minimum padding but also works in cases where 5 wouldn't be enough. Here is an example where the tab solution fails

enter image description here


Log with using columns, without colored graph.

enter image description here


Complete success! Will try to update later.

enter image description here

Upvotes: 6

Views: 3328

Answers (6)

tfpf
tfpf

Reputation: 682

Matplotlib commits

Here's what I have in ~/.gitconfig.

[alias]
    l = log --graph --pretty='%C(yellow)%h%C(reset) %C(brightblack)%cd%C(reset) %C(cyan)%>|(64,trunc)%an%C(reset) %C(auto)%(decorate:pointer= ,prefix=,separator= ,suffix= ,tag=)%C(reset)%<|(-1,trunc)%s'
    ll = l --all
[log]
    date = iso

Rationale: do not remove any information git log shows by default, and do not truncate anything which reduces the information conveyed (meaning that only author names and commit messages may be truncated).

  • %C(yellow)%h%C(reset): write the abbreviated commit hash in yellow.
  • %C(brightblack)%cd%C(reset): write the commit date, respecting the log.date configuration (iso in this case) in grey.
  • %C(cyan)%>|(64,trunc)%an%C(reset): write the author's name right-aligned to the 64th column (right-truncating it if necessary) in cyan.
  • %C(auto)%(decorate:pointer= ,prefix=,separator= ,suffix= ,tag=)%C(reset): write HEAD and the branch it points to with a space in between, and the tag (if any) without a prefix, but use the colours which would normally be used when git log is invoked without any of these configurations or additional options; do not enclose these in brackets or use separating commas, but add a space at the end.
  • %<|(-1,trunc)%s: write the commit message only up to the penultimate column (right-truncating it if necessary) in the default colour.

Customise the pretty format to your liking using the manual: see PRETTY FORMATS, Git - git-log Documentation.

Upvotes: 0

Juarez Rudsatz
Juarez Rudsatz

Reputation: 447

Here are other simple git aliases for git log with excellent results.

What is mostly working:

  • Automatically determines appropriate width for each field
  • Right aligns branch/ref and author
  • Works fine with narrow terminal widths

Add this in the $HOME/.gitconfig file:

[alias]
  l = !git log -n $(($(tput lines) / 2)) --date=format:'%y-%m-%d %H:%I' --pretty=format:'%Cred%h %Cgreen%ad %C(bold 0)%s%C(yellow)%>>|('"$(($(tput cols)-18))"')% D%C(bold blue)%<(16,trunc)% aL%Creset'

  ll = !git log -n $(($(tput lines) / 4)) --date=format:'%y-%m-%d %H:%I' --pretty=format:'%Cred%h %Cgreen%ad %C(bold 0)%s%C(yellow)%>>|('"$(($(tput cols)-18))"')% D%C(bold blue)%<(16,trunc)% aL%Creset%b'

  ls = !git log --stat -n $(($(tput lines) / 5)) --date=format:'%y-%m-%d %H:%I' --pretty=format:'%Cred%h %Cgreen%ad %C(bold 0)%s%C(yellow)%>>|('"$(($(tput cols)-18))"')% D%C(bold blue)%<(16,trunc)% aL%Creset'

  lg = !git log --graph -n $(($(tput lines) / 2)) --date=format:'%y-%m-%d %H:%I' --pretty=format:'%Cred%>|(13)%h %Cgreen%ad %C(bold 0)%s%C(yellow)%>>|('"$(($(tput cols)-18))"')% D%C(bold blue)%<(16,trunc)% aL%Creset'

  lb = !git log --simplify-by-decoration -n $(($(tput lines) / 2)) --date=format:'%y-%m-%d %H:%I' --pretty=format:'%Cred%h %Cgreen%ad %C(bold 0)%s%C(yellow)%>>|('"$(($(tput cols)-18))"')% D%C(bold blue)%<(16,trunc)% aL%Creset'

Upvotes: 0

Murat Guchetl
Murat Guchetl

Reputation: 111

Modern versions of Git (I have git 2.17.0 on cygwin environment) work fine with colorized graph and indentation without any additional tools or scripts.

My .gitconfig aliases part:

[alias]
    l   = log --graph --abbrev-commit --decorate=no --date=format:'%Y-%m-%d %H:%I:%S' --format=format:'%C(03)%>|(26)%h%C(reset)  %C(04)%ad%C(reset)  %C(green)%<(16,trunc)%an%C(reset)  %C(bold 1)%d%C(reset) %C(bold 0)%>|(1)%s%C(reset)' --all

I have tested it on django official repository and it works great:

Upvotes: 11

user1133275
user1133275

Reputation: 2734

#!/bin/bash

#
# git_tree.sh
#

N="$1"
if [ "$N" == "" ] ; then
    N=9
fi
P="$(git log --graph --format=format:'%m%n%m' --all -n "$N" \
    | perl -pe 's/././g' \
    | sort -r \
    | head -n 1 \
    | wc -c)"
P2=$((P+7))
git log --graph \
    --date=format:'%Y-%m-%d %H:%I:%S' \
    --all \
    -n "$N" \
    --format=format:"%C(03)%>|($P2)%h%C(reset) %C(04)%ad%C(reset) %C(green)%<(8,trunc)%an %C(1)%d%C(reset)%n%>|($P) %m %s"
echo

Upvotes: 0

EmceeBC
EmceeBC

Reputation: 71

The bash function below is my solution to aligning git log columns with wrapped text and having support for color and graph lines.

Features :

  • Supports Linux bash as well as macOS/BSD variants.
  • Written to support lowest common denominator for installed OS and sed versions.
  • Automatically determines appropriate width for commit hashes
  • Works with or without the following git log options : --color , --graph , --name-status.
  • Keeps column alignment for graph lines while using the --color option by removing color only on graph lines from wrapped text. all other color perserved.
  • Shows tags and other reference markers immediately below the message column and preserves their colors.

Known issue :

  • Since I support both BSD and linux variants of sed, the posix compliant ($) sed commands did not take advantage of back references. This is because BSD does not support back-references in that mode. Therefore, Instead of using one sed command to remove color from the graph lines I used 4.

Requires : Git 1.9.5 or later for non-graph options. Versions slightly newer than 1.9.5 of git are needed for correct alignment of wrapped text when graph’s are present

Future improvements :

  • Automatically adjust columns widths for author.
  • Consider alternate solution which keeps the color of the graph lines by adjusting alignment based on the number of control characters encountered instead of removing the color codes.

Bash Code

function gitlog
{

   # Check for the existence of certain git log arguments 
   local using_graph=false
   local arg_i
   for arg_i in "$@"
   do 
      if [ "$arg_i" = "--graph" ]; then
         using_graph=true
      fi 
      if [ "$arg_i" = "--oneline" ]; then
         printf -- "--oneline not allowed for this shell function.\n  use regular git log for oneline.\n" 
         return 1
      fi 
   done

   # Set the OS dependant options
   # my_system_type can be set by sourcing my .bashrc
   local sed_regex_sym="r"
   if [ ! -z "$my_system_type" ]; then
      if [ "$my_system_type" = Mac ]; then
         sed_regex_sym="E"
      fi
   fi

   # Set the pre-determined column sizes here
   local N_AUTH_DATE_CHARS=11
   local N_AUTH_NAME_CHARS=15

   # Determine where to place columns for the various content
   local scrn_sz_arr=( $(stty size) )  #stty not tput in case of missing TERMINFO
   local N_SCRN_COLS=${scrn_sz_arr[1]}
   local N_HASH_CHARS=$(git log --pretty=format:%h -1 | tr -d '\n' | wc -c | tr -d '[:space:]')
   if [ "$using_graph" = true ]; then 
      local N_GRPH_MAX_CHARS=$(expr $N_SCRN_COLS / 5) #Use no more then 20% of screen
      local N_GRPH_ACT_CHARS=$(git log --graph --pretty=format:"%<(1,trunc)%ad" | tr -d '..' | \
                               awk '{print length}' | sort -nr | head -1 | tr -d '[:space:]')
      if [ "$N_GRPH_ACT_CHARS" -lt "$N_GRPH_MAX_CHARS" ]; then
         local N_GRPH_RSRV_CHARS=$N_GRPH_ACT_CHARS
      else
         local N_GRPH_RSRV_CHARS=$N_GRPH_MAX_CHARS
      fi
      #Extend space of N_HASH_CHARS to keep alignment when --graph option used.
      N_HASH_CHARS=$(expr $N_HASH_CHARS + $N_GRPH_RSRV_CHARS)
   fi
   local N_MSG_INDENT_CHARS=$(expr $N_HASH_CHARS + 1 + $N_AUTH_DATE_CHARS + $N_AUTH_NAME_CHARS + 1)
   local N_STAT_INDENT_CHARS=$(expr $N_MSG_INDENT_CHARS + 2)

   # Check that there is sufficient room to place all the content
   local N_MIN_COLS=$(expr $N_STAT_INDENT_CHARS + 12)
   if [ "$N_MIN_COLS" -gt "$N_SCRN_COLS" ]; then
      printf -- "Terminal window too narrow.\nNeed at least $N_MIN_COLS cols for this mode.\n"
      return 1
   fi

   # Git log logic below is as follows
   #   - use date=short to minimize space used by that column.  Linked with 
   #        N_AUTH_DATE_CHARS
   #   - use --pretty-format to specify columns as 
   #        hash--author date--author name--commit message.
   #   - first 4 sed statement removes color (if present) from graph lines 
   #        containing wrapped pretty-print text. Done for aligment of wrapped 
   #        text. Was one sed using back references, but that was not compatible
   #        with BSD (OSX) sed with -E.
   #   - fifth sed blanks out graph lines from newlines that were introduced 
   #        between commits by tformat.
   #   - sixth sed aligns wrapped text from pretty-print into message column.
   #   - last three sed statements insert a tab as a delimiter (recall tabs 
   #        removed by expand) between any other text and the --name-status text.
   #        This is in anticipation of the awk statement at the next pipe 
   #   - awk used to right pad the first column up to N_STAT_INDENT_CHARS and
   #        place any --name-status fields present to its right in order to 
   #        align it with the message text.
   #   - use tr to delete the inserted tabs that were used for column alignment
   #   - sed to remove any trailing white space.
   #   - awk removes extraneous blank lines
   #   - finally pipe to less -R to force the color option
   git log \
           --date=short \
           --pretty=tformat:"%C(auto)%w($N_SCRN_COLS,0,$N_MSG_INDENT_CHARS)%>|($N_HASH_CHARS)%h%x09%<($N_AUTH_DATE_CHARS,trunc)%ad%<($N_AUTH_NAME_CHARS,trunc)%an%x09%C(bold blue)%s%C(auto)%+d" \
           $* | \
           expand -t 1 | \
           sed -$sed_regex_sym $'/.*[*]/!{/.*[|]{1}/s/\x1b\\[([0-9](;[0-9])*)*[mGK]([_])\x1b\\[([0-9](;[0-9])*)*[mGK]/_/g;}' | \
           sed -$sed_regex_sym $'/.*[*]/!{/.*[|]{1}/s/\x1b\\[([0-9](;[0-9])*)*[mGK]([|])\x1b\\[([0-9](;[0-9])*)*[mGK]/|/g;}' | \
           sed -$sed_regex_sym $'/.*[*]/!{/.*[|]{1}/s/\x1b\\[([0-9](;[0-9])*)*[mGK]([\\])\x1b\\[([0-9](;[0-9])*)*[mGK]/\\\/g;}' | \
           sed -$sed_regex_sym $'/.*[*]/!{/.*[|]{1}/s/\x1b\\[([0-9](;[0-9])*)*[mGK]([\/])\x1b\\[([0-9](;[0-9])*)*[mGK]/\//g;}' | \
           sed -$sed_regex_sym "/^[|[:space:]]+[^[:alnum:]\\\/]+$/s/[|]//g" | \
           sed -$sed_regex_sym "/^[|]/s/^(.{$N_MSG_INDENT_CHARS})[[:space:]]*/\1/" | \
           sed -$sed_regex_sym "s/^([[:space:]_|\\\/]{0,$N_HASH_CHARS})([A-Z][[:space:]])/\1$(printf -- '\t')\2/" | \
           sed -$sed_regex_sym "s/^([[:space:]_|\\\/]{0,$N_HASH_CHARS})([R][0-9][0-9][0-9][[:space:]])/\1$(printf -- '\t')\2/" | \
           sed -$sed_regex_sym "s/^([[:space:]_|\\\/]{0,$N_HASH_CHARS})([C][0-9][0-9][[:space:]])/\1$(printf -- '\t')\2/" | \
           awk 'BEGIN{ FS="\t" }{ printf "%-'$N_STAT_INDENT_CHARS's%s\n", $1, $2 }' | \
           tr -d '\t' | \
           sed -$sed_regex_sym 's/[[:space:]]*$//' | \
           awk NF | \
           less -R --chop-long-lines
}

Example Output

  1. gitlog --color --graph gitlog --color --graph

  2. gitlog --color --name-status gitlog --color --name-status

Upvotes: 0

VonC
VonC

Reputation: 1328072

The closest I have seen a git log properly aligned is in garybernhardt/dotfiles/.githelpers.

Gary uses:

I tested with within a clone of the repo git:

vonc@VONCAVN7:~/gits/src/git$ 
git -c color.ui=auto log --graph --pretty=tformat:"%C(yellow)%h%Creset}%Cgreen(%ar)%Creset}%C(bold blue)<%an>%Creset}%C(bold red)%d%Creset %s" -100|  column -s '}' -t

In multiple lines:

git -c color.ui=auto log --graph \
  --pretty=tformat:"%C(yellow)%h%Creset}%Cgreen(%ar)%Creset}%C(bold blue)<%an>%Creset}%C(bold red)%d%Creset %s" \
  -100|  column -s '}' -t

BUT: it only works with color.ui set to false or auto, not set to always: colors will mess up the colum alignment.

Without colors:

* 238e487ea                    (3 weeks ago)  <Junio C Hamano>         (HEAD -> master, tag: v2.14.1-b5, origin/master, origin/HEAD) The fifth batch post 2.14
*   6e6ba65a7                  (3 weeks ago)  <Junio C Hamano>         Merge branch 'mg/killed-merge'
|\
| * 9d89b3552                  (3 weeks ago)  <Michael J Gruber>       merge: save merge state earlier
| * 8e6a6bb36                  (3 weeks ago)  <Michael J Gruber>       merge: split write_merge_state in two
| * 62dc42b93                  (3 weeks ago)  <Michael J Gruber>       merge: clarify call chain
| * e2de82f27                  (4 weeks ago)  <Michael J Gruber>       Documentation/git-merge: explain --continue
* |   eabdcd4ab                (3 weeks ago)  <Junio C Hamano>         Merge branch 'jt/packmigrate'
|\ \
| * | 7709f468f                (4 weeks ago)  <Jonathan Tan>           pack: move for_each_packed_object()
| * | f9a8672a8                (4 weeks ago)  <Jonathan Tan>           pack: move has_pack_index()
...
...
...
| * | | | | | | | fdbdb64f4    (5 weeks ago)  <Jeff King>              interpret-trailers: add an option to show only existing trailers
| * | | | | | | | 56c493ed1    (5 weeks ago)  <Jeff King>              interpret-trailers: add an option to show only the trailers
| * | | | | | | | 8abc89800    (5 weeks ago)  <Jeff King>              trailer: put process_trailers() options into a struct
* | | | | | | | |   bfd91b413  (3 weeks ago)  <Junio C Hamano>         Merge branch 'pb/trailers-from-command-line'
|\ \ \ \ \ \ \ \ \
| * | | | | | | | | c88bf5436  (7 weeks ago)  <Paolo Bonzini>          interpret-trailers: fix documentation typo
| * | | | | | | | | 0ea5292e6  (7 weeks ago)  <Paolo Bonzini>          interpret-trailers: add options for actions

The first 100 commits are perfectly aligned.

With colors...

colors

You would need additional pre-processing of the git log output before piping it to column.
See "Color escape codes in pretty printed columns".

Upvotes: 3

Related Questions