0

Is it possible to collapse fully-merged branches when using git log --graph?

Instead of having git log --graph --branches displaying:

*   16bb2c5 (HEAD, dev) Merge branch f
|\
| * 4571fbd Commit 14
| * de845ac Commit 13
|/
| * aba23a5 (branch e) Commit 12
|/
*   305d031 Merge branch c
|\
| | * 80c47c6 (branch d) Commit 11
| | * dbc182e Commit 10
| | * 18bb013 Commit 9
| |/
| * 879e64a Commit 8
| * b9a1413 Commit 7
| * ddd92f9 Commit 6
|/
*   2e94cc8 Merge branch b
|\
| * 852ddaf Commit 5
| * 88cdaf9 Commit 4
| * d1d7c7b Commit 3
|/
| * bd1557a (branch a) Commit 2
|/
o e740474 (master) Commit 1

Since branches a and c have been fully merged (and removed so --branches doesn't try to show them), I would like to have (with or without the # COLLAPSED comments):

*   16bb2c5 (HEAD, dev) Merge branch f ### COLLAPSED
| * aba23a5 (branch e) Commit 12
|/
*   305d031 Merge branch c
|\
| | * 80c47c6 (branch d) Commit 11
| | * dbc182e Commit 10
| | * 18bb013 Commit 9
| |/
| * 879e64a Commit 8 ### DO NOT COLLAPSE THOSE COMMITS SINCE BRANCH D ISN'T MERGED
| * b9a1413 Commit 7
| * ddd92f9 Commit 6
|/
*   2e94cc8 Merge branch b ### COLLAPSED
| * bd1557a (branch a) Commit 2
|/
o e740474 (master) Commit 1


My use case is the following. I would like to have an alias to display all local commits that I didn't merged yet, from the list of local branches, starting from master, unless they are not a descendant of the first parent (recursively) of dev. EDIT: The goal is to differentiate between what is integrated and what is still research-in-progress work.

Note that git log --graph --branches --first-parent display all the commits I want, but doesn't include the links between all the visible parents of all commits (879e64a Commit 8 isn't linked as the second parent of 305d031 Merge branch c).

