124

I know there has been very similar questions here, but they didn't solve my problem. Perhaps there's something I'm not understanding well.

This is a portion of the commit history of fitnesse (https://github.com/unclebob/fitnesse/):

* | | | | | | | | | | | | | | | fa86be8 Avoid possible issue when using CachingPage under heavy memory load.
|/ / / / / / / / / / / / / / /  
* | | | | | | | | | | | | | |   7b4a07a Merge pull request #256 from barredijkstra/fitnesse_issue_250
|\ \ \ \ \ \ \ \ \ \ \ \ \ \ \  
| * | | | | | | | | | | | | | | ecf5891 Fixed test checking for OS specific exception message.
| * | | | | | | | | | | | | | | 082236e Added rendering of cause exceptions. Fix for unclebob/fitnesse#250
* | | | | | | | | | | | | | | |   a92b37f Merge pull request #243 from amolenaar/fix/243-hash-table-rendering

I want the list of commits between 2 commit hashes. In this particular case, I want the commits between ecf5891 and 7b4a07a, and I expect the result to be:

ecf5891
7b4a07a

Si far I've been using git rev-list commit_hash_from_here^..commit_hash_up_to_here and it has worked fine with linear history. However, in this case I get a lot more commits.

I've tried this and it works just as expected:

git log --since='<date ecf5891>' --until='<date 7b4a07a>'

(I've manually searched for those 2 dates).

One possible solution is to get the 2 dates and just do that, but I think there should be a better way.

Edit: 7b4a07a parents are ecf5891 and a92b37f. So far, the solutions work fine if I want to go from ecf5891 to 7b4a07a, but if I want to go from a92b37f to 7b4a07a I want to get:

7b4a07a
ecf5891
082236e
a92b37f

but I don't get a92b37f

Nico
  • 1,385
  • 2
  • 8
  • 11

4 Answers4

90

I think that you`re looking for --ancestry-path, in your case:

git rev-list --ancestry-path 7b4a07a..ecf5891
onlynone
  • 7,602
  • 3
  • 31
  • 50
aquavitae
  • 17,414
  • 11
  • 63
  • 106
  • 15
    `--ancestry-path` was the ticket for me. I used it, in the end, in this way: `git log --oneline --ancestry-path commit1~1..commit2` in order to see everything exactly between my two commit hashes I had. Thanks! – Hoonerbean Oct 17 '19 at 13:39
  • 6
    commit 1 needs to be the old commit and commit 2 the new one to make these commands work – Shivendra Agarwal Sep 06 '21 at 03:58
43

"Between" is a somewhat slippery notion, when it comes to git commits.

The text you show above, with a snippet of graph output, shows why from^..to produces more than just those two commits: the to part is a merge commit.

The notation A..B is really just shorthand for B ^A. That is, "everything starting from B and working backwards, minus everything starting from A and working backwards". But B is a merge commit, so "everything starting there and working backwards" uses both parents.

Here the first parent of 7b4a07a is a92b37f (not in your [original] snippet above but I cloned the linked repo and found it). We can refer to it symbolically, though, and I will below. The second parent of 7b4a07a is ecf5891, the "from" part you're interested in.

When you ask for:

ecf5891^..7b4a07a

that means:

7b4a07a ^ecf5891^

which is the same as:

7b4a07a ^082236e

which gets you both parents of the merge, and then trims off everything from 082236e back. You need to trim off everything from 7b4a07a^—the first parent—and back as well:

git rev-list 7b4a07a ^ecf5891^ ^7b4a07a^
git log --oneline 7b4a07a ^ecf5891^ ^7b4a07a^

In general, though, you have to figure out which descendent line(s) to chop-off.

Edit: you can stick with the A..B notation, but you do need to add the extra "exclude". So jthill's answer works too, once you move the hat to the front.


Re your edit ("if I want to go from a92b37f to 7b4a07a"): we're back to that issue of "between" being a slippery notion. Which commits are "between"? There's a direct line from a92b37f to 7b4a07a, because a92b37f is one of the two parents of the merge commit 7b4a07a. So by the earlier logic ("commits directly on an ancestral line", perhaps "inclusive") that would just be one, or maybe both, of those two commits. But you say you want two commits that are not, in any ancestral sense, related to a92b37f at all. Why do you want those two particular commits? What makes 082236e "interesting" and 082236e^, its parent, "uninteresting"?

Community
  • 1
  • 1
torek
  • 448,244
  • 59
  • 642
  • 775
  • Ok, I understand when you said "all the way back, but that applies to the 2 parents". Then, you do what I did before and chop-off the extra-parent part, by doing `^7b4a07a^` which is `^a92b37f`. How do you know that `7b4a07a^` is going to be "the other" parent and not `ecf5891`? I'm doing this in a script, so I can't manually look up. – Nico Sep 08 '13 at 03:56
  • "Aye, there's the rub" –Hamlet. There's no way *a priori* to know which parent(s) of a merge to cut off, just from the commits themselves. You'll have to provide (perhaps a lot) more background. – torek Sep 08 '13 at 05:39
  • Right now I want the commits in chronological order, the notion of "between" would be: look for commit A and B in the chronological graph, all the commits between them including A and B. Perhaps it doesn't make much sense and I'm thinking too svn-way. So far, the solution has been the most easiest and ugly: get all commit hashes, search for A and add to list until I find B. Thank you anyway, you have cleared out some things and made me think if the chronological way is what I'm looking for. – Nico Sep 08 '13 at 13:50
  • Or, maybe it does make sense, and what you want *is* limiting with `--since` and `--until` (or `--min-age` and `--max-age` which do the same thing). (Note, these look at "committer" dates rather than "author" dates, i.e., when the patch was committed, vs when it was written.) But, yes, that's the question, what exactly does "between" mean when history is non-linear? – torek Sep 08 '13 at 21:03
  • Thanks @torek. You saved my day! I have been banging my head to include the starting commit & "^" helped a lot. – Rewanth Tammana May 21 '22 at 10:34
25

First identify the relevant 2 commit hashes that you need for getting the list of commit hashes in between them by using

git log --oneline

Then you can pick the relevant two commit hashes and find the commit hashes in between them by using

git log <commit hash 1>..<commit hash 2> --oneline | cut -d " " -f 1
Richard Nienaber
  • 10,324
  • 6
  • 55
  • 66
Kasun Siyambalapitiya
  • 3,956
  • 8
  • 38
  • 58
  • Did you test this answer? Its [not producing expected results](http://stackoverflow.com/q/41688733) for me. – jww Jan 17 '17 at 04:00
  • 11
    I needed to do the following: `git log --oneline hashone..hashtwo` – Andrew Jul 06 '17 at 16:56
  • 1
    Funny, the "from" commit has to be older than the "to" commit, otherwise it doesn't work. – Diego Pino Jan 15 '20 at 11:51
  • why is the --online option necessary?! What is the difference between with --online and without? –  Feb 04 '21 at 16:52
  • @user12411795 `--oneline` is just a formatting flag. It prints the result on one line per commit, omitting some information. – Zorobay Feb 09 '23 at 14:31
3

Add ^7b4a07a~ to also exclude everything reachable from the merge's first parent. You're only excluding what's reachable from its second parent.

jthill
  • 55,082
  • 5
  • 77
  • 137
  • 1
    Typo of sorts, you need the `^` in front (or `--not`) – torek Sep 08 '13 at 03:25
  • Where should I add that part? How would be the complete line? – Nico Sep 08 '13 at 03:58
  • add it to the rest of your specification, just another argument. @torek: :-P yow. Thanks. – jthill Sep 08 '13 at 04:05
  • Ok, that works so far. However, it doesn't work in the case I've provided in the edit. – Nico Sep 08 '13 at 04:37
  • You have all the tools you need to do it. `git help revisions` will walk you through all the ways you can specify which revisions you want or don't. The thing to understand is what it says in the description: commands that work on commit sets use "reachable from" and "not reachable from" specifications. Now all you need is time and a bit of experimentation and play. – jthill Sep 08 '13 at 06:18
  • not showing the complete command. Not explaining what all the magic characters are doing. Potentially one should add if this only applies to databases for which git pull --rebase is not being enforced –  Feb 04 '21 at 16:55