(Git/Mercurial) Clone per feature workflow¶
People usually do single clone of project, and then later do the branch-switching and stashing dances in time of development. I find it rather uncomfortable.
What I do is simply having a clone per feature. So my ~/workspace/ directory looks something like this:
myproj-1134-refactor-tests
myproj-1534-add-useful-stuff
myproj-12.0
myproj-13.0
myproj-1983-do-nice-things
myproj-master
And before I want to work on some feature, say, for ticket #9999, I would do:
➤ proj-clone myproj-9999-something-new-to-do master
Which would ask small script to make a directory myproj-9999-something-new-to-do for me, which would contain clone of project in master branch (you can branch-out to feature-branch then if you want).
Why is this better than stashing / branch switching¶
Reasons are that you don’t even have to exit your text editor (or even save your edits), or stopping your local webserver, or remove temporary files (like *.pyc if you’re doing python), or the stashing thing itself.
Personally I find it also better from “keep it simple” perspective.
If you’re in a middle of working on something, and you’re asked to put some small fix, you just do (if you’re already working on master) ➤ proj-clone myproj-master-tmp master, launch new editor and go fix your thing. Later you can just rm -rf the whole directory if it’s not needed.
The proj-clone script itself¶
You’ve noticed, that I didn’t just do hg clone or git clone, but rather called some proj-clone script. There’s a reason for that.
At glance, here’s how it looks like for git:
#!/bin/bash
if [ $# != 2 ] ; then
echo "usage: proj-clone target_dir revision"
exit 1
fi
cd proj-git
git pull
cd ..
git clone --local proj-git $1
cp proj-git/.git/config $1/.git/
cd $1
# I don't know how else do you clone
# with all origin heads being kept, sorry
git pull
# <- you can also do some project-specific bootstrapping here
cowsay $'Ok, it\'s ready!'
Note
This script looks like non-perfect, but I didn’t yet figured out how to make it efficient in git. Maybe you know.
First, you need to make a clone of your project to proj-git directory. Script goes to that directory and does git pull inside. Then it runs git clone proj-git $1 to make a clone. Reason why it’s doing local clone rather than remote clone is that Git and Mercurial build hard-links when they’re cloning locally, so you’re space is not increasing much.
Then, it copies .git/config file so that from now on your pulls and pushes are going to push remotely by default. And checks out the branch you provided in second argument.
You should also add some project-specific things. For my project it is creating an empty directory for test-data, copying settings and copying .emacs-project file.
For mercurial, script would look something like this:
#!/bin/bash
if [ $# != 2 ] ; then
echo "usage: proj-clone target_dir revision"
exit 1
fi
cd proj-hg
hg fetch
cd ..
hg clone proj-hg $1 --noupdate
cp proj-hg/.hg/hgrc $1/.hg/
# <- configuration and other bootstrapping here
cd $1
hg up -r $2
cowsay $'Oh mercurial, I miss you so much!'
Summarize¶
This approach may not fit your programming routine, but it definitely made my life happier. So I hope it will do so for more people.