*   16bb2c5 (HEAD, dev) Merge branch f
| * aba23a5 (branch e) Commit 12
|/
*   305d031 Merge branch c ### MISSING LINK WITH 879e64a Commit 8
| * 80c47c6 (branch d) Commit 11
| * dbc182e Commit 10
| * 18bb013 Commit 9 
| * 879e64a Commit 8 ### MISSING LINK WITH 305d031 Merge branch c
| * b9a1413 Commit 7
| * ddd92f9 Commit 6
|/
*   2e94cc8 Merge branch b
| * bd1557a (branch a) Commit 2
|/
o e740474 (master) Commit 1
Robin
  • 423
  • 3
  • 10
  • 1
    The short answer here is no, you cannot get quite what you want with `--graph` as it insists on walking the graph. You can simplify the graph that it walks with `--first-parent` and `--simplify-by-decoration` and the like but this will omit some of the items you want. Consider instead running `git fetch`, then using `git log` or `git rev-list` on `--branches --not --remotes`, which will simply enumerate all commits reachable by local branch names but not by remote-tracking names. – torek Oct 30 '19 at 16:14
  • @torek Is there a way to display a given list of commit as a graph, something like `git log --graph --only-those-commits commit1 commit2 commit3`? Technically `git log --branches --first-parent --pretty='%H' master..` returns exactly the list of commit I want, but I don't know how to display them as a graph. The `-n 1` (`--max-count 1`) option of `git log` doesn't work if you list multiple commits, it will only display the first. – Robin Oct 31 '19 at 09:19
  • Not with `git log --graph`. Its internal code is pretty cheesy. You can get other graph-drawing programs (e.g., the sort of canonical one, "dot") to draw all kinds of stuff. – torek Oct 31 '19 at 09:24
  • Thanks a lot for the info. I guess I will have to code something if I really want to be able to create my alias! – Robin Oct 31 '19 at 10:11
  • By the way, see [Pretty git branch graphs](https://stackoverflow.com/q/1057564/1256452). – torek Oct 31 '19 at 10:18
  • @torek In case you are interested, I found a way with sed, see below. – Robin Oct 31 '19 at 15:10

2 Answers2

0

all local commits that I didn't pushed yet

There may be a precise answer to your query, but you should avoid having local commits that are not pushed. Relying on these unpushed commits to not loose work seems like not a sustainable solution.

A better strategy could be to compare branches and use that information as the basis to decide what needs to be integrated.

This way you could push everything (yey! it's safe now).


Ahead/behind

You could checkout git ahead/behind info between master and branch?.

Some online tools give you the ahead/behind per branch 'for free':

enter image description here

tymtam
  • 31,798
  • 8
  • 86
  • 126
  • "you should avoid having local commits that are not pushed. Relying on these unpushed commits to not loose work seems like not a sustainable solution." My whole home directory is already backed-up on the network, so I don't rely at all on git for back-up of un-finished work. Your solution unfortunately doesn't help me since what I want is comparing what is integrated/shared versus what is still work-in-progress. I don't really care about the number of commit, but about the content of those commits (and therefore the commit message). – Robin Oct 30 '19 at 13:31
  • Also if all I wanted was to push everything to be sure it exists somewhere else, I could just do `git push --all` – Robin Oct 30 '19 at 13:50
-1

I kind of found a hacky way to do it (and it supports colors).

I added the following alias in ~/.gitconfig

graph = !sh -c '~/scripts/gitgraph --boundary master..  "$@"' -

and I created the following script in ~/scripts/gitgraph

#!/usr/bin/env sh
# Display a graph of all umerged branches
# All arguments will be passed to git log

# Use color if output is not connected to a terminal
COLOR=''
[ -t 1 ] && COLOR='--color'

# Note: each ASCII_CODES create two capture group
ASCII_CODES="$(printf "\\\\(\\\\(\033\\\\[[^m]*m\\\\)*\\\\)")"·

#1: Replace color of |\ and |/
#2: Display first-parents
#3: Display non-merged commits whitch aren't first-parents
#4: Replace commit message of merged commits witch aren't first parents with "..."
#uniq: Squash multiples consecutive lines created by #4
git log --graph --oneline --decorate --branches ${COLOR} "$@" | sed -n \
    -e "s/^${ASCII_CODES}|${ASCII_CODES}\\([\\\\\\/]\\)${ASCII_CODES} */\\1|\\5\\6/p" \
    -e "/^${ASCII_CODES}|${ASCII_CODES}\\\\/ , /^${ASCII_CODES}|${ASCII_CODES}\\// "'!p' \
    -e "/^${ASCII_CODES}|${ASCII_CODES}\\\\/ , /^${ASCII_CODES}|${ASCII_CODES}\\// { /^${ASCII_CODES}|${ASCII_CODES} \\*/"' !p }' \
    -e "/^${ASCII_CODES}|${ASCII_CODES}\\\\/ , /^${ASCII_CODES}|${ASCII_CODES}\\// { s/^${ASCII_CODES}|${ASCII_CODES} \\*.*/\\1| ...\\3/p }" \
| uniq 

Example (note: prefixes #1 to #4 corresponds to the line in sed that will modify it)

#1 * 87842c1 Commit 17
#1 * 1ab18c1 Commit 16
#1 *   16bb2c5 (HEAD, dev) Merge branch f
#2 |\
#4 | * 4571fbd Commit 15
#4 | * de845ac Commit 14
#2 |/
#3 | * 12afeee (branch e) Commit 13
#3 | * aba23a5 Commit 12
#2 |/
#1 *   305d031 Merge branch c
#2 |\
#3 | | * 80c47c6 (branch d) Commit 11
#3 | | * dbc182e Commit 10
#3 | | * 18bb013 Commit 9
#3 | |/
#4 | * 879e64a Commit 8
#4 | * b9a1413 Commit 7
#4 | * ddd92f9 Commit 6
#2 |/
#1 *   2e94cc8 Merge branch b

Will become

* 87842c1 Commit 17
* 1ab18c1 Commit 16
*   16bb2c5 (HEAD, dev) Merge branch f
|\
| * 4571fbd Commit 15
| * de845ac Commit 14
|/
| * 12afeee (branch e) Commit 13
| * aba23a5 Commit 12
|/
*   305d031 Merge branch c
|\
| | * 80c47c6 (branch d) Commit 11
| | * dbc182e Commit 10
| | * 18bb013 Commit 9
| |/
| * ...
|/
*   2e94cc8 Merge branch b

Robin
  • 423
  • 3
  • 10