I migrated my libraries to git, and GitHub, from Subversion over eight and a half years ago. While there is a bit of a learning curve to git, it is possible to handle basic operations fairly easily. The following is an overview of the basic features of git with some comparisons to Subversion. This basic overview completely omits many features of git; for more information check out the git docs.

Setup

It is useful to configure git with your name, email, and editor for all the projects that you will be using it for. For example, the following is my setup for git:

$ git config --global user.name "Michael Galloy"
$ git config --global user.email mgalloy@gmail.com
$ git config --global core.editor "emacs -nw"
$ git config --global core.autocrlf input

You can also do configurations per project. For example, in the case you have a project where you interact with a remote repository where you have a different account name.

Create a new repo

If you have a directory (with possible subdirectories) that you would like to turn into a git repo, use init from the directory:

$ git init

This is a major advantage of git over Subversion: you can very quickly turn any directory into a git repository and start working.

Use clone to make your own local copy of an existing repo, e.g., a repo created on GitHub. For example, the following command will grab the mglib GitHub repo and make a local copy:

$ git clone https://github.com/mgalloy/mglib.git

This is analogous to a Subversion checkout.

Add files and commit them

If you are familiar with Subversion or other version control systems, this is similar. We need to tell git to track a particular file with the add subcommand, then use commit to indicate that you want to save the current contents:

$ git add <filename>
$ git commit

There are several differences with Subversion at this stage though:

  1. The changes are only saved locally, not pushed to a centralized repository (see next section about communicating with a remote repository).
  2. It is necessary to “stage” files with the add subcommand before every commit, not just the first time.

The status subcommand is useful to check which the state of the files in repo:

$ git status

Push/pull to/from another repository

If you cloned from a remote repository, then you have a remote called “origin”. You can push commits from your local repository to this remote repository with the following:

$ git push origin master

The “master” refers to the default branch. Similarly, you can retrieve new commits from origin by pulling:

$ git pull origin master

Look at your history

The log subcommand gives the history of your commits:

$ git log
commit cac05188a6997d4dc8febd7363d706768cd8cd16
Author: Michael Galloy <mgalloy@gmail.com>
Date:   Mon Aug 25 18:40:50 2014 -0600

    Doing total to find contrast.

commit 4bb170a6a57e53a87b1a5dd4db3ed31774f977af
Author: Michael Galloy <mgalloy@gmail.com>
Date:   Mon Aug 25 17:51:22 2014 -0600

    Adding example in main-level to compute contrast from GLCM.

Sometimes, I like using a few options to get a history that is easier to glance down through many changes:

$ git log --color --pretty=oneline --abbrev-commit
cac0518 Doing total to find contrast.
4bb170a Adding example in main-level to compute contrast from GLCM.

Note that git commits are referenced by a long hash value, not an incrementing integer value. Because of the distributed nature of git, it would not be possible to keep a simple incrementing counter. The first seven digits of the hash are usually all that is needed to reference a commit.

See your changes

The diff subcommand shows differences between items. To see the changes that have not been added yet do:

$ git diff

To see the changes just for a single filename, do:

$ git diff <filename>

To see the changes between two commits, do:

$ git diff <hash1> <hash2>

Undo a change

One of the main features of version control is to be able to revert changes and to retrieve old versions of code. There are multiple commands to revert, depending on the stage of the code that is being reverted.

For example, to destroy the changes to a file that has not been added or commited, you can just checkout a fresh copy of it:

$ git checkout -- <filename>

To “visit” the repo at the state it was on a specific commit, do:

$ git checkout <hash>

To make a new commit that undoes existing commits (like a version control inverse function), use the reset subcommand. The first few characters of a hash found from the log subcommand are needed to refer to commits, though there is special notation for the most current commit HEAD and back n commits HEAD~n. So to create a new commit that reverts the last two commits, you can do:

$ git revert HEAD~2..HEAD

To create a new commit that reverts the commits from 0123456 to the HEAD, do:

$ git revert 0123456..HEAD

It is also possible to actually delete commits using the reset subcommand, either “soft” or “hard”. This can be problematic if the commit has been pushed to a remote; it is much simpler if the commit hasn’t been pushed yet.

For example, to delete the last commit, keeping the state of the repo as it was just before the commit, i.e., the code changes are still present:

$ git reset --soft HEAD~1

To really delete the commit and its changes fully, do:

$ git reset --hard HEAD~1

Branching and merging

Branching and merging are fundamental to using git effectively. Branching is useful because there are usually multiple versions of the code that are progressing at the same time. For example, you might create a branch for a specific feature so that large changes can be made without breaking the main branch. Or a branch for a release might be made so that quick fixes for the release can be made as well as progressing along for the next release.

To create a branch named “geometry”, do:

$ git branch geometry

That will create the branch, but you will still be on the default “master” branch. To change to the “geometry” branch, do:

$ git checkout geometry

After doing commits on this branch, when it is time to merge the changes back into the “master” branch, use the merge subcommand:

$ git checkout master
$ git merge geometry

There can be conflicts in a merge, if both branches have made changes. In that case, the merge will indicate the issues. Fix the conflicts and do an add/commit. Use git status to find the remaining conflicts.

If you are done with the geometry branch now, you can delete it with:

$ git branch -d geometry