Git Cheatsheet

Posted by Christian Jung on Wed, Apr 14, 2021

Getting started with git

This is just a list of useful commands and practices I learned over time while using git.

Basic git workflow

The following chapters are the simple commands to get you started.

Clone a repository

Create a local clone:

1git clone URI

Git supports different protocols, typically you use one of the below:

1# clone for GitLab, GitHub etc. via HTTPS
2git clone https://github.com/ansible/ansible.git
3# if you want to commit to a repo, it is often more efficient to use SSH
4git clone git@github.com:ansible/ansible.git

Edit locally

When you work in your local repository:

 1# review current status
 2git status
 3# after editing a file, save and commit
 4git add path/to/file
 5git commit -m "implemented new feature A"
 6# you can combine the two previous commands if you only modified an existing file
 7git commit -m "fixed bug #123 by verifying input data" -a
 8# delete a file from the repository
 9git rm path/to/file
10# and commit the change
11git commit -m "delete path/to/file since it's obsolete"

This was only saving your change locally and did not (yet) push it to your remote! You can do many changes without pushing to your remote, depending on your work style and collaboration mode.

Commit messages

Some people get annoyed about the fact that git commit asks them for a commit message every time and start using messages like “minor change”, “fix”, “updated README”. It’s natural and understandable that people get annoyed and feel forced to write messages. It feels interrupting and you just want to get things done and don’t to waste time thinking about good commit messages.

Commit messages should be short and precise. They should describe the change in as few words as possible. If you ever try to go back in your git log to find a certain change and you can only see “minor fix”, it can become incredible hard to find the commit you’re looking for. So do your future self a favor, pause a second and write something useful.

  • describe the change: why was it needed? what was the problem you try to fix?

  • be as short as possible, no need for epic descriptions

  • no redundant information, e.g. the commit already contains the information about which file was modified, there is typically no need to repeat that in the commit message (no “updated README”)

Pull updates and push changes

Until now, you only worked on your local repository - typically you want to interact with a remote server like GitLab, GitHub or others, for collaboration.

1# only fetch latest changes, but do not merge them!
2git fetch
3# get all changes in all remote branches - particularly helpful if you want to see what others changed in their branches - but does not merge them!
4git fetch --all
5# get latest changes from remote and merge them locally
6git pull
7# push changes to remote
8git push

Note: If the remote has a newer version of the branch than your local repository, a git push will give you an error message. In this case run git pull again to fetch and merge the latest changes from the remote repository.

Review changes

Git keeps all commits and you can review them with git log. You can also see more details:

 1# history of all changes
 2git log
 3# git more details about a specific commit
 4git show <commit>
 5# show differences
 6git diff <commit>
 7# roll back previous change
 8git checkout <commit>
 9# switch back to last commit
10git checkout HEAD

Create your own repository

I recommend to always use git - even if you’re not sure yet you want to keep your work. Creating a git repository is just one simple command and therefore comes with very little cost:

1# create a work directory
2mkdir my_new_project && cd my_new_project
3# initialize repository
4git init
5# you're done! You just created a git repository!

Now you can do local edits, revert changes, do diffs and when you’re done, add a remote repository later. If you realize it was all in vain, you can just delete the entire directory.

Remote Repositories

Since git is a decentralized software management tool you can add and remove remote repositories at any point in time and you can use multiple remotes as well.

1# add a new repository
2git remote add <name> <URI>
3# get a list of all remotes currently configured
4git remote -v
5# remove a remote repository
6git remote remove <name>

All git commands like pull, push, diff etc. support different remotes, so you can easily compare their different states and decide where to pull or push changes to/from. I find it difficult at times to work with too many remotes, and seem to get lost in what’s where, so I would personally suggest not to stress this concept too much…

Working with branches

Git loves branches. It’s always a good idea to create a new branch before you implement a new feature (remember the old days when you created script-v1.sh, script-v2.sh, script-20200802.sh and lost track which script has which change?).

 1# create a new branch from the current one
 2git checkout -b <new branch>
 3# switch between branches
 4git checkout <old branch>
 5# get a list of branches
 6git branch
 7# add -a to see also remote branches
 8git branch -a
 9# or add -v for more details
10git branch -v
11# or combine them
12git branch -av

Stashing

Sometimes you have a local change which you want to keep but not yet commit. Or you accidentally started to work in the wrong branch. Instead of copying your local changes to /tmp or similar hacks, you can use git stash.

1# stash local changes without committing them
2git stash
3# switch to the branch you actually wanted to apply the change
4git checkout <branch>
5# apply the stashed changes again
6git stash apply
7# note until this point everything just happened in your working directory and nothing was committed or pushed

You can also work with different stashes by assigning names, check git stash -h for more details.

