29 February 2012

Git - alias to cherry-pick with automatic message

While working with Git, there is situation where you will use git cherry-pick to carry over change from a version to another.
Even if you want to adapt cherry-picked commit messages, it can be done very quickly, if
you know SHA1 of commits you want to manage (e.g. you can use my script/alias to 'Get your commits'), and if you can program the message update 'rule'.

Let's say you work in a Team using a SVN repository, and you want to fit the rule which is providing a final line likes 'Carried over from trunk svn #XXX', or 'Carried over from RX_Y svn #XXX'.

This is a very simple GNU/Bash script allowing to cherry-pick commits whose SHA1 are specified, with automatic message update (for instance create a file /path/to/gitCherryPickAutoMessage.sh and copy/paste):

#!/bin/bash
#
# Author: Bertrand BENOIT
# Version: 1.0
# Description: automatically formats commit message (according to git-svn-id info, or cherry picked ... one).
#
# usage: $0 []
# To use this script, create a git alias.
# It can NOT be done like this (git complains with: Expansion of alias 'cp' failed; ... is not a git command):
# git config --global alias.cp 'GIT_EDITOR=/data/scripts/gitCherryPickAutoMessage.sh cherry-pick -ex'
#
# A workaround:
# git config --global alias.cp '!sh -c "GIT_EDITOR=/data/scripts/gitCherryPickAutoMessage.sh git cherry-pick -ex $*"'
# Information:
#  - if the 'cherry-picked' commit was already commited on svn, there is a git-svn-id information which is enough
#  - otherwise, work on '(cherry picked from commit XXX)' message
# In any case, it replaces 'git-svn-id' or 'cherry picked ...' message by '(Carried over from XXX svn #YYY)'
#  with XXX corresponding to trunk or remote branch, and YYY svn revision (only if there is git-svn-id message).
messageFile="$1"
# Checks if there is a 'git-svn-id' information.
if [ $( grep -c "git-svn-id" "$1" ) -gt 0 ]; then
  # Works on message: 'git-svn-id'
  # Formats trunk information, if any.
  sed -i 's/^.*git-svn-id:.http.*\/trunk@\([0-9]*\)[ ].*$/(Carried over from trunk svn #\1)/' "$messageFile"

  # Formats branch information, if any.
  sed -i 's/^.*git-svn-id:.http.*\/branches\/\(R[^@]*\)@\([0-9]*\)[ ].*$/(Carried over from \1 svn #\2)/' "$messageFile"

  # Removes any potential "(cherry picked ..." message.
  sed -i 's/^.*cherry picked from commit .*$//' "$messageFile"
else
  # Works on message: '(cherry picked from commit XXX)'
  commitHash=$( cat "$messageFile" |grep "(cherry picked from .*)" |sed -e 's/^.*commit[ ]\([a-f0-9]*\).$/\1/' )
  remoteBranch=$( git branch --contains "$commitHash" -vv |head -n 1|sed -e 's/^[^[]*[[]\([^:]*\):.*$/\1/' )
  [ -z "$remoteBranch" ] && echo "WARNING: unable to define remote branch of commit '$commitHash'. Check your commit message before push." >&2 && exit 1
  sed -i "s/^.*cherry picked from commi.*$/(Carried over from $remoteBranch)/" "$messageFile"
fi
You can add this script as a new Git alias:
git config --global alias.cp '!sh -c "GIT_EDITOR=/path/to/gitCherryPickAutoMessage.sh git cherry-pick -ex $*"'

Then, after git checkout, you can easily cherry-pick as many commit as you want (let's say 566f417 6047dde 46361ee c83c18e 0cbbfc2):
git cp 566f417 6047dde 46361ee c83c18e 0cbbfc2

No comments:

Post a Comment

Thank you for your visit, let's share your point of view: