In Star Wars, when Grand Moff Tarkin orders the destruction of the planet Alderaan, you must question his motivations. Historically, I think too much emphasis has been placed on “he’s an Evil Warlord doing the bidding of Darth Vader and the Emperor”, and “the Rebel scum must be tortured and punished.” But I’m not so sure this is the whole picture.
As developers, we know how exciting it is for a project/website to “go live”. You’ll get some praise from users, some bugs reports, but mostly, you will get the thrill of having finished something and seen it in action.
I’ve got to believe that when Tarkin gave the orders to “open up the taps on this baby,” there was a very different emotion at work amongst all his outwards “Give in to the Empire, Princess Leia” soapboxing. After flying around the emptiness of space in his brand new Death Star, never having actually used its main weapon, he just wanted to see if the thing actually worked.
If George Lucas hadn’t cut away from the cockpit of the Death Star to show us the planet Alderaan being obliterated, I guarantee you that Tarkin was waving his arms in the air, yelling “Oh that’s what I’m talkin’ ’bout,” with his lackies were all high-fiving each other in the background.
This brings me to Git.
Since moving the development of the Rails TextMate bundle to a git repository, several people have forked the repository.
When I pulled in the first “patch” from one of the forked repositories, I finally felt I’d “opened up the taps” on git. It was a sweet feeling.
Whilst Git was created by Linus for managing the Linux project, I get the feeling that Git’s raison d’Ãªtre was to manage TextMate bundles. Weird since Linus probably doesn’t use TextMate.
A TextMate bundle is a combination of common/default snippets and personal snippets. Those personal snippets may even be useful for other people. Other people way want them. They may even join the set of default snippets.
Git’s system of forked repositories makes all this a reality. In a different, subversion-tainted reality, this scenario would mean that your local subversion checkout of the bundle becomes a mess of modified files and patch requests. With Git, you can stop caring about the central SCM. You make your own local changes, you push them to your own remote fork of the repository, and if they get absorbed into the common/default/central bundle so be it.
As I’m to understand it, this workflow is to Git as destroying planets is to the Death Star. Both Git and the Death Star are technologically impressive and to associate with them is to be seen as “cool”, but they can both do so much more.
Forking and Cloning
I’m not sure if I’m using official vocabulary, but I think of “forking” and “cloning” as different and I’ll use these terms until I’m educated otherwise.
Cloning is to make a copy of a remote repository into your local development environment. Your work machine. With the exception of IM, bittorrent and your shared iTunes library, that FTP server you don’t know is running, etc, no one’s got access to this machine or your clone.
You can make changes to your clone. For the TM bundles you could create a new snippet etc. You can then add and commit those changes into your local Git clone. They are committed now like a normal subversion repository commit. Except only you have them.
You could share the changes with a patch. You create the patch, then email it or upload it to wherever patches are uploaded to for your project.
Alternatively, you can push your changes to remote repositories (see “fork” below). If you have commit access to the original repository you cloned, you’d probably push your commits to this repository. If you don’t have commit rights, then you can fork the repository and push your commits there. “Freeeeeedooooom!!!” cried William Wallace whilst simultaneously having his Scottish testicles emasculated.
Forking is to clone an entire remote repository into another remote repository. Now you have two repositories based around the same code base. At that one point in time, they have the same set of files and the same history of changes.
As suggested above, you might do this because you don’t have commit rights to another fork, or because you are literally doing just as the name suggests: forking the project and going your own way. Either a moderate or radically different direction.
This is exactly what is wonderful about Git with TextMate bundles – there is no “one true path”.
If you wanted to fork the Rails TM bundle that I’ve hosted on github into another repository hosted on github then you click the “fork” button. [Email me for for the secret "I want to help make TM Rails Bundle awesome" github password if you need it to create an account]
Alternately you could fork and host your repository on any public git server. Dean Strelau forked it onto Gitorious. You could also fork it onto gitorious.org, you’ll just need to give it a different name; e.g. prefix/suffix your name.
“In the end, there can be only one”
No. No one needs to have their head cut off, Highlander-style, with Git. I mean, unlike Subversion, Git doesn’t force any organisational behaviour. All commits don’t have to make their way back into one “root” repository.
But, once you have committed changes to your fork you might like to let other forkers know about them; especially if there is one repository that is commonly known as the “root” repository. For the TM Rails bundle it would be my repository since I’ll then aggregate changes and push them down to the official Subversion repository and from there they get pushed out with future TextMate releases.
For the Rubinius project, you’d probably want all your commits investigated and pulled into Evan Pheonix’s personal git clone. He’s not good looking enough to just be a poster boy so I assume he knows how to build and distribute the project for download.
I’m not sure what the organisation hierarchy of evil that is being built around the Rubinius project, but you can probably post a notification of your commits and your repository URL to the Rubinius lighthouse tracker. Don’t have a fork? Just submit patch files. Already have commit rights to Evan’s repository? Push directly to it.
Three different ways to contribute. Which one to use? The organisation of the project decides. Rubinius has a how to contribute page.
For the Rails TextMate bundle project, the preferred way to contribute is either patch files from your local clone, or to fork the project and let me know of your fork URL. Discussion of the project happens on the Google Group.
So, once your project has multiple forks floating around – how do you as a project maintainer pull in the commits contributed by others?
How to pull friends and influence people
Let’s continue with the example of Dean’s fork of the TM bundle. After he forked it, he used the previous article’s instructions to clone his own fork, rather than my repository. To you, once you’ve forked a repository, then your repository is your git “origin” and the original repository you forked just becomes a fork to pull from when you want to synchronise your repositories. Make sense? Thought so.
Put another way, if you don’t fork my TextMate repository rather you just clone it and modify it, then your “origin” will be my repository. You’ll then contribute by emailing patch files.
Or you can fork my repository and then you clone this new repository locally. This new repository is your “origin”. You contribute by committing changes locally and pushing them to your origin (your fork). I then investigate them (see below), and merge them into my repository if I feel like it (gifts help too).
So, Dean’s got a fork. He’s cloned it locally, made changes, committed them locally and pushed them out to his fork. I know I’ve said the three times, but it confused the crap out of me so I think its worth repeating… a lot.
Now how do I pull in Dean’s commits into my local clone, investigate them, and then merge them into my repository? I’m glad you asked.
From within my local clone:
git checkout two_point_ooh git remote add strelau git://gitorious.org/ruby-on-rails-tmbundle/mainline.git git checkout -b strelau/two_point_ooh git pull strelau two_point_ooh
The first line changes my local clone into the “two_point_ooh” branch. Dean has told me that he has made his commits into his own two_point_ooh branch. So, my own two_point_ooh branch is the closest so I’ll start here. Its probably irrelevant which branch you start with. Perhaps.
The second line stores the information about Dean’s fork into my .git/config file. I’ve given the fork a label “strelau”, to differentiate it from my own remote repository “origin”.
The third line creates a new branch of my local repository. This branch will not be pushed up into my remote repository later on, rather its just for my own personal collection. The name of this branch is arbitrary. I could call it “ginger_beer_cordial”, but “strelau/two_point_ooh” is more meaningful. “strelau” to remind me which fork I should pull from, and “two_point_ooh” to remind me which branch of “strelau” to pull from.
Note, you are best to run this “git checkout -b name” operation from within another branch that most closely matches the contents you are about to pull in. That’s why I did the first line – to change into my own two_point_ooh branch first.
The fourth line pulls down any changes from Dean’s two_point_ooh branch into the current branch – strelau/two_point_ooh. That is, you now have a copy of it locally.
UPDATE: I really think this needs a good diagram here to explain the existance of two remote repositories, and within the local clone, the existance of two branches: two_point_ooh, and strelau/two_point_ooh. Plus there’ll be other branches in the local clone: master, origin/master (my remote version), origin/two_point_ooh (my remote version that I’ll push too when I’ve merged in Dean’s changes).
I can now investigate his commits.
gitk is a fun tool to see the various branches and differences. It also shows the unique SHA1 codes for each commit, if you want to cherry pick changes rather than merge all of Dean’s changes into your own code.
Later, when Dean has more commits to offer the world, I’ll just run:
git checkout strelau/two_point_ooh git pull strelau two_point_ooh
See how the name of “Dean’s branch” helps remember what the “git pull” command is? TIP: Give meaningful name to remote branches.
Once you’ve pulled down someone else’s remote branch (from their fork) it is just another local branch. You can explore it in
gitk and see how it compares to other branches, for example.
But what you’ll ultimately want to do is merge some/all of Dean’s commits into your branch, commit them, and push them out to your remote repository. If you have the “central” repository then this is akin to “accepting a patch”.
This process is now basic Git. Like driving the Death Star. Boring, and described elsewhere. Go back to your own branch, merge changes over, and push out to remote repo.
And now, Dean’s changes are in my remote repo:
And my gitk now show’s I’m sweet:
But what about Dean?
That’s like caring about the people on Alderaan…
What I mean to say is… Dean can now pull in my remote “two_point_ooh” branch into his local “two_point_ooh” branch. He may or may not like what I did to it.
I guess Dean and the people of Alderaan can blog about that one…