My Git Cheatsheet

I’ve used Git for many years but it still trips me up. At times I’ve worked primarily in a GUI (like Sourcetree or Fork), and other times directly on the command line. I’ve worked on projects where I’ve been the sole developer and others where I’m part of a large team. Regardless of the tools or context, I’ve learned there are certain need-to-knows. Here’s a list of useful Git concepts and commands for my reference and yours.

Note: the following is not an exhaustive list but rather the thing I keep coming back to and/or regularly forget. For deeper explanations, see the list of resources at the foot of the article.

Starting work #

Create a remotely-hosted repo #

Option 1: Create a new repo in your Github account

This generates a new, empty repo (optionally initialised with a README).

Do this when you will be working on a new, dedicated project rather than contributing changes to a pre-existing one.

Option 2: Create repo from a “template repository” (owned by you or someone else)

This generates a new repo with the same directory structure and files as the template. It’s a good option for starting your own new, potentially long-lived project from a solid starting point.

Unlike a fork it does not include the entire commit history of the parent repository. Instead it starts with a single commit.

Github Reference: Creating a repository from a template

Option 3: Fork an existing repo (usually owned by someone else)

This generates a new repo which is a copy of another repo, including its commit history. Your commits will update your copy rather than the original repo.

Do this by clicking the Fork button in the header of a repository.

This is good for (often short-lived) collaboration on an existing repo. You can contribute code to someone else’s project, via PRs.

Github Reference: Working with forks

Start locally by cloning #

clone creates a local copy on your computer of a remote (Github-hosted) repo.

cd projects
git clone https://github.com/githubusername/projectname.git optionallocaldirectoryname

You might be cloning a repo you own, or one owned by someone else (to use its features in your project).

Your local copy will, by default, have its origin remote set to the Github repo you cloned.

I cloned an empty new project

We’re in easy streets. The default remote is set exactly as you want it. Just write code, push at your leisure, and pull if/when you need to.

I cloned a pre-existing project (owned by me or someone else):
I plan to use it in my own, separate project

You might want to cut all ties and have a clean slate, git-wise.

rm -rf .git
git init
git remote add origin https://github.com/mygithubusername/mynewproject.git
git push -u origin master

Alternatively you might want to keep the original remote available so you can pull in its future project updates, but reset the origin remote to your new/target repo.

git remote rename origin upstream
git push origin master
git pull origin master
# in the future the original repo gets an update
git pull upstream master
The source repo is my fork of a project to which I want to contribute

See Working with forks for how best to stay in sync and open PRs.

Duplicating (also knows as “duplicate without forking”)

This is a special type of clone. I know this is an option, but it‘s not one I’m familiar with or have had call to use. I can refer to Duplicating a repository if need be.

Start locally from a blank slate #

Although cloning is the easiest way to get started locally, ocassionally I start by coding from scratch instead.

mkdir myproject && cd myproject
echo "# Welcome to My Project Repo" >> README.md
git init
git add README.md
git commit -m "first commit"

# go to Github and create an empty repo, if you haven’t already.
# then add as a remote
git remote add origin https://github.com/mygitusername/myproject.git

# push up, passing -u to set the remote branch as the default upstream branch our local branch will track
# this saves typing out ‘origin master’ repeatedly in future.
git push -u origin master

Remotes #

Remove a remote from your local settings:

git remote rm <name>

Rename a remote:

git remote rename oldname newname

Configuration #

Configure your favourite editor to be used for commit messages:

git config --global core.editor "nano"

Use git st as a shortcut for git status (to stop me mistyping as “statsu”):

git config --global alias.st status

Configure any setting:

git config [--global] <key> <value>

Staging, unstaging and deleting files #

# stage all unstaged files
git add .

# stage individual file/s
git add filename.txt

Unstage with reset (the opposite of git add):

# unstage all staged files
git reset .

# unstage individual file/s
git reset filename.txt

Delete a physical file and stage the deletion for the next commit:

git rm folder/filename.txt

Committing updates #

Commit with a multi-line message:

git commit

Commit with short message:

git commit -m "fix: typo in heading"

Stage and commit all changes in a single command (note: doesn’t work with new, untracked files):

git commit -am "fix: typo in heading"

Branches #

Show all local branches:

git branch

Show all local and remote branches:

git branch -a

Save current state to new branch but don’t yet switch to it (useful after committing to wrong branch):

git branch newbranchname

Create and switch to new branch:

git checkout -b mynewbranch

Switch to an existing branch:

git checkout branchname

Save typing by setting the upstream remote branch for your local branch:

