Dr Nic

Using Git within a project (forking around)

Death Star - as seen on TV

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]

drnic's ruby-on-rails-tmbundle at two_point_ooh 2014 GitHub

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.

What now?

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.

gitk: Ruby on Rails.tmbundle

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:

Commit History for drnic's ruby-on-rails-tmbundle 2014 GitHub

And my gitk now show’s I’m sweet:

gitk: Ruby on Rails.tmbundle

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…

Related posts:

  1. Hacking someone’s gem with github and gemcutter Ever used a rubygem, found a bug, and just...
  2. Migrating project websites to github pages with sake tasks, new websites with jekyll_generator Its almost Christmas time and that means presents. It...
  3. My attempt at sake task management I’ve used sake intermittently in my workflow. It competes...
  4. Git for Rubyforge accounts First there was CVS, then came SVN to RubyForge....
  5. Get ready for the TextMate “Trundle to Rails 2.0 Bundle” Have you noticed lately that the Rails TextMate git...

29 Responses to “Using Git within a project (forking around)”

  1. Sam Aaron says:

    Bring on the clone wars!

  2. Garry says:

    In your “third line” where you have:

    git checkout -b strelau/two_point_ooh

    I think it might be wise to point out — Since “strelau” is also what you named the remote, you may have subtle problems when git tries to resolve the reference “strelau/two_point_ooh” b/c it can mean two things:

    1. A local branch named “strelau/two_point_ooh”
    2. A branch named “two_point_ooh” on the “strelau” remote.

    You’d have to prefix the ref with “remotes” (e.g. remotes/strelau/two_point_ooh”) if you ever needed to refer to #2.

    Overall I think it’s OK, but just keep it in mind.

  3. dstrelau says:

    So I’ve moved over to the cool-kids-club and am now hosting on GitHub[1] Also, I noticed another fork by peimei[2] pop up, but nothing new yet. Added as a remote though!

    Seriously, the more I use (and therefore actually understand) Git, the more awesome I find.

    [1]: http://github.com/dstrelau/ruby-on-rails-tmbundle/tree/two_point_ooh
    [2]: http://github.com/peimei/ruby-on-rails-tmbundle/tree/two_point_ooh

  4. tomtt says:

    Thx for the nice article on git, I have been using it for a while and it *kicks* svn’s ass!

    Also check out qgit which is a much nicer gui implementation for viewing the git tree. On Ubuntu it’s just an apt-get qgit away, it may or may not be a bit harder on OS-X.

  5. [...] Nic tries to explain git, if you want to understand how to contibute to an open source [...]

  6. [...] Using Git within a project (forking around) by Dr. Nic [...]

  7. Phil says:

    Great article.

    I do believe that your fork/clone distinction is something that’s specific to github, not applicable across git in general. Within git, every clone is technically a fork, but github calls clones that happen within its own domain “forks”, and uses the term in a more specific way.

  8. Dr Nic says:

    @Phil [via] – yeah that’s possibly likely. I still like the word “fork” as a concept of a different remote push/pullable clone.

  9. zimbatm says:

    I like thinking in term of code divergence. For me forking is publishing local divergences from the cloned repository :)

  10. Dr Nic says:

    @zimbatm [via] – “local divergences” = branching? :)

    I’m suitably confused, and I wrote the article… hehe.

    Again, I like having a word to describe the existence of multiple “public” (remote) repositories that share some common commit history (fork), since it is the existence of these that enables the “pulling” btw repositories. If the DSCM allowed local commits (useful when disconnected from internet) but still only had a single remote repo, it would miss the magic. I lack a good word to describe what it would be missing. Damn.

    Forking. Good word, imo :)

  11. Dr Nic says:

    @Phil [via] – they do take this concept and embedded it in their application unlike other “community git repository hosts”. They even give you a handy “fork” button. I’m to believe they’ll soon be using the knowledge of which repos are forks of each other to provide other useful info like – which repositories have new changes that I might like to investigate?

    But its not specific to github – you can remotely host your clone of a repository. If there are 2+ remote repositories out on the intertubes that share common commit history, then I think of them as forks of each other.

    I get confused easily, so I’m hoping some terminology makes life easier for me.

  12. [...] for his adept use at Star Wars metaphor and humanization of Grand Moff Tarkin in his post on using Git to manage the new Rails TextMate bundle. Well done, sir. I owe you a frosty one.Share [...]

  13. [...] Using Git within a project (forking around) [...]

  14. Patrick says:

    There’s a nice tutorial on how to install QGit on OS X. It also works on Leopard:

    http://wincent.com/knowledge-base/Installing_QGit_2.0_on_Mac_OS_X_Tiger

    Greetings

  15. [...] Git’s raison d’être? 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. “Using Git within a project” [...]

  16. I’m really digging git lately; still a lot to learn though. thx for the writeup!

  17. [...] you’re initiating an open source project, there are good reasons to prefer Git, as detailed here by Dr Nic Williams. If your project is just for yourself or your minions (that is, with a single point of ultimate [...]

  18. James says:

    Can you discuss the differences among “Public Clone URL,” “Your Clone URL,” and “Push URL” on GitHub? I tried forking a project (your Lovd) and making a commit to my fork, but the commit doesn’t show up on GitHub.

    (Also: your OpenID login doesn’t work with my OpenID account at https://gcnovus.myopenid.com, which is, in fact, an OpenID endpoint.)

  19. [...] Whitten: Well you don’t have to go far to see the excitement around Git. I am hosting PmpknPi in two Git repositories (GitHub and Gitorious) and one Subversion [...]

  20. [...] Using Git within a project (forking around) [...]

  21. [...] Whitten: Well you don’t have to go far to see the excitement around Git. I am hosting PmpknPi in two Git repositories (GitHub and Gitorious) and one Subversion [...]

  22. [...] Using Git within a project (forking around) [...]

  23. markatharvest says:

    Great Article,
    Only thing, I did not get was, lets say I have my own repo say $myrepo, now some personx forks out of $myrepo, and now I want to pull his changes. How do I go it.
    The article explains if that personxhas a branch name say $xbranch, then I can add a remote repo by saying
    # git remote add personxrepo git@github.com:personx/$myrepo.git ,
    # git pull personxrepo $xbranch,
    but what if he does not have the $xbranch, what is the command I need to execute, looking for your guidance

  24. [...] out the repo’s public address. And before I know it I had my first patch. Now what? I read Dr. Nic’s blog post about git when it came out, so I went back and read it again. After reading a few times I realized two [...]

  25. [...] Git Cloning and Git Forking defferences are described in this article [...]

  26. [...] Using Git within a project (forking around) [...]

  27. aPeel Blog says:

    Git can make your IDE faster!…

    We recently switched from using Subversion to Git for source controll management….