61

I have a simple alias to display few last commits:

log --pretty=format:'%h %an %s' -10

How can I make the results to be displayed in columns, like this:

898e8789 Author1             Commit message here
803e8759 Other Author name   Commit message here
takeshin
  • 49,108
  • 32
  • 120
  • 164

8 Answers8

85

In Git 1.8.3 and later, there is native support for this in the pretty format, using the %<(N) syntax to format the next placeholder as N columns wide:

$ git log --pretty=format:'%h %<(20)%an %s' -10

For versions before 1.8.3, the previous version of this answer, retained below, should work.

Here's a solution in Bash using read to parse the log lines back apart, and printf to print them out, with a fixed width field for the authors name so the columns will stay lined up. It assumes that | will never appear in the author's name; you can choose another delimiter if you think that might be a problem.

git log --pretty=format:'%h|%an|%s' -10 | 
  while IFS='|' read hash author message
  do 
    printf '%s %-20s %s\n' "$hash" "$author" "$message"
  done

You can create this as an alias using:

[alias]
    mylog = "!git log --pretty=format:'%h|%an|%s' -10 | while IFS='|' read hash author message; do printf '%s %-20s %s\n' \"$hash\" \"$author\" \"$message\"; done"

I'm sure you could do this in fewer characters using awk but as the saying goes,

Whenever faced with a problem, some people say “Lets use AWK.” Now, they have two problems.

Of course, having said that, I had to figure out how to do it in awk which is a bit shorter:

