Question

We have a script that sends email with list of all commits that were deployed. It is done by keeping date of last deploy and doing git log for given time range (now - last deploy time). The problem that it fails to produce list of all changes that were deployed due to branching. I created minimalistic sample to show the problem. I am pretty sure this question was asked before, but I couldn't formulate it properly apparently.

*   24d9c49 - (HEAD, master) l-m (Wed Mar 19 15:54:48 2014 +0100) <Andrey>
|\  
* \   0f29219 - r-m (Wed Mar 19 15:54:48 2014 +0100) <Andrey>
|\ \  
* | | 73a1f4b - m3 (Wed Mar 19 15:54:48 2014 +0100) <Andrey>
| * | 349c1eb - (right) r1 (Wed Mar 19 15:54:47 2014 +0100) <Andrey>
|/ /  
| * 15c190f - (left) l2 (Wed Mar 19 15:54:46 2014 +0100) <Andrey>
| * 50b8c59 - l1 (Wed Mar 19 15:54:45 2014 +0100) <Andrey>
* | da47211 - m2 (Wed Mar 19 15:54:44 2014 +0100) <Andrey>
|/  
* 581e3a9 - m1 (Wed Mar 19 15:54:43 2014 +0100) <Andrey>

Here is code to generate given repo.

Imagine I deployed previously at 15:54:48, and now I want to get list of commits that will be deployed with current deploy. I do:

git log --pretty=format:"%h %s %ad" --since='Wed Mar 19 15:54:48 2014 +0100'

which returns:

24d9c49 l-m Wed Mar 19 15:54:48 2014 +0100
0f29219 r-m Wed Mar 19 15:54:48 2014 +0100
73a1f4b m3 Wed Mar 19 15:54:48 2014 +0100

which is obviously not true, because it misses commits l1, l2 and r1, because they were committed before last deploy in other branches, but merged just now. So it is not just about time. I came up with algorithm that will handle this situation, but it is rather complicated, so I hope maybe there is simpler command that is capable of producing logs that take branches into consideration.

Update, the solution: based on @user3426575 advice I figure out that I need to do this:

git log --pretty=format:"%h %s %ad" HEAD ^da47211

where da47211 is last commit before deploy. So I need to store last commit number before previous deploy and not datetime of deploy.

Was it helpful?

Solution

You could specify an open commit range:

git log --pretty=format:"%h %s %ad" da47211..

This is explained in man gitrevisions:

History traversing commands such as git log operate on a set of commits, not just a single commit. To these commands, specifying a single revision with the notation described in the previous section means the set of commits reachable from that commit, following the commit ancestry chain.

To exclude commits reachable from a commit, a prefix ^ notation is used. E.g. ^r1 r2 means commits reachable from r2 but exclude the ones reachable from r1.

This set operation appears so often that there is a shorthand for it. When you have two commits r1 and r2 (named according to the syntax explained in SPECIFYING REVISIONS above), you can ask for commits that are reachable from r2 excluding those that are reachable from r1 by ^r1 r2 and it can be written as r1..r2.

A similar notation r1...r2 is called symmetric difference of r1 and r2 and is defined as r1 r2 --not $(git merge-base --all r1 r2). It is the set of commits that are reachable from either one of r1 or r2 but not from both.

In these two shorthands, you can omit one end and let it default to HEAD. For example, origin.. is a shorthand for origin..HEAD and asks "What did I do since I forked from the origin branch?" Similarly, ..origin is a shorthand for HEAD..origin and asks "What did the origin do since I forked from them?" Note that .. would mean HEAD..HEAD which is an empty range that is both reachable and unreachable from HEAD.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top