Git commits code in two phases:
$ cd ../athena $ git status # Always a good idea to see where you are... branch master-my-topic Changes not staged for commit: (use "git add <file>..." to update what will be committed) (use "git checkout -- <file>..." to discard changes in working directory) modified: python/trfArgClasses.py modified: python/trfExe.py no changes added to commit (use "git add" and/or "git commit -a") $ git diff # ...and what you changed
$ git add python/trfArgClasses.py python/trfExe.py $ git status On branch master-my-topic Changes to be committed: (use "git reset HEAD <file>..." to unstage) modified: python/trfArgClasses.py modified: python/trfExe.py
$ git commit ... # Editor should open and you write a commit message # see next section...
git add can take wildcards and it’s possible to add
all changed files and new files automatically
git add -A, but be very careful not to add
unwanted files to the repository. Definitely use
git status to check what will be/had been staged.
git status also helpfully tells you what to do if
you want to rollback changes to a file or unstage
git resetwill unstage changes for you if you did an
addof something in error.
git checkout FILEwill revert
FILEto the original version.
git reset --hardwill unstage and discard all local changes.
git statusis your friend - consult it often!
Commit messages should be informative yet concise.
It is suggested that you write a short one line explanation,
followed by a blank line, then some additional longer paragraphs
explaining the patch. Use less than 72 characters per line -
commit logs get read at the terminal. Reference any
bugs you are fixing in the usual Jira notation (e.g.,
and GitLab will post a comment on the Jira ticket, which is
useful in correlating a bug with its fix.
The Linux kernel recommendations state:
For these reasons, the “summary” must be no more than 70-75 characters, and it must describe both what the patch changes, as well as why the patch might be necessary. It is challenging to be both succinct and descriptive, but that is what a well-written summary should do.
Further guidelines are in How to Write a Git Commit Message and 5 Useful Tips For A Better Commit Message.
An example of a good commit message would be:
FooTool: Fixed uninitialised value and leak in alignment tool It was possible to have the m_alignmentOffset variable uninitialised in certain situations outlined in Jira. This patch corrects for that and changes the behaviour to return StatusCode::FAILURE immediately if the setup is inconsistent at initialise. The memory leak from failing to delete the pointer returned from the foo tool was fixed. Fixes ATLASRECTS-98765.
The first line should start with a topic prefix that gives an indication where changes were made. This could e.g. be a reconstruction domain, package name or algorithm name depending on the size and scope of changes. The commit message should say why something was changed, not what was changed (so it’s not necessary to list changes by filename).
With git it’s extremely easy to see the code changes alongside the commit message:
$ git log --oneline path/to/mypackage # List only commits # that changed this path ... # Identify the COMMIT_ID you are interested in $ git show COMMIT_ID
ATLAS does not use
ChangeLogfiles anymore. The commit message is the new change log. This is why it’s really important that you write it well. If you make a mistake use
git commit --amend
to edit it before you push anything. Software review shifters will be instructed to reject merges with bad commit messages.
Of course while you are developing, the branch you intend to push
your changes to is probably changing too (and it will certainly
be changing, if
master is your target).
For long-lived developments it is a good idea to periodically update your development branch. This will avoid unpleasant surprises when you open a MR (and you should certainly do this before running your tests, to make sure you are testing against the version of the codebase you intend to merge into).
There are two mains ways to do this, merge and rebase. Broadly speaking merge is safer (especially if you are new to git), but it has some definite downsides: each time you merge from the remote branch, a merge commit is added to your git history. These merge commits will clutter the history, which is something we don’t want to do: the commit history of atlas/athena should be clean, with each commit having a well-written commit message and a well-defined purpose. By default, we squash all commits from MRs, so if you have a bunch of debugging commits and merge commits, they will vanish - replaced by one commit in atlas/athena when your MR is accepted (see this link for more about squashing). Unfortunately however, the very existence of merge commits can make an automatic squash fail. The more merge commits you have in your history, the more likely this becomes.
An alternative is to rebase your commits. Rebasing can be dangerous because you are altering history - you are actually changing the commit hashes of your code changes. You should never violate the Golden Rule of Rebasing - never rebase a branch which is shared with other people (which is public, in other words). However as long as you are working on a local branch, or a branch which only you are touching on your fork, then rebasing is a very good strategy to use.
To rebase, the procedure is:
git fetch upstream # get latest version from GitLab git rebase upstream/master # replay your local changes on top of that git push [--force] origin # push our branch
Hopefully this just works - if you have conflicts, then you will need to handle them as shown in Resolving Conflicts. The
--force push is needed in case your branch had already been pushed to GitLab before
There is one other very powerful use of rebasing, which is to clean your commits before opening a MR. Often, when developing you might add some debugging tests, or make some missteps you have to correct. This can lead to a convoluted history, which should not end up in the main repository. One option is, as discussed, to squash the commits into one single commit. For simple developments, this might well be best.
However for more complicated MRs, you might want to have several commits, to make the history more understandable, and to make it possible to cherry-pick or revert part of you MR in the future.
For example, you might want to clean the following cluttered and messy history:
To something appropriate to share with the rest of ATLAS:
To do this, you can do an interactive rebase which allows you to squash several commits into one, rewrite commit messages, drop unneeded commits, etc. See interactive rebasing or the Atlassian documentation. Or, if you use our recommeneded IDE, Visual Studio Code, you can install a plugin GitLens which makes this (and many other git operations) a lot easier:
Here is what the GitLens GUI looks like for the example above. You start with a representation of the current history:
You can then choose what to do with each commit (pick, reword, edit, squash, drop), and can drag them around to change their order. For example, this is what we chose to clean the messy history above:
Once your development is finished and tested, copy it from your local repository back to your GitLab fork:
git push --set-upstream origin master-my-topic
--set-upstream (or just
-u) associates your topic
branch with the copy on your fork. So subsequent pushes
can be a plain
Your topic branch is now available on GitLab and now you can make a merge request.
Usually it’s sufficient to work with a branch of Athena, as discussed above:
git fetch upstream git checkout -b master-my-topic upstream/[parent_branch] --no-track
but sometimes you want to work with exactly the same code version as in the release you’re working with. In this case you can checkout the nightly tag - the code as it was when the nightly was built.
asetup master,Athena,2020-09-27T2101 git checkout "nightly/master/2020-09-27T2101" #or alternatively, using the generic environment variables: asetup master,latest,Athena git checkout "$AtlasReleaseType/$AtlasBuildBranch/$AtlasBuildStamp" #For a release build it's different, since the nightly tags are archived after a while. #There is always a stable tag pointing to the release asetup 22.0.15,Athena git checkout release/22.0.15 ###make changes git checkout -b my_topic_branch_from_a_nightly_tag #You can now make a merge request as usual
This is particularly useful if you don’t intend to make changes but just see the code as it is in a nightly/release build, or if your code is likely to be affected by changes in other packages that you don’t compile.