Diff branches

Sometimes there are many changes you need to identify them. I find it useful to do the following list of commands:

1# differences between branches
2git diff <branch>
3# sometimes the reversed output is more useful
4git diff -R >branch>
5# just find the list of modified files
6git diff -R <branch> --name-only

Merging branches

After you finished your work in the new branch, you want to merge it back to master (or any other branch).

1# switch to the target branch, e.g. master
2git checkout master
3# merge changes from the other branch
4git merge <branch>
5# sometimes you want to review changes and apply them individually, this will use the editor specified in the EDITOR environment variable if you want to edit the changes
6git checkout -p <branch>
7# merge a specific file from the other branch
8git checkout <branch> -- path/to/file

Solving conflicts

When merging branches conflicts often occur. While git is quite clever in solving many of them automatically, you will still have some which will require manual fixes.

1# merge with master or other branch
2git merge <branch>
3# assume a conflict happens, solve it with your favorite editor
4vi file/with/conflict
5# add the files to your next commit
6git add files/with/conflict
7git commit -m "solving conflict" # or other meaningful commit message

Delete and cleanup

After your work is complete and has been merged, you can delete the local branch.

1git branch -d <branch>
2# or, if there are uncommitted changes you don't want to keep
3git branch -D <branch>
4# if you need to delete the branch on a remote repository, you can do that as well
5# this examples assumes your remote is called "origin"
6git push origin -d <branch>

Use check the chapter Cleaning your local directory.

Pull or Merge Requests

Git makes it easy to work with branches to keep track of new features, bug fixes, releases etc. To simplify collaboration in projects Merge Requests (GitLab) and Pull Requests (GitHub) can be used. These are not features of git, but capabilities provided by the respective platform. Specially when you’re new to git it can be difficult to differentiate between pure git functionality and these additional features.

Typical workflow

Merge or Pull Requests are a good way to collaborate on new features or code changes. My typical workflow looks like this:

  • make sure your local repository is up to date by running git pull first

  • create a local branch to start development (git checkout -b <new branch>)

  • make your changes, commit them and continue the typical workflow as described in basic git workflow

  • push the local branch to the remote (git push, doing this the first time, you will probably see a message the remote branch does not yet exist and how you fix that, e.g. git push -u origin local-branch)

  • you will see a link which will create the Merge or Pull Request - you can also navigate to the Web UI and create it from there

  • fill out the details, mark it as a draft or WIP (Work in Progress) - this will make sure nobody “accidentally” merges the branch until it’s ready

  • continue working on your branch (you can still push new changes to the same PR/MR, no need to delete it and create a new one!)

  • when you feel it’s ready, remove the draft or WIP flag

  • collaborate and discuss the proposed changes with your peers, push additional changes when needed

  • merge the changes

  • delete the branch created for this MR/PR

Merge from master

When working with MR/PR your branch might fall behind and new changes from master need to be merged into your branch:

 1# make sure master is up to date and optionally review changes
 2git checkout master
 3git pull
 4# switch back to your branch
 5git checkout <branch>
 6# and merge all changes from master
 7git merge <master>
 8# or, review them while merging
 9git checkout -p master
10# pull and merge in one command
11git pull <remote> <branch>
12# push your merged branch
13git push

Clean up merged branches

If you create a lot of branches to work on changes, you probably want to clean them up, after they got merged.

 1# clean orphaned remote branches
 2git remote prune <remote>
 3# find local branches which no longer exist on the remote
 4git branch -v
 5# delete those local branches which no longer exist on the remote
 6git branch -d <branch>
 7# if the branch was not fully merged and you know what you're doing
 8git branch -D <branch>
 9# you can do this in one command
10git branch -d `git branch -vv | grep gone | cut -f3 -d' '`

User Experience

In this section I’m listing some tweaks I learned which make git easier to use.

Aliases

Unlike some other tools, git doesn’t allow you to shorten commands. For example, in svn you were allowed to shorten commands like “cummit” to “ci”. I got used to that and defined some aliases which bring back this comfort.

Create or edit your ~/.gitconfig configuration file like this:

1[alias]
2        co = checkout
3        br = branch
4        ci = commit
5        st = status
6        pr = remote prune origin

After saving these changes you can type git ci instead of git commit - the rest of the command line remains the same.

1git ci -m "commit a change"
2# is the same as
3git commit -m "commit a change"
4# this works with longer aliases as well
5git pr
6# is the same as
7git remote prune origin

Pipelines

A very powerful feature which builds on top of SCM are pipelines. In GitLab CI/CD has been integrated for a long time and GitHub recently introduced the concept of Actions. There are many other tools like Jenkins, Travis etc.

There are a few articles on CI/CD on this blog as well.