Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

git log reverse and then limit the results to one

Tags:

git

I am at the commit on master, and I need to get to the next commit wrt origin/master.

git log --ancestry-path --date-order --reverse HEAD..origin/master

or a similar git rev-list command gives me the right commits, properly reversed, so I could |head -n 1 that and be done with it.

However, I wonder it it's possible to get it by using just one process (one git invokation). Limiting with -1 limits first, and then reverses the list, which I not what I need.

How to accomplish this?

I know what a DAG is, I also know enough graph theory to understand why -1 behaves like that. What I'm asking here is not a matter of theory, it's a matter of using a tool used in software development.

like image 301
Flavius Avatar asked Jun 14 '15 17:06

Flavius


2 Answers

I'm 90% confident this can't be done in a single Git invocation for two reasons.

  1. It just doesn't look like they've implemented it. Commits have pointers to their parents, not their children, which is why --max-count (-1) and --skip (which I also tried a bit) run before --reverse. Since Git's capable of printing in --reverse or not, it seems like running -1 afterwards should be technically feasible, but perhaps there's an underlying reason it's not. Or perhaps they considered it and decided anyone could just --reverse | head -n 1 like you're doing.

  2. More importantly, you're not guaranteed a unique next commit, even when using --ancestry-path, so picking --reverse -1 is ambiguous. Here's an example from the --ancestry-path description in the git-log docs, where your HEAD could be commit E. If you're happy with --date-order, it's more of an academic issue, but the DAG nature of Git makes the whole "next commit" concept unsound.

As an example use case, consider the following commit history:

    D---E-------F
   /     \       \
  B---C---G---H---I---J
 /                     \
A-------K---------------L--M

A regular D..M computes the set of commits that are ancestors of M, but excludes the ones that are ancestors of D. This is useful to see what happened to the history leading to M since D, in the sense that “what does M have that did not exist in D”. The result in this example would be all the commits, except A and B (and D itself, of course).

When we want to find out what commits in M are contaminated with the bug introduced by D and need fixing, however, we might want to view only the subset of D..M that are actually descendants of D, i.e. excluding C and K. This is exactly what the --ancestry-path option does. Applied to the D..M range, it results in:

E-------F
 \       \
  G---H---I---J
               \
                L--M
like image 57
Kristján Avatar answered Oct 17 '22 11:10

Kristján


This does what you want:

git rev-list --children HEAD...origin/master^ | tail -2 | head -1 | cut -d" " -f 2-

This will even print N children, if the history forks at this point.

You could wrap this into a git alias to make a single command.

For other solutions, see also How do I find the next commit in git?

like image 22
Ewan Mellor Avatar answered Oct 17 '22 09:10

Ewan Mellor