Skip to content

Instantly share code, notes, and snippets.

@stepheneb
Created January 7, 2009 02:20
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save stepheneb/44147 to your computer and use it in GitHub Desktop.
Save stepheneb/44147 to your computer and use it in GitHub Desktop.
Hi Brent,
Here's a special intro to git for you (and anybody else on ruby-core
interested in your patches).
I'm not writing any kind of complete introduction -- I'm writing just enough
so you can do several things which should be interesting to you. I'm definitely
NOT presenting enough info so you can't easily mess things up.
The idea is to quickly get to some use of git that provides real value ... so
it becomes actually worth it to you to learn it.
So here's what's covered:
1. Get git installed from source using git (so you can update it easily later).
2. Cloning an existing subversion repository so you can easily keep
up-to-date with another project and view the changesets.
3. Clone MRI Ruby, apply your MBARI memory patches in a new branch, and push
that branch to a public git repo so others can more easily try the patches.
fyi: In my examples below I create directories with suffixes
that indicate to me what kind of repository they hold --
dir.git for a dir that has a git repo and dir.svn.git for a
dir that has a git repo cloned from a svn repo. Nobody else
I know does this -- you don't need to do this -- it's just
a convention I use.
-----------------------------------------------------------------------
1. Get git installed from source using git (so you can update it easily later).
There are other ways of getting git but building it from source is so easy.
Get the tar.gz archive.
Starting from the download link on his page: http://git-scm.com/download
$ wget http://kernel.org/pub/software/scm/git/git-1.6.1.tar.gz
$ tar xzf git-1.6.1.tar.gz
$ cd git-1.6.1
$ make
$ make install
$ cd ..
That will install git in your ~/bin dir.
Put ~/bin on your path and now use git to clone git:
$ git clone git://git.kernel.org/pub/scm/git/git.git git.git
$ cd git.git
Install the bash completion scripts:
Follow the instructions at the beginning of this file:
contrib/completion/git-completion.bash
to install the bash completion scripts.
I'm assuming you use bash -- if not look in this dir:
contrib/completion/
to see if there are completion scripts for the shell you use.
Now your shell prompt should look something like this,
the branch you are on is displayed in your prompt:
[git.git (master)]$
Compile and install a new git from the git clone
Right now you have the master branch checked out in your working dir.
The whole repo you cloned is in this dir:
git.git/.git
[yeah ... I know .. that's a case where my directory suffix conventions look insane]
Unless you want the bleeding edge git instead checkout the most
recent stable tagged version -- list the tags in your local repo:
[git.git (master)]$ git tag
Looks like v1.6.1 is the latest stable tag so create a new local
branch and check it out into your working dir
[git.git (master)]$ git checkout -b v1.6.1
Switched to a new branch "v1.6.1"
[git.git (v1.6.1)]$
Now make and install that version -- it's probably
the same as the one you just downloaded
[git.git (v1.6.1)]$ make
[git.git (v1.6.1)]$ make install
Now you can delete the original tar archive.
If a new stable (or unstable) branch of git appears you want to use
just update your local cloned repository.
[git.git (v1.6.1)]$ git fetch
That changes nothing in your working directory -- but let's say there's
now a stable 1.6.2 release -- your git fetch operation copied that new
objects that make up that branch into your local repository. You just need
to make a new local branch and check it out into your working directory.
[git.git (v1.6.1)]$ git checkout -b v1.6.2
Switched to a new branch "v1.6.2"
[git.git (v1.6.2)]$ make
[git.git (v1.6.2)]$ make install
# start the TCL X11 git visualization tool gitk
gitk&
You can view all the changesets for git in gitk
-----------------------------------------------------------------------
2. Cloning an existing subversion repository so you can easily keep up-to-date
with another project and view the changesets.
I'm still assuming here you are not making commits or patches to this project so
I haven't yet described how to setup your general git configuraion ...
Let's say you just want to be able to easily keep up-to-date with ruby-debug
and be able to review their changesets. Ruby debug is hosted in a svn repo here:
http://ruby-debug.rubyforge.org/svn
Opening that page shows that it has a common form for svn repos of branches,
tags, and trunk (I'm going to ignore the branch named ruby-debug-0.10.3).
Clone a copy of the trunk, branches, and tags directories in the svn repo:
$ git svn clone --stdlayout http://ruby-debug.rubyforge.org/svn ruby-debug.svn.git
This will download all 905 revisions in the svn repo that occur in the trunk,
branches, and tags directories. It took about 10m for me.
Once you have your own git clone of the ruby-debug svn repo updates will be
very fast.
$ cd [ruby-debug.svn.git
[ruby-debug.svn.git (master)]$ git svn rebase
Current branch master is up to date.
-----------------------------------------------------------------------
3. Clone MRI Ruby, apply your MBARI memory patches in a new branch, and push
that branch to a public git repo so others can more easily try the patches.
If you were a committer to Ruby and wanted to use Git you'd clone the Ruby svn repo --
but that would take a very long time and because you are just making matches and new
branches you'd like people to try there is an easier way.
Once an hour Vladimir Sizikov" <vsizikov@gmail.com> (vvs) pushes any new
revisions to the Ruby svn repo to a public git clone on github:
http://github.com/rubyspec/matzruby/tree/master
Initially importing a large svn repo into git takes a long time but this repo is
now in native git form so it's much faster to get it:
$ git clone git://github.com/rubyspec/matzruby.git matzruby.git
$ cd matzruby.git
Cloning the entire Matz Ruby git repo took 36m on my DSL connection. The
total size of the content in dir that holds the whole repo:
matzruby.git/.git is just 73M. This 73M holds all the branches, tags, and
revisions for Ruby.
OK -- now for some more advanced stuff -- let's checkout Ruby v1.8.7
patchlevel 72 into a new branch named v1_8_7_72_mbari, apply your
patches in a series of commits, fork the matzruby repo on github and
push your new branch to your fork of the matzruby repo.
This is where it gets both more tricky (easier to shoot yourself) but even
more useful.
First checkout a the tag v1_8_7_72 into your local branch. In subversion
a tag is just a convention -- it's really a branch -- but in git a tag
is just a useful label referencing a specific commit instance. I know that
won't make much sense yet. But here's what it looks like when you checkout
a tag in git:
[matzruby.git (master)]$ git checkout v1_8_7_72
Checking out files: 100% (2560/2560), done.
Note: moving to "v1_8_7_72" which isn't a local branch
If you want to create a new branch from this checkout, you may do so
(now or later) by using -b with the checkout command again. Example:
git checkout -b <new_branch_name>
HEAD is now at 0ca4925... add tag v1_8_7_72
Git warn's you that you haven't actually made a new branch yet -- you've
just changed the state of your working directory to the commit tree
associated with the tag: v1_8_7_72.
Now make a new branch named v1_8_7_72_mbari -- it will automatically be
associated with the commit tree associated with the tag you just checked
out:
[matzruby.git (0ca4925...)]$ git checkout -b v1_8_7_72_mbari
Switched to a new branch "v1_8_7_72_mbari"
[matzruby.git (v1_8_7_72_mbari)]$
I downloaded your directory of patches to my matzruby dir and tried to apply
them but the application process failed because your patches expect svn
variables like this:
$Author:$
To actually look like this:
$Author: shyouhei $
Here's what it looked like:
[matzruby.git (v1_8_7_72_mbari)]$ MBARIp72patches/apply .
Applying all patches in MBARIp72patches to .
Applying MBARIp72patches/ruby-1.8.7-p72-mbari1.patch:
patching file ChangeLog
patching file eval.c
Hunk #1 FAILED at 2.
1 out of 31 hunks FAILED -- saving rejects to file eval.c.rej
patching file version.h
Great -- I've gotten half way through a set of patches and now I've
got a mess to clean up somehow. ...
I'm sure there was a better way but I just deleted all these specific
patches from your set and cleaned up my working directory by doing
a hard reset back to the state of the last commit (git calls this HEAD).
[matzruby.git (v1_8_7_72_mbari)]$ git reset HEAD --hard
HEAD is now at 0ca4925 add tag v1_8_7_72
Well I intended to but several times I tried and found more errors --
they were all the same kind -- not errors I actually had to think about
to fix -- I just need to more effectively find all the patch hunks that
had to be deleted.
After I got all the patches to apply cleanly I erased them one more time:
[matzruby.git (v1_8_7_72_mbari)]$ git reset HEAD --hard
HEAD is now at 0ca4925 add tag v1_8_7_72
Running git log will show one screenful of the most recent commits:
[matzruby.git (v1_8_7_72_mbari)]$ git log
commit 0ca4925414627223b1f7a507b0f31775501a5685
Author: shyouhei <shyouhei@b2dd03c8-39d4-4d8f-98ff-823fe69b080e>
Date: Mon Aug 11 00:37:26 2008 +0000
add tag v1_8_7_72
git-svn-id: http://svn.ruby-lang.org/repos/ruby/tags/v1_8_7_72@18480 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
OK -- that looks right -- right now the HEAD of the v1_8_7_72_mbari branch
is pointing to the commit tree where the svn tag v1_8_7_72 was added.
FYI: lines like these in the git log messages:
git-svn-id: http://svn.ruby-lang.org/repos/ruby/tags/v1_8_7_72@18480 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
are automatically added to the git log of commits when the git svn import occurs.
I then created and ran this short ruby script to commit each one of your patches as
a separate commit:
[matzruby.git (v1_8_7_72_mbari)]$ cat commit_mbari_patches.rb
patches = Dir["MBARIp72patches/ruby-1.8.7-p72-mbari*"]
patches.each do |p|
`patch -p1 < #{p}`
`git commit -a -m "#{File.basename(p)}"`
end
[matzruby.git (v1_8_7_72_mbari)]$ ruby commit_mbari_patches.rb
Now checking the log shows my commits of your patches:
[matzruby.git (v1_8_7_72_mbari)]$ git log
commit 7e58194806ab779c4b9a2c77acda693727ecc60f
Author: Stephen Bannasch <stephen.bannasch@gmail.com>
Date: Tue Jan 6 17:53:23 2009 -0500
ruby-1.8.7-p72-mbari7.patch
commit 8a4e26f24a39d9d538999111281acc5c55d1aff2
Author: Stephen Bannasch <stephen.bannasch@gmail.com>
Date: Tue Jan 6 17:53:23 2009 -0500
ruby-1.8.7-p72-mbari6.patch
etc ...
I already have an account on github:
http://github.com/stepheneb
so I logged in to my account and opened the matzruby repo page:
http://github.com/rubyspec/matzruby/tree/master
and clicked the fork button. That took github about 1m and after I refreshed
my new repo page:
http://github.com/stepheneb/matzruby/tree/master
I had a fork of matzruby!
Back in my local repo I had one remote reference to the original matzruby repo
on github:
$ git remote -v
origin git://github.com/rubyspec/matzruby.git
I added another to the private clone url to my github fork and labeled
it 'stepheneb':
[matzruby.git (v1_8_7_72_mbari)]$ git remote add stepheneb git@github.com:stepheneb/matzruby.git
Now listing the remotes shows two separate repositories I can reference:
[matzruby.git (v1_8_7_72_mbari)]$ git remote -v
origin git://github.com/rubyspec/matzruby.git
stepheneb git@github.com:stepheneb/matzruby.git
Note the different form of the remote url. Mine uses an ssh
connection so I can push to it.
I then pushed my local v1_8_7_72_mbari branch to my remote fork
of matzruby using the remote named: stepheneb
[matzruby.git (v1_8_7_72_mbari)]$ git push stepheneb v1_8_7_72_mbari
Counting objects: 54, done.
Compressing objects: 100% (44/44), done.
Writing objects: 100% (44/44), 20.66 KiB, done.
Total 44 (delta 36), reused 0 (delta 0)
To git@github.com:stepheneb/matzruby.git
* [new branch] v1_8_7_72_mbari -> v1_8_7_72_mbari
Now if you open my matzruby fork in your browser:
http://github.com/stepheneb/matzruby/tree
and select 'all branches' you'll see v1_8_7_72_mbari listed.
I can recreate your patch set locally like this:
$ git format-patch v1_8_7_72
0001-ruby-1.8.7-p72-mbari1.patch.patch
0002-ruby-1.8.7-p72-mbari2.patch.patch
0003-ruby-1.8.7-p72-mbari3.patch.patch
0004-ruby-1.8.7-p72-mbari4.patch.patch
0005-ruby-1.8.7-p72-mbari5.patch.patch
0006-ruby-1.8.7-p72-mbari6.patch.patch
0007-ruby-1.8.7-p72-mbari7.patch.patch
That created seven patch files, one for each commit I made (minus
the elements I deleted manually).
The names look silly because I didn't truncate the string '.patch'
from my commit log message but each one of them can be applied to
a svn repo checkout of 1.8.7 patchlevel 72 using the standard patch
command.
I could post these patches for you to download or you can git clone
the matzruby repo yourself, add my repo as a remote and get a copy
of my v1_8_7_72_mbari branch to start working on like his:
$ git clone git://github.com/rubyspec/matzruby.git matzruby.git
$ cd matzruby.git
[matzruby.git (master)]$ git remote add stephens-fork git://github.com/stepheneb/matzruby.git
[matzruby.git (master)]$ git fetch stephens-fork
[matzruby.git (master)]$ git checkout -b stephens-mbari stephens-fork/v1_8_7_72_mbari
Now you have checked out in your local working directory my v1_8_7_72_mbari
branch. In your local git repo you now have a branch named: stephens-mbari
[matzruby.git (stephens-mbari)]$ git branch
master
* stephens-mbari
If it is worth continuing from there you can merge the changes in my mbari branch
to a new development branch you make named mbari:
[matzruby.git (stephens-mbari)]$ git checkout -b mbari
Now delete my branch:
[matzruby.git (mbari)]$ git branch -d stephens-mbari
And continue work on your branch ...
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment