Skip to content

Entries from November 2010.

"git cherry-pick" for Perforce

Cherry-picking is a technique of porting only selected commits from one branch to another. It's directly supported in GIT by special command:

git cherry-pick <SHA-COMMIT-ID>

Also SVN has simple merge mode that supports selecting of single commit:

svn merge -c <REV-NO> <URL>

What about Perforce? After checking Perforce documentation for merging I hit the following syntax for selecting subset of changelists to merge:

p4 integrate //depot/release/jam/...@30,@30 ...

That's it: add the same change list id twice (separated by comma) to source URL and you will get cherry-pick!

[2011-04-20] Update: looks like sometimes @CL,@CL will not merge change properly, it's better to use SVN-style revision range mode (@CL-1,@CL):

p4 integrate //depot/release/jam/...@29,@30 ...

Perforce has additional step to perform:

p4 resolve -af

that walks thru all changes from integrate step and allow to check for conflicts. Of course in the end you have to commit changes.

p4 submit

BTW. I (still) don't see any benefit from using Perforce over well-known SVN. Anyone?

Software Releases Using GIT

Releasing Software is not just packing latest version to tarball and send to SFTP server. It requires preparation and some planning to be done properly. I'll describe release procedure I applied on one of my latest projects. Supporting version control system is GIT.

The aims for releasing procedure designed:

  • allow for testing window before release date
  • have the possibility for examine released version to test for reported bugs
  • possibility to manage existing releases (hot-fixing critical bugs)

Prepare Release Candidate Branch

We want to stabilize and test some snapshot of current development branch. That's why I'm forking few days before release RC branch from "master" and switch (it will be used for hot-fixing):

git branch RELEASE_0.2.1_branch
git push origin RELEASE_0.2.1_branch
git co RELEASE_0.2.1_branch

I'm marking RC state (RC=Release Candidate) to be able to see changes done for released version:

git tag RELEASE_0.2.1_RC
git push --tags

Anyone familiar with advanced CVS usage will see similarities to tagging for CVS merge purposes. GIT tracks merges automatically, however marking branch starting point is a good idea.

As you can see I created simple naming convention schema to manage releases.

Prepare Release

Time after creating RC branch and before releasing from this branch is the time for testers to do their job and sweep out as many defects as possible. Fixes are added directly on release branch (we will port them to master later).

When tests are done we are preparing release and tag current version by RELEASE_0.2.1

git commit -a -m "version number changed (#XYZ)"
git tag RELEASE_0.2.1
git push --tags

By this tag we will be able to inspect exact version that was sent to our clients.

Prepare hotfix

Sometimes out safety net composed of automated test suite and testing team fails and we have to fix errors reported from production. That is the purpose for release candidate branch. First, switch to correct branch that supports hot-fixed release:

git branch --track RELEASE_0.2.1_branch origin/RELEASE_0.2.1_branch
==OR==: git co RELEASE_0.2.1_branch; git pull origin

Tag current version that goes in this hotfix by RELEASE_0.2.1_hotfix_YYYYMMDD:

git commit -a -m "version number changed (#XYZ)"
git tag RELEASE_0.2.1_hotfix_YYYYMMDD
git push --tags

As you might noticed naming convention is based on branch name. Thanks to this convention we can answer the following questions:

  • what hot-fixes were prepared for release X?
  • what is the latest hotfix for release X?
  • what was delivered in latest hotifix of release X?
  • etc.

Porting back changes from branch to master

Sometimes changes made on branch will be useful for next releases. You can easily merge them back to master:

$ git co master
$ git merge RELEASE_0.2.1
$ git push

GIT tracks what have been merged already so you can merge/cherry-pick in both directions.

Typical Usage

What changes were included in latest hotfix compared to previous one:

 $ git diff RELEASE_0.2.1_hotfix_date1 RELEASE_0.2.1_hotfix_date2

What changes were added in new release:

$ git log  RELEASE_0.2..RELEASE_0.2.1
$ git diff RELEASE_0.2..RELEASE_0.2.1

Git: "pull --rebase" by default

GIT is a distributed version control system that allows to share codebase between developers. Born in Linux kernel world proved to be very useful for any programming task. "Distributed" means you can commit locally (during flight), syncing commits to some external repository is done in separate step (at the airport, waiting for luggage).

During watching my commit list using gitk I noticed many developers are accidentially merging their changes without so called "fast forward" (additional commit is created and the history is not linear). Why? The cause is that they are pulling changes from server AFTER local commit. A example commit tree taken from this worth-reading article:

The solution for this problem is to use "git pull --rebase" when downloading changes from repository. Existing local commits will be "rebased" (SHA-ids will change) and the history will be left linear. It looks much better:

"Rebasing" can be requested during pull by using this syntax:

git pull --rebase

I bet you will forget that after n-th commit ;-) That's why GIT allows to make rebase default option. Just do for every branch you have (including "master"):

git config branch.master.rebase true
git config branch.branch_10.rebase true
...

And tell GIT to setup such rule for every new branch:

git config branch.autosetuprebase always

Of course you can disable automatic "rebasing" when needed:

git pull --no-rebase