Git Tips and Tricks

Last update: 05 Jul 2023 [History] [Edit]

Cheat Sheet

We have an ATLAS cheat sheet that gives the most important git commands and terms that we use in ATLAS code development. Keep this by your side!

Migrating from the old repository

On the 17th December 2018, ATLAS updated the Athena repository to make it public and open-source. If you are an ATLAS member and have forks or clones from before that date, please look at the instructions on the twiki

Useful aliases

A few useful aliases that you can add to your ~/.gitconfig:

[alias]
# Nicely formatted history
hist = log --pretty=format:'%h %ad | %s%d [%an]' --graph --date=short
lg =  log --graph --abbrev-commit --decorate --format=format:'%C(bold blue)%h%C(reset) - %C(bold green)(%ar)%C(reset) %C(white)%s%C(reset) %C(dim white)- %an%C(reset)%C(bold yellow)%d%C(reset)' --all
# Find/show merge request for commit on current branch (http://stackoverflow.com/q/8475448/)
find-merge = "!sh -c 'commit=$0 && branch=${1:-HEAD} && (git rev-list $commit..$branch --ancestry-path | cat -n; git rev-list $commit..$branch --first-parent | cat -n) | sort -k2 | uniq -f1 -d | sort -n | tail -1 | cut -f2'"
show-merge = "!sh -c 'merge=$(git find-merge $0 $1) && [ -n \"$merge\" ] && git show $merge'"
# Fetch an open MR
fetch-mr = "!sh -c 'git fetch $1 merge-requests/$2/head:mr-$2' -"

Useful environment variables

If you want to avoid switching between your source and build directories, you can tell git where your working directory and repository resides by setting:

export GIT_WORK_TREE=/path/to/my/git/repo
export GIT_DIR=${GIT_WORK_TREE}/.git

All git commands (e.g. git diff) will then operate as if you had executed them in your working directory even if your current directory is different. Note the above is a special case of using multiple work directories with the same git repository. For further details see Git Loves the Environment and git-worktree.

Diffing

A plain git diff -- PATH shows the difference of the currently checked out files against the copy that is staged (or last commit) for PATH. It is very common to diff against a commit ID or a tag and as ATLAS makes tags for each release it is easy to diff changes between the current version and a release tag:

git diff release/21.0.8 -- Tools/PyJobTransforms

To show the difference between two releases use:

git diff release/21.0.1..release/21.0.8 -- Tools/PyJobTransforms
git diff nightly/21.0/2017-05-05T2130..nightly/21.0/2017-05-06T2130 -- MagneticField

Use git diff --name-only to only show the file names that changed. GitLab also has web-based diff feature that can be useful for look at a limited number of changes, e.g. between two nightlies (it does not allow to filter on a PATH though).

git revisions --help gives more information on how to specify revisions:

  • HEAD has the obvious meaning
  • adding ^ means parent of, so HEAD^ means the commit before current HEAD
  • adding ~N means the Nth ancestor, so HEAD~10 means the 10th commit before HEAD
  • using the range specifier A..B is equivalent to A B in the above examples

Commit Logs

If you replace diff with log in the above commands, you will see the commits and their log messages.

git log   # from HEAD backwards
git log release/21.0.1..release/21.0.8 -- Tools/PyJobTransforms

There are many options controlling how much to show, e.g, --oneline or --pretty=format:... (see the examples above).

git show [commit id] shows both the commit log and the diff with respect to the previous version.

Cherry-picking merge requests

If you want to apply (“cherry-pick”) an entire merge request (which may consist of several commits), to your local branch use one of the following two options:

A) MR is already merged
git fetch upstream
git cherry-pick -m 1 HASH

where HASH is the merge commit hash that you can find on the GitLab MR page (e.g. 934a7995, click on the clipboard icon to copy/paste it):

B) MR is not merged yet

For each open MR, GitLab stores a special reference in the main repository under refs/merge-requests/MRID where MRID is the merge request ID (e.g. 42420). So you can simply fetch the branch from there (instead of having to add the developer’s fork as a remote):

git fetch upstream merge-requests/MRID/head:mr-MRID
git merge mr-MRID

Tip See the fetch-mr alias above as a convenient shortcut for the first command.

Interactive Rebasing

One of the most useful forms of rebasing, used for squashing commits and rewriting commit messages, is the interactive rebase. To do this run

git rebase -i HEAD~N

Where git will keep commit HEAD~N commit the same, but then rebase everything else from here up to HEAD; HEAD~N is the Nth ancestor of HEAD (be aware that if there are merge commits in the range you specify you might well get more commits included that you expect, git log --oneline HEAD~N..HEAD will help, but it is strongly discouraged to rebase across merge commits).

Now in your editor a page will open, showing every commit that will be part of the rebase along with what will happen to it (the default is pick meaning keep this commit as is) and the one line commit message.

Alert Do make sure that your EDITOR environment variable is set to an editor that you know how to use.

To merge a commit with its parent, change pick to squash (or just s); if you choose fixup instead then the commit message for the fixed-up commit will be discarded. In both cases you will have the chance to rewrite the commit message for the merged commit. To just rewrite a commit message change the command to reword. The descriptions of the other command options are pretty clear.

When you save and exit your editor git will execute each of the rebase commands in turn, producing a new commit history from the starting point.

A much more extensive discussion of these options is in the git tools documentation.

CMake Errors

If you get strange cmake errors e.g.

undefined reference to `pthread_create'

then it’s likely that you have:

testarea = <pwd>

in an .asetup file, and you also ran asetup inside the athena/ directory. You could remove testarea, delete the extraneous files (use git status to find what was added) and re-run. However we instead recommend running asetup in the top-level directory (i.e. the directory which contains athena/), as this means you don’t need to modify your configuration but also avoids asetup creating unnecessary local .asetup files.