List history since version

= How Do I List All History Since a Particular Version? =

Say you're working on a release branch, preparing for release 1.1.3, and you want to know everything that has changed in your project on that branch since the previous release (1.1.2). This is exactly the sort of thing we expect to get from version control, so it should be easy, right? Not so fast.

CVS
This task is quite difficult with CVS. First, I'll assume you're on a branch release-1_1-branch, and your previous release was tagged release-1_1_2. (CVS doesn't allow periods in tag names, and the most common convention is to use underscores instead.)

As mentioned in the previous recipe List history on branch, it's easy to get all revisions along a branch. If you read the documentation for cvs log, you might think that this would work:

cvs log -N -S -rrelease-1_1_2::    # DOES NOT WORK

The docs say that will give you "revisions starting just after to the end of the branch containing ". That sounds nice, but consider the case of a file that did not change on release-1_1-branch before release-1_1_2, but has changed on the trunk since the branch was created:

1.1* --- 1.1.2.1  (release-1_1-branch) |         |   |       1.1.2.2   |  1.2  * = tagged release-1_1_2, since no revisions existed on      release-1_1-branch when release-1_1_2 was tagged

In this case, release-1_1_2 tags a revision on the trunk (1.1), not on release-1_1-branch. Thus, the `cvs log` command above shows revision 1.2, not revisions 1.1.2.1 and 1.1.2.2. Wrong.

As near as I can tell, this task is impossible with vanilla CVS. One possible solution is to run two passes of cvs log: first, determine which revision of every file is tagged with release-1_1_2</tt>:

cvs log -N -S -rrelease-1_1_2

Obviously you'll have to parse the output of cvs log</tt> and build a data structure mapping filename to revision number. Then get all revisions along the branch of interest:

cvs log -N -S -rrelease-1_1-branch

This time you'll have to parse the output and only show revisions whose revision number is greater than that stored in the previous run. In this case, "greater than" has the obvious meaning of "1.4" > "1.3" > "1.2.4.3" > "1.2.4.1" > "1.1".

git
git handles this case with ease:

git-log release-1.1.2.. --

(That assumes that you've taken advantage of git's more liberal rules for naming tags and branches and used dots rather than underscores.)

Incidentally, git-log</tt> stubbornly sticks to listing commits in reverse chronological order newest first. Use --reverse</tt> if you prefer to see oldest commits first, which seems likely when you're reviewing the commits that will go into the next release.

Of course, if the current branch is something other than release-1.1-branch</tt>, you will need to explicitly specify it as the endpoint:

git-log release-1.1.2..release-1.1-branch --

Subversion
As a consequence of Subversion's peculiar implementation of tags, this is surprisingly awkward. In particular, I cannot find an easy way to determine which revision on branches/release-1.1-branch</tt> was the basis for tags/release-1.1.2</tt>. So I came up with a two-step process: first, determine the revision where the release tag was created:

svn log --stop-on-copy <repo-url>/tags/release-1.1.2

Since this is a "tag" copy rather than a "branch" copy, that should show exactly one revision; we'll call its revision number  </tt>. Now we can get all revisions on the branch after that tag:

svn log -r :HEAD

(Unlike git, Subversion changes the order of log entries according to the range of revisions on the command line; in this case, it shows oldest first, as I prefer. If you like newest first, just reverse the order: svn log -rHEAD: </tt>.)