Le TwiBlog

The one with Twidi

Aller au contenu | Aller au menu | Aller à la recherche

samedi 11 décembre 2010

Transform a linear git repository into a one adapted to a workflow named git-flow

For a few months now, i develop "GRead", a Google Reader client written in python + Qt, for use on the Nokia n900, but with the help of PyQt, works also on any desktop.

It's my first complete project, open-source, and managed by Git, on GitHub.

But i come from Subversion and although i know that git is really powerful and that i can easily manage branches with it, i used to have the same workflow than with Subversion : a linear one.

I mainly work in the master branch, with some developments done in a specific branch but finally merged in the master without nothing in the master during this time.

It was a "subversion applied to git" way of doing things.

And then i saw a git presentation in Paris and the orator spoked about "git-flow".

I was interested in this and i read some stuff about git-flow and decided to apply it to all of my future projects. And on my current main one, GRead

I won't tell you why and how git-flow is great. Just how to transform an linear flow to a git-flow one.

Here is the graph of my repository before :

And after :

For transform my graph i wrote a bash script (it took me lot of hours, i just started too learn git !) which will do everything. It will create master and develop branches, and a branch for each feature or hotfix you specify in the script, and for each tag you want, a release branch.

Launch the script it locally, in the directory of a clone of your repository, and all the magic will apply. It can takes a long time to finish. For me it was 150 commits. The more branches and the more commits you have, the longer it will take to run.

Be careful, some times the script will ask your attention, in several cases :

  • a cherry-pick cannot be applied. Simply ignore it if it's from a merge (read the message just above the alert)
  • an existing branch will be duplicated, you should answer "Y" to continue for this branch (else the branch is ignored)

You can find the script "linear-git-to-git-flow.sh", on GitHub, heavily commented. Just read comments in the first part to know how to use it.

PS : i know that this script can surely be better. But notice that i just started to really use Git... i you have any suggestion i will be happy to enhance this script with your help

Duplicate a Git repository

Imagine you have a repository on GitHub. And you want to play with objects in the Git internal key value store. For example to create a branch for past commits, rearrange branches, etc, etc.

But it can be preferable to have a test repository to do this if you do not want to lost things...

For me it was to adapt the linear development of an application (GRead) to a workflow i discovered at a Git presentation : Git-flow. I'll explain this in the next post on this blog.

The first thing to do for me was to find a way of duplicate my repository on GitHub on which i can work as it was the original one, with same data.

The solution is easy if you know a little of the Git internal, but for me it was not the case (i just did some pull/commit/push by this time)

So thanks to Thomas Mango for giving me the solution :

0. Some variables

  • $myproject is your project name on github and the name of the directory in which the project was cloned.
  • $myotherproject is the name of the duplicate.
  • $meandmyself if your username on GitHub

1. Create a new repository on GitHub, but don't follow steps after that. Just create it.

You now have https://github.com/$meandmyself/$myotherproject

Duplicate your local copy of the repository :

 cp -a $myproject $myotherproject

Change the origin of the copy :

 cd $myotherproject
 git remote rm origin
 git remote add origin git@github.com:$meandmyself/$myotherproject.git

And then push your copy online :

 git push origin master

It's done !

If you want to copy branch too, note that they are already in your local copy. You just have to do this : (work for each local branch) :

 for branch in $(git branch | sed -e s/\*//g); do if  "$branch" != "master" ; then
   git checkout $branch
   git push origin $branch
   git checkout master
   git branch -f $branch origin/$branch
 fi; done