Git Notes

Notes on Using Git

C. David Sherrill
School of Chemistry and Biochemistry
Georgia Institute of Technology

These notes introduce some basic git commands and operations. They assume you are working off private or locally shared repositories. They do not cover community development, like with GitHub.

Recommended book: Pragmatic Version Control Using Git, Travis Swicegood (The Pragmatic Bookshelf, Raleigh, 2010)

To make a repository for your own (non-shared) use:

  • cd into the project directory
  • git init
This will make a local repository and store it in a .git subdirectory. That's all there is to it! Migrating your repository to another computer is as simple as copying the working directory (and its included .git subdirectory) where you want it to go.

To make a shared repository for use by a group:
I have some separate notes on this

To clone a local repository:

  • git clone other-repository-location proj-dir
This will make a clone of the remote repository and put it in a local directory called proj-dir.

To clone a remote repository:

  • git clone username@machine://remote-repository proj-dir
where username@machine specifies an SSH login to a remote machine. With certain services like GitHub, it is also possible to clone via http.

To add a new file to the repository:

  • git add [filename]
and then check it in with
  • git commit -m "log message"
If you have a large number of changed files, and you want to review them one by one, you can enter the "interactive" mode of git add by typing
  • git add -i
If you made many changes to a file, you might need more information than just the list of changed files. You can look at diffs with the diff command within git add -i, or via git diff. Alternatively, you can review the individual changes at staging time, and even selectively apply some and leave others unstaged, by using
  • git add -p
which enters "patch" mode (one change at a time). (You can also look at patches from within git add -i using the "patch" option in the interactive menu.)

Checking in changes: This requires two steps: (1) staging the change, and (2) committing the change.

  • git add [filename]
  • git commit -m "log message"
A shortcut to the above procedure is
  • git commit -m "log message" filename
To automatically stage all changed files and commit the changes,
  • git commit -a -m "log message"
Note: git add filename will stage a commit of the changes to the given file at the time of the git add command. If you change the file again, you need to do git add again to stage the latest change.

To check on the status of the working copy:

  • git status
This will list files that are modified, staged for chekin, etc.

Get changes from repository:

  • git pull [remote-repository] [remote-branch-to-pull]
where remote-branch-to-pull does not include the origin/ prefix. This fetches and merges changes from the remote repository into the local repository. Alternatively, one can also do
  • git fetch
This downloads branches from the remote repository, not only for your current working branch, but for any other branches located at the remote repository. The changes to the current branch are not automatically merged into your current working copy. Not as commonly used as git pull.

Communicate local changes to remote repository:

  • git push [--dry-run] [remote-repository] [refspec]
pushes committed changes from the local repository to the remote repository. The --dry-run option shows you what changes would be pushed. refspec is a tag, branch, or keyword like HEAD; e.g., mybranch:master pushes changes from mybranch to the remote master branch. The default remote repository is named origin.

To see what's been changed in a file:

  • git diff
shows what changes in the working tree have not yet been staged or committed. To see the differences between changes that are staged and what's in the repository,
  • git diff --cached
To see differences between the working directory AND what's staged vs the repository,
  • git diff HEAD
To see differences between the working tree and a previous revision,
  • git diff [revision-id]
To get a summary of how often files have changed since a revision or tag,
  • git diff --stat [tagname or revision-id]

To get a summary of recent committed changes,

  • git log [-n] [--pretty=oneline]
will print the last n log entries. To view the diffs that a revision created, use
  • git log -p
To view the log starting from a given revision, give the revision number (just enough characters, like 7, to be unique) as an argument:
  • git log [revision-id]
To view recent changes happening in the last certain timeframe,
  • git log --since="7 hours"
where instead of "7 hours" you can put "1 day" or "2009-12-01", etc. To get a list of changes from a particular commit or tag until now, and in a short summary format,
  • git log --pretty-format:"%h %s" 1.0..HEAD
You can also use the ^ character to mean the revision before a given revision. 6f1bf6f^^ is the revision two revisions before 6f1bf6f.

To see who changed a particular file: so you know whom to blame for an error,

  • git blame filename
To see who changed line 208 or the following 5 lines in filename,
  • git blame -L 208,+5 filename
You can also search text instead of linenumbers using regular expressions
  • git blame -L "regexp",+5 filename

To remove a file from the repository:

  • git rm filename
  • git commit -m "log message"

To move a file:

  • git mv oldname newname
  • git commit -m "log message"

To tell git to ignore some files in a working directory:
Sometimes you'll have files, like vi swap files with names like .file.swp, that you don't want git to worry about. This is easy to fix, just add the relevant filenames or wildcard filenames (like *.swp) to the file .gitignore. Alternatively, if this is a personal preference appropriate to a particular developer, and maybe not appropriate to adding to a shared repository, exclusions like this can be added to the local .git/info/exclude file.