git ... | awk -F '|' '{ printf "%s %-20s %s\n", $1, $2, $3 }'
Brian Campbell
  • 322,767
  • 57
  • 360
  • 340
  • While this works - using the native git-log method as Suggested by @Jesse is much neater – Sean Burlington Feb 05 '15 at 14:55
  • @SeanBurlington When I wrote this answer in 2010, that did not exist; support for the spacing placeholders was added [in 1.8.3, in 2013](https://github.com/git/git/commit/a57523428b4c08795e793356e12afc3de812f84a) (though for some reason, it seems to be [missing from the release notes](https://github.com/git/git/blob/master/Documentation/RelNotes/1.8.3.txt)). Now that you have pointed out that there is a better solution available, I've incorporated that into my answer. – Brian Campbell Feb 05 '15 at 17:03
  • 2
    I hoped that the `%<(N)` syntax would work in other areas of Git where `--format` is used, but it seems to be limited to `--pretty` for now. In 2013 there was [some discussion](http://lists-archives.com/git/797299-for-each-ref-support-aligned-for-left-alignment.html) about using that syntax with `for-each-ref --format` and some experimentation with `%(...:aligned)` but that discussion seems to have died. – Dennis Feb 23 '15 at 13:56
  • 2
    Is there any way to apply the fixed size to the graph as well? And to also truncate fields longer than the specified size? I'm trying to make a log with fixed positions for everything, as that's easier on the eyes. – TamaMcGlinn Jul 06 '16 at 18:12
  • 2
    note that for `for-each-ref` you can use `%(align:width=20,position=left)` in the formatting, see https://git-scm.com/docs/git-for-each-ref – Jared Forsyth May 24 '17 at 19:27
41

You can also do:

git log --pretty=format:'%h %<(20)%an %s' -10

No need for shell magic or post processing with awk, column etc.

Jesse
  • 6,725
  • 5
  • 40
  • 45
  • This seems like the best solution by far to me. Where did you find docs on the %<(20) syntax? – Connor McKay Feb 18 '14 at 21:39
  • 1
    It's referenced in the `git help log` docs, under the PRETTY FORMATS section (I'm using git version 1.8.3.4). – Conan Feb 25 '14 at 11:52
  • This is the shortest yet most accurate answer. Don't need anything else, just built-in git log. – phnah Dec 25 '14 at 04:44
  • 1
    This is a new option in 1.8.3, so if you're using 1.8.3 or later, this is definitely a better solution. I've incorporated this suggestion into my answer, as it is on top due to being accepted and thus more likely to be the first thing people see when coming here. – Brian Campbell Feb 05 '15 at 17:10
19

The following command will print the log in a tabular form

git log --pretty=format:'%h|%an|%s' -10 | column -t -s '|'

the column command "columnates" the output, using the "|" as field separator, it will find out the optimal column width given the input, so it would work well even if you have more fields.

On Linux it will work ok as long as you don't use colors, the Linux implementation doesn't handle well the ANSI escape codes.

But in Mac OS X, it will handle colors and you can use any unicode character as field delimiter. I use ∑ since I'm pretty sure it won't occur by chance on the commit text. | is a bad choice because it could appear in the commit description and also if you use --graph --decorate --all it will appear as part of the symbols used to draw the graph

RubenLaguna
  • 21,435
  • 13
  • 113
  • 151
  • First answer I saw that worked with this: `git log --pretty=format:'%cr|%s' -10 | column -t -s '|'` – llf Mar 06 '18 at 14:38
14

In order to get truly tabular format you need to also truncate usernames that are longer than e.g. 20 characters:

git log --pretty=format:'%h %<(20,trunc)%an %s' -10

Additionally, if you're outputting to the terminal, you may want to prevent line overflows by either truncating the commit message field:

git log --pretty=format:'%h %<(20,trunc)%an %<(39,trunc)%s' -10

or wrapping the lines and indenting any overflowing lines to align:

git log --pretty=format:'%w(79, 0, 29)%h %<(20,trunc)%an %s' -10

EDIT: The above example hard-codes the terminal width to be 79 characters. On POSIX systems you can use tput cols to return the width:

git log --pretty=format:'%w(`tput cols`, 0, 29)%h %<(20,trunc)%an %s' -10

or

git log --pretty=format:'%w($((`tput cols`-1)), 0, 29)%h %<(20,trunc)%an %s' -10

Unfortunately these last two break git alias so it will require a terminal alias (unless you really love typing).

insysion
  • 301
  • 2
  • 9
7

How to add a tab?

What you are looking for is:

%x09

Here is an example

git log --pretty=format:"%C(magenta)%h %C(cyan)%C(bold)%ad%Creset %C(cyan)%cr%Creset%x09 | %s %C(green)%Creset" --date=short

I wanted the relative date to be tabbed bc it was not a fixed length, this way all columns line up (for anything less than a year ago). Wanted to make it line up all of the time, but this is as far as I got before I ran out of time (ironically).

Hope this helps!

If you have suggestions to improve this answer for the relative year case (not just grepping out the year) happy to hear them too, feel free to edit this answer to add them if you know how to do it.

Edit:

I decided to try out the %<(n) syntax suggested by another person too, I found that it is too short if you have anything over 9 years bc 10 years is one more digit using %<(20) which was suggested. Instead I suggest %<(23)

git log --pretty=format:"%C(magenta) %h %C(cyan)%C(bold)%ad%Creset %<(23) %C(cyan)%cr%Creset %s%C(green)%Creset" --date=short`

Unless the project is over 100 years old it will line up great. But if you want it to work for that you just add 1 making it %<(24)

jasonleonhard
  • 12,047
  • 89
  • 66
1

The problem with the tabular format is the fact that you might run out of space ...

The following one is my personal best compromise between the essential stuff to display:

  • who
  • did what
  • and when
  • to be able to dig more by the commit hash for the how

so:

  git log --pretty --format='%h %aI %<(15)%an ::: %s'

or

 git log --pretty --format='%h %cI %<(15)%an ::: %s'

if you want to get the commiter time and not the author time

Yordan Georgiev
  • 5,114
  • 1
  • 56
  • 53
0

This is give you the last 20 changes in nice view with numbering; You can change the colors

git log --pretty=format:"%C(magenta)%h %C(cyan)%C(bold)%ad %C(green)%<(20,trunc)%an%x09%Creset%C(yellow)%s%Creset" --date=short --color=always | head -20| cat -n

0

All those answers work well with ASCII characters, like insysion's one:

git log --pretty=format:'%w(79, 0, 29)%h %<(20,trunc)%an %s' -10

But that breaks down for UTF-8 characters.

With Git 2.39 (Q4 2022), "git diff --stat"(man) etc.
were invented back when everything was ASCII and strlen() was a way to measure the display width of a string; adjust them to compute the display width assuming UTF-8 pathnames.

See commit ce8529b (21 Oct 2022) by Junio C Hamano (gitster).
See commit 12fc4ad (14 Sep 2022) by Torsten Bögershausen (tboegi).
(Merged by Junio C Hamano -- gitster -- in commit 7d5a4d8, 28 Oct 2022)

diff.c: use utf8_strwidth() to count display width

Reported-by: Alexander Meshcheryakov
Helped-by: Johannes Schindelin
Signed-off-by: Torsten Bögershausen

When Unicode filenames (encoded in UTF-8) are used, the visible width on the screen is not the same as strlen().

For example, git log --stat(man) may produce an output like this:

[snip the header]

Arger.txt  | 1 +
Ärger.txt | 1 +
2 files changed, 2 insertions(+)

A side note: the original report was about cyrillic filenames.
After some investigations it turned out that

  • a) This is not a problem with "ambiguous characters" in Unicode
  • b) The same problem exists for all Unicode code points (so we can use Latin based Umlauts for demonstrations below)

The 'Ä' takes the same space on the screen as the 'A'.
But needs one more byte in memory, so the the git log --stat output for "Arger.txt" (!) gets misaligned: The maximum length is derived from "Ärger.txt", 10 bytes in memory, 9 positions on the screen.
That is why "Arger.txt" gets one extra ' ' for alignment, it needs 9 bytes in memory.
If there was a file "Ö", it would be correctly aligned by chance, but "Öhö" would not.

The solution is of course, to use utf8_strwidth() instead of strlen() when dealing with the width on screen.

And then there is another problem, code like this: strbuf_addf(&out, "%-*s", len, name); (or using the underlying snprintf() function) does not align the buffer to a minimum of len measured in screen-width, but uses the memory count.

One could be tempted to wish that snprintf() was UTF-8 aware.
That doesn't seem to be the case anywhere (tested on Linux and Mac), probably snprintf() uses the "bytes in memory"/strlen() approach to be compatible with older versions and this will never change.

The basic idea is to change code in diff.c like this strbuf_addf(&out, "%-*s", len, name);

into something like this:

int padding = len - utf8_strwidth(name);
if (padding < 0)
  padding = 0;
strbuf_addf(&out, " %s%*s", name, padding, "");

The real change is slightly bigger, as it, as well, integrates two calls of strbuf_addf() into one.

Tests: Two things need to be tested:

  • The calculation of the maximum width
  • The calculation of padding

The name "textfile" is changed into "tëxtfilë", both have a width of 8.
If strlen() was used, to get the maximum width, the shorter "binfile" would have been mis-aligned:

binfile    | [snip]
tëxtfilë | [snip]

If only "binfile" would be renamed into "binfilë":

binfilë | [snip]
textfile | [snip]

In order to verify that the width is calculated correctly everywhere,

  • "binfile" is renamed into "binfilë", giving 1 bytes more in strlen()
  • "tëxtfile" is renamed into "tëxtfilë", 2 byte more in strlen().

The updated t4012-diff-binary.sh checks the correct alignment:

binfilë  | [snip]
tëxtfilë | [snip]

The output from "git diff --stat"(man) on an unmerged path lost the terminating LF in Git 2.39, which has been corrected with Git 2.40 (Q1 2023).

See commit 209d9cb (14 Dec 2022) by Peter Grayson (jpgrayson).
(Merged by Junio C Hamano -- gitster -- in commit e57caee, 26 Dec 2022)

diff: fix regression with --stat and unmerged file

Signed-off-by: Peter Grayson
Acked-by: Jeff King

A regression was introduced in 12fc4ad (diff.c: use utf8_strwidth() to count display width, 2022-09-14, Git v2.39.0-rc0 -- merge listed in batch #8).

That causes missing newlines after "Unmerged" entries in git diff --cached --stat(man) output.

This problem affects v2.39.0-rc0 through v2.39.0.

Add the missing newline along with a new test to cover this behavior.

VonC
  • 1,262,500
  • 529
  • 4,410
  • 5,250