Flameman/git

For more interesting projects done by Flameman, be sure to check out his project index

Overview
Git is a distributed version control system. No, you don't need to know what that means to use this guide. Think of it as a time machine: Subversion or CVS without the cruft.

If you make a lot of changes, but decided you made a mistake, this will save your butt.

This guide is for people who want to jump to any point in time with their project/game/whatever, and want something to use for themselves.

Install git (on gentoo)

 * emerge dev-util/git

Introduce yourself to git

 * git config --global user.name "Joey Joejoe"
 * git config --global user.email "joey@joejoe.com"

You only need to do this once.

Start your project
Start your project using the Sphere editor, or from a ZIP file, or just by making the directory and adding files yourself.

Now cd to your project directory:

cd myproject/

Tell git to start giving a damn about your project: git init

... and your files in it:

git add.

Wrap it up:

git commit

Now type in a "commit message": a reminder to yourself of what you've just done, like:

Initial commit.

Save it and quit (type Ctrl+o Ctrl+x if you're in nano, :x if you're in vim) and you're done!

Work in bits
When dealing with git, it's best to work in small bits. Rule of thumb: if you can't summarise it in a sentence, you've gone too long without committing.

This section is your typical work cycle:

1. Work on your project. 2. Check which files you've changed:

git status

3. Check what the actual changes were:

git diff

4. Add any files/folders mentioned in step 2 (or new ones):

git add file1 newfile2 newfolder3

5. Commit your work:

git commit

6. Enter and save your commit message. If you want to back out, just quit the editor.

Repeat as much as you like. Just remember to always end with a commit.

Admire your work
To see what you've done so far, type: git log

To just see the last few commits you've made:

git log -n3

Replace 3 with whatever you feel like.

For a complete overview, type:

git log --stat --summary

Browse at your leisure.

View changes
To view changes you haven't committed yet:

git diff

If you want changes between versions of your project, first you'll need to know the commit ID for the changes:

git log --pretty=oneline

6c93a1960072710c6677682a7816ba9e48b7528f Remove persist.clearScriptCache function. c6e7f6e685edbb414c676df259aab989b617b018 Make git ignore logs directory. 8fefbce334d30466e3bb8f24d11202a8f535301c Initial commit.

The 40 characters at the front of each line is the commit ID. You'll also see them when you git commit. You can use it to show differences between commits.

To view the changes between the 1st and 2nd commits, type:

git diff 8fef..c6e7

Note how you didn't have to type the whole thing, just the first few unique characters are enough.

To view the last changes you made:

git diff HEAD^..HEAD

How to fix mistakes
Haven't committed yet, but don't want to save the changes? You can throw them away:

git reset --hard

You can also do it for individual files, but it's a bit different:

git checkout myfile.txt

Messed up the commit message? This will let you re-enter it:

git commit --amend

Forgot something in your last commit? That's easy to fix.

git reset --soft HEAD^

Add that stuff you forgot:

git add forgot.txt these.txt

Then write over the last commit:

git commit

Don't make a habit of overwriting/changing history if it's a public repo you're working with, though.

Undoing in Git - Reset, Checkout and Revert
Git provides multiple methods for fixing up mistakes as you are developing. Selecting an appropriate method depends on whether or not you have committed the mistake, and if you have committed the mistake, whether you have shared the erroneous commit with anyone else. Fixing un-committed mistakes

If you've messed up the working tree, but haven't yet committed your mistake, you can return the entire working tree to the last committed state with

$ git reset --hard HEAD

This will throw away any changes you may have added to the git index and as well as any outstanding changes you have in your working tree. In other words, it causes the results of "git diff" and "git diff --cached" to both be empty.

If you just want to restore just one file, say your hello.rb, use git checkout instead

$ git checkout -- hello.rb $ git checkout HEAD hello.rb

The first command restores hello.rb to the version in the index, so that "git diff hello.rb" returns no differences. The second command will restore hello.rb to the version in the HEAD revision, so that both "git diff hello.rb" and "git diff --cached hello.rb" return no differences. Fixing committed mistakes

If you make a commit that you later wish you hadn't, there are two fundamentally different ways to fix the problem:

You can create a new commit that undoes whatever was done by the old commit. This is the correct thing if your mistake has already been made public.

You can go back and modify the old commit. You should never do this if you have already made the history public; git does not normally expect the "history" of a project to change, and cannot correctly perform repeated merges from a branch that has had its history changed.

Fixing a mistake with a new commit

Creating a new commit that reverts an earlier change is very easy; just pass the git revert command a reference to the bad commit; for example, to revert the most recent commit:

$ git revert HEAD

This will create a new commit which undoes the change in HEAD. You will be given a chance to edit the commit message for the new commit.

You can also revert an earlier change, for example, the next-to-last:

$ git revert HEAD^

In this case git will attempt to undo the old change while leaving intact any changes made since then. If more recent changes overlap with the changes to be reverted, then you will be asked to fix conflicts manually, just as in the case of resolving a merge. Fixing a mistake by modifying a commit

If you have just committed something but realize you need to fix up that commit, recent versions of git commit support an --amend flag which instructs git to replace the HEAD commit with a new one, based on the current contents of the index. This gives you an opportunity to add files that you forgot to add or correct typos in a commit message, prior to pushing the change out for the world to see.

If you find a mistake in an older commit, but still one that you have not yet published to the world, you use git rebase in interactive mode, with "git rebase -i" marking the change that requires correction with edit. This will allow you to amend the commit during the rebasing process.