To create a branch:

  • git branch new-branch-name branch-to-create-from
where branch-to-create-from is a branch name or tag (often branch "master"). If the final parameter is not present, git will assume you want to create a branch off of the current working branch. Note that creating a new branch does NOT automatically switch the working copy to that branch. Use git checkout to do that. A shortcut to avoid having to do that is
  • git checkout -b new-branch-name branch-to-create-from
This will create a new branch and check it out in one step.

To switch the working copy to a different branch:

  • git checkout branch-name
Warning: you can lose unsaved changes when doing this!

To see a list of all available local branches:

  • git branch
The name of the current working branch will be marked by a *

To see a list of all available remote branches:

  • git branch -r
This lists branches in the remote repository. These branches can be checked out, but they should not be changed. If you want to change them, create a local branch from them first, and then make the change. The remote branches will be named with an origin/ prefix to keep them distinct from local branches.

To rename a branch:

  • git branch -m oldname newname

Rebasing: to apply changes from one branch to some other branch: First, figure out what branch you want to absorb changes from another branch (usually, master). Assuming the other branch is already up-to-date and checked in, switch to the branch you want to absorb the changes:

  • git checkout master
Now, apply changes from the other branch on top of the current one:
  • git rebase other-branch-name
That should do it. If you're done with the other branch once it's absorbed back into the master branch, you can delete it with
  • git branch -d other-branch-name

Resolving merge conflicts:
Sometimes you might get a conflict when trying to do the merge. In such a case, the file(s) with the conflict will have the standard "conflict markers." The beginning of the conflict region will be marked with "<<<<" symbols and the name of the current branch and file. That version of the file will continue until another marker of "======" symbols. Then, the conflicting version of the text will appear until closed off by ">>>>" symbols and the name of the conflicting branch and filename. Multiple areas of conflicting text might appear in a single file. Edit the file by hand to resolve the conflict. Make sure you delete the conflict marker lines beginning with ">>>", "<<<", or "===". We don't want those checked in. Once the file is the way it's supposed to be, git add the conflicted file and do a git commit. In this particular case, if you leave off a log message, git will automatically create one specifying that it's related to a merge.

Squashed commits:
If you had to experiment quite a bit in an alternate branch before getting something right, you might not want to commit all the individual changes, but just the final changes in the alternate branch relative to the main branch. In a case like this, finish checking in any changes on the alternate branch, check out the master branch

  • git checkout master
merge all the changes from the alternate branch in squashed form,
  • git merge --squash alternate-branch
note that squashed merges DO NOT update the master branch repository yet. They must be committed with
  • git commit -m "log message"

Cherry-picking merges:
If you want to merge in just one change from another branch, you can use the fact that commit identifiers are unique across the entire repository to select the commit you want to merge. Get the commit ID by noting it after it's printed in git commit, or from the log file (you don't need the entire ID number from the logfile, the first 7 characters or so should do it). Then, switch to the branch you want to merge changes into, like

  • git checkout master
Finally,
  • git cherry-pick [commit-id]
  • git commit -m "message"
To cherry-pick multiple commits, do
  • git cherry-pick -n [commit-id-1]
  • git cherry-pick -n [commit-id-2]
  • ...
  • git commit -m "message"
Note: cherry-pick does the merges but needs to be followed up by a commit.

Tags:
you can tag a specific point in the repository by

  • git tag tag-name branch-name
You can view a list of all the tags in the repository by running
  • git tag
with no argments.

Multi-paragraph commit messages: can be specified by multiple -m "message" arguments to git commit

To create a gzip archive of the project as of some specific tag:

  • git archive --format=tar \
    --prefix=proj-dir tagname \
    | gzip > proj-dir.tar.gz
where proj-dir is the name of the directory for the working copy, and tagname is the name of a tag for the version you want to archive.

Reverting a commit:
To undo the latest commit, do

  • git revert
To undo multiple previous commits, stage them before committing with the -n flag:
  • git revert -n [commit-id, or HEAD for most recent]
  • git revert -n [other-commit-id]
  • ...
Revert the most recent commit first, then the earlier commits, in order. Finally,
  • git commit -m "revert [commit-id1] and [commit-id2]"
If you don't give -m, git will make an automatic revert log message for you.

Resetting the repository:
If we really did something terrible (like checked in a private password file), we can reset the whole repository to its state at some given point

  • get reset [commit-id]
[commit-id] defaults to HEAD, the previous version. the flag --soft allows you to stage the previous commits but not commit them. The --hard option removes the commit from the repository and from the working tree.