Hi, I'm Chris Moyer's Blog.

Git-ting started with Git

Recently, I've wanted to become aquainted with Git, the open source Version Control System that Linus Torvalds wrote after moving away from BitKeeper. My past SCM experience has been with CVS and Subversion, and the Git model varies significantly. The main difference being that Git is entirely distributed… Essentially, every user has a complete copy of the repository including history and metadata. They work with other repostiories by accepting patches.

If you've worked long enough with source code, you're familiar with patches, probably enough that the network of repostitories connected and synced up by a series of patches described above scares you. It sounds a lot harrier than it ends up being in practice.

For my examples, I'll walk through the processes I've used while working with Io, the neat little language that got me using Git in the first place. Keep in mind, I'm a relative Git newbie and my vantage is that get moving quickly with projects using Git.

Getting Started

  • Get Git. I'm going to suggest the source. I installed the ubuntu git-core package originally, and it was missing some incredibly useful features, git rebase -i being the most important.
    Git Website, Git Download Site
  • Now, clone your target repository:
> git clone git://www.iolanguage.com/Io

Initialized empty Git repository in /home/cdmoyer/foo/Io/.git/

remote: Generating pack...

remote: Done counting 7812 objects.

remote: Deltifying 7812 objects.

remote:  100% (7812/7812) done

Indexing 7812 objects...

remote: Total 7812 (delta 3799), reused 7468 (delta 3566)

  100% (7812/7812) done

Resolving 3799 deltas...

  100% (3799/3799) done
  • At this point, you have the entire repository cloned on your local machine. You can do many of the things you'd normally expect with source control:
> git log

...

> git log Makefile

...

> git status

# On branch master

nothing to commit (working directory clean)
  • Next, it's helpful to name the remote repository you cloned. Steve is the creator of Io, and maintains the authoritative repository, so I named it steve (it's already named origin, but when you start to work with multiple repositories, a mnemonic name is helpful). We'll also use git fetch to ensure that our local copy of steve is still up to date:
> git remote add steve git://www.iolanguage.com/Io

get fetch steve
  • At this point, we can now compare two things. steve/master and master, which is our local copy. We haven't changed anything, so we won't see any changes. master is the name automatically given to the branch you checked out and started with. I've found it's best to leave this branch alone, letting it represent the state of steve/master, and use it for merging changes in from other sources. I'll periodically update master from steve, this is done in one of two ways:
> git pull steve

or

> get fetch steve

git merge steve/master

They seem to be synonymous.

Making Changes

At this point, if you're a CVS or Subversion user, you're a bit concerned… branches are generally no fun. But under Git, they are pretty manageable. Next we'll walk through creating a branch, doing work on it, and then creating a patch.

  • Create the branch
 > git branch foo

> git branch

  foo

* master
  • Switch to the branch
> git checkout foo

Switched to branch "foo"

> git branch

* foo

  master
  • Make some changes
> echo "# a comment" >> Makefile

> git status

# On branch foo

# Changed but not updated:

#   (use "git add <file>..." to update what will be committed)

#

#       modified:   Makefile

#

no changes added to commit (use "git add" and/or "git commit -a")
  • Add those changes to the local index cache.
> git add Makefile

> git status

# On branch foo

# Changes to be committed:

#   (use "git reset HEAD <file>..." to unstage)

#

#       modified:   Makefile

#
  • Rinse and repeat, change, git add, change, etc.
  • Finish changes, commit to the branch.
> git commit -m"Modified the makefile" Makefile

Created commit 14ff3a4: Modified the makefile

 1 files changed, 1 insertions(+), 0 deletions(-)

> git status

# On branch foo

	nothing to commit (working directory clean)

Note: Locally modified and added files follow you when you change branches, so be careful with files that you modify and leave uncommitted as you move around.

Fetching and Merging Changes

  • Switch back to master (note the note above)
> git checkout master
  • Update from remote server
> git pull steve
  • Switch back to the working branch
> git checkout foo
  • Merge changes. This will open an editor and show you all the commits you've made to this branch. You can pick and choose which commits to keep, which ones to squash together, and which ones to delete. Afterwards, Git will take your commits, bundle them up as you specify, merge the recent changes you pulled into the master, and then apply your changes on top. If there is a conflict, it will drop you to the command-line for fixing any issues.
> git rebase -i master

... Uh oh, we had a conflict!

> vi Makefile

> git add Makefile

> git commit Makefile

> git rebase --continue

If we couldn't fix the merge conflicts, we could do git rebase --abort

Preparing a Patch

  • Switch back to our branch (if we weren't there already)
> git checkout foo
  • Merge down messy working commits into one
> git rebase -i master

# generally change all but the first "edit" into "squash" ... you'll see what I mean.
  • Verify that we have what we want. Use —color to loo for the whitespace issues that Git hates. (many editors add whitespace to the end of lines that you edit, if you aren't very careful.)
> git diff --color master
  • Make the patch
> git format-patch master

0001-Modified-the-makefile.patch
  • And voila, there's your patch, now you can email it off to “steve”.
  • You may want to set some git config options to have your name and email address automatically be set properly in the patch file.
> git config user.name Chris Moyer

> git config user.email chris@inarow.net

Miscellany

  • Normally git diff will only show you changes since your last addition, to see since your last commit:
> git diff --cached
  • Search files controlled by git
> git grep "error"
  • Delete a branch that you're done with, including your local changes and code
> git branch -D branchname

Hopefully this will give you enough to get started. It's server me well so far. As I come across other common, useful or complex operations, I'll write them up. Good Luck!



Back to Blog Home »