# git branch -u remotename/branchname
git branch -u fuzzylogic/v3

# now there’s no need to type origin master
git pull

Staying current and compatible #

fetch remote branch and merge simultaneously:

git pull remotename branchname

# common use case is to update our local copy of master
git pull origin master

# shorthand when a default upstream branch has been set
git pull

# an alternative is to update (fetch) which does not auto-merge, then 'reset' to the latest commit on the remote
# https://stackoverflow.com/questions/55731891/effects-of-git-remote-update-origin-prune-on-local-changes
git checkout master
git remote update --prune
git reset --hard origin/master

Merge another branch (e.g. master) into current branch:

git merge otherbranch

# a common requirement is to merge in master
git merge master

Rebasing #

git rebase can be used as:

  1. an alternative to merge; and
  2. a means of tidying up our recent commits.

As an alternative to merge its main pro is that it leads to a more linear therefore easier-to-read history. Note however that it is potentially more disruptive therefore not right for every situation.

Say I’ve been working on a feature branch and I think it’s ready.

I might want to just tidy up my feature branch’s commits and can do this with an “interactive rebase”. This technique allows me to tidy my feature branch work to remove trivial, exploratory and generally less relevant commits so as to keep the commit history clean.

I might also want to bring in master to ensure synchronicity and compatibility. rebase sets the head of my feature branch to the head of master then adds my feature branch’s commits on top.

While it’s a good idea to rebase before making a PR, don’t use it after making a PR because from that point on the branch is public and rebasing a public branch can cause problems for collaborators on the branch. (The only exception to the previous rule is if you’re likely to be the only person working on the PR branch)

Rebuild your feature branch’s changes on top of master:

git checkout master
git pull origin master
git checkout myfeaturebranch
git rebase master

Force push your rebased branch (again, only when you’re unlikely to have/require collaborators on the PR):

git push --force origin myfeaturebranch

Tidy a feature branch before making a PR:

git checkout myfeaturebranch
git rebase -i master

# just tidy the last few (e.g. 3) commits
git rebase -i HEAD~3

# this opens a text editor listing all commits due to be moved, e.g.:
pick 33d5b7a Message for commit #1
pick 9480b3d Message for commit #2
pick 5c67e61 Message for commit #3

# change 'pick' to ‘fixup’ to condense commits, say if #2 was just a small fix to #1
pick 33d5b7a Message for commit #1
fixup 9480b3d Message for commit #2
pick 5c67e61 Message for commit #3

Undo a rebase:

git reset --hard ORIG_HEAD

For more detail, read Atlassian’s guide to rebasing.

Reviewing #

Show commit history (most recent first; q to quit):

git log

# compact version
git log --oneline

# limit scope to commits on a branch
git log branchname

Check if your feature branch is trailing behind:

# show commits in master that are not yet in my feature branch
git log --oneline my-feature..master

# show commits on remote branch that are not yet in my local branch
git log --pretty='format:%h - %an: %s' new-homepage..origin/new-homepage

# show commits by me that included “heroku” and that changed file Gemfile
git log --author=Demaree --grep=heroku --oneline Gemfile

Review differences between staged changes and last commit:

git diff --cached

Review changes between a given version/commit and the latest:

git diff 591672e..master

Fixing Things #

Undo all the changes in a given commit:

git revert 591672e

Alter the previous commit (change the message and/or include further updates):

# we are amending the previous commit rather than creating a new commit.
# if file changes are staged, it amends previous commit to include those.
# if there are no staged changes, it lets us amend the previous commit’s message only.
git commit --amend

Move current branch tip backward to a given commit, reset the staging area to match, but leave the working directory alone:

git reset 591672e

# additionally reset the working directory to match the given commit
git reset --hard 591672e

See what the app/site was like (e.g. whether things worked or were broken) at a given previous commit, noting the following:

  • You’re now “detatched”, in that your computer’s HEAD is pointing at a commit rather than a branch.
  • You’re expected to merely review, not to make commits. Any commits you make would be “homeless”, since commits are supposed to go in branches. (However you could then branch off.)
git checkout 591672e

Grab one or more commits from elsewhere and drop into your current branch:

git cherry-pick 591672e

# grab the last commit from a branch e.g. master
git cherry-pick master

Fix a pull that went wrong / shouldn’t have been done:

git pull origin branchname
# whoops!

git reflog
# shows a list of every thing you've
# done in git, across all branches!
# each one has an index HEAD@{index}
# find the one before you broke everything

git reset HEAD@{index}
# magic time machine

Useful external resources #

External Link Bookmark Note Entry Search