[Written for internal DD9 use, published for the good of mankind]

What is git?

Git is an application for distributed version control. It’s version control because it lets you deftly create and manage versions of your files, and it’s distributed because there is no server.

What is a git repository?

A git repository is a collection of files that git is managing versions for. You can turn any folder into a git repository with the command

git init

A git repository looks just like any other folder on your computer, except it contains a (often hidden) folder called “.git”. This is where it stores all its data, including the version history of your files.

What is github?

Github is, among other things, a site for hosting git repositories. It also has bonus features like issue tracking, project wikis, and basic social networking.

Why host git repositories?

The fundamental unit of version control, under git, is a “commit”. A commit is a collection of changes to files, labeled with a message indicating why that change was made, what it’s for, or what it does. You could have a whole team working out of one git repository, but if two users were working simultaneously, it would be very difficult for them to commit their own changes without also committing each other’s changes. A better process is for each member of a team to have their own clone of the repo.

We host git repositories so that members of a team, each of whom have their own clone of the repository, have somewhere to push their local commits to, and somewhere to pull other people’s commits from.

Git has no server, but people often treat a hosted repository as though it is one. You can think of the hosted repo as the canonical, latest working version which everyone can safely sync with.

How do I get my own copy of (clone) a repo?

“git clone” followed by the URL to the repository. For example

git clone git@github.com:DD9/dd9-extranet.git

What is a basic workflow with git?

1)   Verify my repo is clean (i.e. hasn’t been somehow altered since the last time I worked on it)

git status

This will tell you, among other things, the current version control status of your files. It’ll tell you if you’ve changed, added, or deleted any files, and if you’ve staged any changes for your next commit.

What does it mean to “stage” changes? When you make a commit, by default, it includes only the changes you’ve staged. In this way you could change a bunch of files, but only stage and commit a few at a time (e.g. if you aren’t ready to commit some of your changes yet).

2)   Pull any new changes from github.

git pull

Whenever possible, I try to do this when my repository is “clean”, i.e. when “git status” reports no changes. This is because icgitf I have changes, “git pull” will try to merge them for me, and I like to do that as infrequently as possible.

3)   Improve something.

With git, it’s best to work on one feature at a time, with the smallest features you can, to commit as often as makes sense. This way, in the future, you (and I) will have more fine grained control over the available versions.

4)   Double-check my changes.

I frequently run “git status” to see what files I’ve changed, and “git diff” to see the full patch for my current commit. Or “git diff <filename>” to see the patch for a specific file or folder. This lets me make sure I’m not checking in anything weird unintentionally.

5)   Commit my changes.

git commit -am "commit message goes here"

will stage and commit all your current changes and assign the commit message you specify. This command is a little dangerous, however, because 1. you’d better be sure you actually want to commit all your changes, and 2. it only includes changes for files it already knows about, not new files.

A safer process is to first:

git add <filename>

to stage changes for specific files or folders one at a time, followed by:

git commit -m ‘commit message goes here’

to commit your staged changes. If you’re feeling particularly reckless, you can do “git add .”, which stages all changes, period. Just don’t forget to commit them.

The only thing (the reckless) “git add .” won’t catch is deleted files. For that you can do “git add -u”. If you want to deal with deleted files manually, you can either use the “git add <filename>” syntax (which notices when a file or folder has been deleted… I think), or you can use “git rm <filename>” which works just like “git add <filename>” except it first tries to delete it for you.

6)   Push my changes to github.

git pull --rebase
git push

This first pulls in any changes that other people pushed while you were working, automatically merges them with your changes (“–rebase”), and then pushes your changes up to the github. Note that it’s perfectly fine to make more than one commit before pushing, if you aren’t ready. They can wait.

What if git can’t automatically merge my changes?

Git should let you know about this, and provide some instructions on what you need to do to proceed. If it gets scary, you should contact your lead developer for help.

But I don’t want to ever commit certain files?

There’s a file called “.gitignore” in the root of your repo which you can create or modify to cause git to exclude certain files from the repository, such as config/database.yml (which includes database credentials), or other files which might include sensitive information like API keys.

If you’ve already made a commit with a file that you shouldn’t have, you’re going to need to fix it before pushing. Ask your developer. If you’ve already pushed it, you definitely need to ask.

Oh #@!#$.
I $#@!ED something up.

Git is pretty resilient. Unless you’re jacking around inside the “.git” directory (in which case you probably need to start from scratch and run “git clone” again), or you’re forcing changes to commits that have already been pushed to github (using commands I haven’t taught you), everything is probably fine.

Here are some commands which could be helpful:

git checkout -- <filename>

Reverts a file to the version before you started the current change. i.e. obliterates your current changes for that file. Can’t be undone.

git reset HEAD <filename>

Unstages a staged change. (But doesn’t modify any files.)

git commit --amend

Lets you write a new commit message for your last commit. Don’t try this if the commit has already been pushed, though.

What are your favorite git commands you haven’t included yet?

git log
git log -p

Gives you a chronological listing of commit messages. “-p” gives you the commit messages with the commits’ patches. And you can include a filename to see only commits or patches including a specific file.

git blame <filename>

Gives you a breakdown of who changed which line of a file when. Useful for knowing who made a specific change.

git checkout <commit id>

If your repo is clean, this will let you switch to an earlier version of the project, which is great if I’m trying to figure out when and how and by whom a bug was introduced. Don’t forget to “git checkout master” to get back to where you were.

git stash

Temporarily reverts all your changes, so you can have a clean repo for a command like “git checkout <commit id>” which requires it. “git stash pop” to bring your changes back.

I’m scared

If, after reading this document, you’re feeling intimidated, you could copy a project of yours to a new folder, run “git init” in it, and experiment with the workflow I describe (sans “pull” and “push”). Your own private git sandbox.

Isn’t there a graphical user interface I can use instead?

Yeah, but it’s good to know what you’re doing on the command line first. I haven’t used any of the Git GUIs, so I can’t recommend one in particular. Do some googling, give it a shot, see if it works. But you’ll have a much easier and safer time with a GUI if you already understand the basics of staging, committing, pushing, pulling and merging.