Writing good commit messages
The author of Pro Git (an excellent online book) gives this advice for commit messages:

Getting in the habit of creating quality commit messages makes using and collaborating with Git a lot easier. As a general rule, your messages should start with a single line that's no more than about 50 characters and that describes the changeset concisely, followed by a blank line, followed by a more detailed explanation. The Git project requires that the more detailed explanation include your motivation for the change and contrast its implementation with previous behavior — this is a good guideline to follow. It's also a good idea to use the imperative present tense in these messages. In other words, use commands. Instead of "I added tests for" or "Adding tests for," use "Add tests for." Here is a template originally written by Tim Pope at tpope.net:

Short (50 chars or less) summary of changes

More detailed explanatory text, if necessary. Wrap it to about 72 characters or so. In some contexts, the first line is treated as the subject of an email and the rest of the text as the body. The blank line separating the summary from the body is critical (unless you omit   the body entirely); tools like rebase can get confused if you run the two together.

Further paragraphs come after blank lines.

- Bullet points are okay, too

- Typically a hyphen or asterisk is used for the bullet, preceded by a      single space, with blank lines in between, but conventions vary here

If all your commit messages look like this, things will be a lot easier for you and the developers you work with. The Git project has well-formatted commit messages — I encourage you to run git log --no-merges there to see what a nicely formatted project-commit history looks like.

Ignoring files
When you check your project status, sometimes you'll get something like this:

git status

nothing added to commit but untracked files present (use "git add" to track)
 * 1) On branch master
 * 2) Untracked files:
 * 3)   (use "git add ..." to include in what will be committed)
 * 4)       bleh.txt
 * 5)       module.c~
 * 1)       module.c~

If you don't want git to track these files, you can add entries to .gitignore:

nano .gitignore

And add the files you want ignored:

bleh.txt

The first line ignores bleh.txt the second line ignores all files and directories ending with a tilde (~), i.e. backup files.

You can check if you got it right:

git status

no changes added to commit (use "git add" and/or "git commit -a")
 * 1) On branch master
 * 2) Changed but not updated:
 * 3)   (use "git add ..." to update what will be committed)
 * 4)       modified:   .gitignore
 * 1)       modified:   .gitignore

Don't forget to commit your changes to .gitignore!

git add .gitignore git commit

With something like this for your commit message:

Make git ignore bleh.txt and backup files.

Use .gitignore to keep your messages clean, and stop git from bugging you about stuff you don't care about. It's a good idea to ignore things like executable binaries, object files, etc. Pretty much anything that can be regenerated from source.

Branching and merging
A branch is a separate line of development. If you're going to make a bunch of changes related to a single feature, it might be a good idea to make a "topic branch": a branch related to a topic/feature.

To make a new branch:

git branch feature_x

To view the current branches:

git branch

feature_x
 * master

The asterisk (*) shows your current branch. master is the default branch, like the trunk in CVS or Subversion.

To switch to your new branch, just type:

git checkout feature_x

If you check the branches again, you'll see the switch:

git branch

master
 * feature_x

Now go through the usual edit/commit cycle. Your changes will go onto the new branch.

When you want to put your branch changes back onto master, first switch to master:

git checkout master

Then merge the branch changes:

git merge feature_x

This will combine the changes of the master and feature_x branches. If you didn't change the master branch, git will just "fast-forward" the feature_x changes so master is up to date. Otherwise, the changes from master and feature_x will be combined.

You can see the commit in your project's log:

git log -n1

If you're happy with the result, and don't need the branch any more, you can delete it:

git branch -d feature_x

Now when you see the branches, you'll only see the master branch:

git branch


 * master

You can make as many branches as you need at once.

Tags
If you hit a new version of your project, it may be a good idea to mark it with a tag. Tags can be used to easily refer to older commits.

To tag the current version of your project as "v1.4.2", for example:

git tag v1.4.2

You can use these tags in places where those 40-character IDs appear.

What now?
git can help with working with other people too. Of course, then you do have to learn about distributed version control. Until then, just enjoy this page.

But if you want to learn:


 * Pro Git online book
 * gittutorial manual page online
 * Everyday git with 20 commands or so
 * The official git web site

Main git selling points (ripped off the main site):


 * Distributed development, i.e. working with other people.
 * Strong support for non-linear development, i.e. working with other people at the same time!
 * Efficient handling of large projects, i.e. fast!
 * Cryptographic authentication of history, for the paranoid.
 * Scriptable toolkit design, you can script pretty much any git task.

If something doesn't seem right or is confusing, contact me =P

How to Meld for Git diffs
git config --global diff.external meld

you could navigate to a Git tracked directory and enter this

git diff filename

Meld will open but it will complain about bad parameters. The problem is that Git sends its external diff viewer seven parameters when Meld only needs two of them; two filenames of files to compare. One way to fix it is to write a script to format the parameters before sending them to Meld. Let's do that.

Create a new python script in your home directory (or wherever, it doesn't matter) and call it diff.py.


 * 1) !/usr/bin/python

import sys import os

os.system('meld "%s" "%s"' % (sys.argv[2], sys.argv[5]))

Now we can set Git to perform it's diff on our new script (replacing the path with yours):

git config --global diff.external /home/nathan/diff.py git diff filename

This time when we do a diff it will launch Meld with the right parameters and we will see our visual diff.