Git is the version control system used for tracking the source code of LifeV. A good knowledge of Git is thus mandatory for developing inside LifeV, for getting the latest changes and publishing the own source code.
Development in LifeV must follow a small set of guidelines, in order to facilitate the collaboration among developers and the propagation of changes, features, and bug fixes. There are several LifeV Git repositories:
lifev-release: release version of LifeV, containing tags for each release version number
lifev-dev: development version of LifeV, shared by all groups of the consortium
lifev-[group]: development version of LifeV internal to a group
There should be a continuous integration of features and changes from the internal development versions to the shared codebase and then to the release version of LifeV. This integration is maintained, both the heads of the groups and the LifeV administrators, and by the developers themselves by following the common guidelines.
The single LifeV developer works, usually, on the development version internal to its group.
Each developer, or a sub-group of developers, work inside of a specific topic branch.
Branches should be called with a meaningful name: the usual convention is to use the format
The branches must be updated with the changes on the master branch on a daily basis, by merging (or, better, rebasing) the master branch inside the development branch. This is to enforce all branches to remain aligned to the master and to incorporate all bug fixes.
The branches must be merged into the master branch ideally on a weekly basis. This is to maintain the master branch updated and to facilitate the collaboration and sharing of source code among the group.
Sub-groups usually work on different part of the codebase, thus a continuous merging of the source code should not interfere much between developers.
If this is not the case, i.e. different sub-groups work on the same part of source code, it is even more important to keep the sources aligned, in order to avoid accumulating differences which are difficult/impossible to merge in a later moment.
Merging with the master branch must be done by issuing a pull request. When pushing a branch to Bitbucket, a link for registering the pull request on the website is automatically shown in the console. The pull request must contain a meaningful name and description.
Bug fixes related to code belonging to the master branch must be coded directly on the master branch, in order to be shared with the other developers as soon as possible. This is done by:
Creating a branch from the master (following the same naming convention as written above).
Coding the fix to the inside the branch.
Pushing the branch to the git repository and opening a pull request corresponding to the branch with the bug fix.
Before each pull request to the master branch, the full set of tests must be run locally with success. All the examples (in general, all the code belonging to every module) must, at least, compile.
Pull requests and reviews of the code are handled by the heads of the groups and the LifeV administrators.
Various references to learn Git:
First basic commands
We highly suggest to look at the basic references on git. Here we report a quick list of the most basic commands to use.
To clone a repository:
$ git clone email@example.com:lifev-dev/lifev-release
Add some files to the files staged for commit:
$ git add files dir/
Remove some files from the files staged for commit:
$ git rm files
Check the status of the working tree:
$ git status
Perform a commit, including all the files staged for commit:
$ git commit -m "message"
Push the local changes to the remote (e.g. from the remote origin on the branch master):
$ git push origin master
Pull the remote changes into the local cloned repo:
$ git pull
Download the remote changes without merging them into the current working tree:
$ git fetch
Download the remote changes, including the deleted branches:
$ git fetch -p
List all remotes:
$ git remote -v
Add a remote:
$ git remote add <name> <url>
Remove a remote:
$ git remote remove <name>
Change the URL of a remote:
$ git remote set-url <name> <newurl>
For the commands regarding merge/rebase and the handling of topic branches, see the following sections.
Ignoring some files or directory
In order to make git ignore some files or directories, create a
file formatted, for example, as follows:
file.txt *.cpp a_directory another_directory/*.h /directory3
.gitignore in the parent directory from which the indicated files/directories
should be ignored.
It is possible to specify a single file or directory to ignore:
which will ignore all files or directories named
the parent directory and all its subdirectories;
a set of files/directories using wildcards:
a specified file or directory located inside the parent directory (this rule does not apply for its subdirectories):
.gitignore files are like other files: they should be added, committed and pushed
Moving files inside a Git repository
The operation of moving or renaming files is supported by the Git source control tool, no external tools being necessary. To rename or move a file, simply issue:
$ git mv old_name new_name
Proceed with care, as there is one caveat: renaming and modifying a file in the same commit will make the repository loose it's history. Therefore, the procedure is to always rename a file in one commit and modify it in the next one.
Git branches, used together with rebasing, represent a very powerful solution to organize local and remote work. The following are the steps that need to be taken to create, use and maintain local and remote topic branches.
Creating a new local topic branch
Suppose you are starting to experiment with new code, but want to do the development in a sandboxed environment, without affecting the existing stable part of the code. Creating a new branch for this topic is easy:
$ git branch new_topic $ git checkout new_topic
or issue the following command to create and checkout the new branch at the same time:
$ git checkout -b new_topic
At this point you can begin to develop and make commits to this new branch.
Following an already existing remote topic branch
In order create a local copy of an already existing remote branch and start following its updates, issue the following command:
$ git checkout --track origin/branch
Listing the branches
In order to list the local branches:
$ git branch
To list all branches, including the remote branches on the remotes:
$ git branch -a
Merging a topic branch into another
At some point you may desire to bring the changes introduced by the new branch into an existing branch, for example into the master. All you have to do is issue:
$ git checkout new_topic $ git rebase master $ git checkout master $ git merge new_topic
As stated earlier, the rebase command ensures the history will remain linear: it appends the local commits of the new_topic branch after the last commit of the master. Alternatively a simple merge command can be used, resulting in a less linear history:
$ git checkout master $ git merge new_topic
In effect, by using a branch and rebase the other developers don't even have to be aware that a new branch exists. However, to avoid undesired results of a rebase command, it is important to follow the golden rule of git rebase: never use it on public branches.
Suggested reading before starting to use the rebase command:
Publishing the topic branch upstream
If it is desired that the new branch is to be shared among developers, it can be published to a shared repository, for example the "origin" repository which you cloned:
$ git push origin new_topic:remote_new_topic
or, more simply:
$ git push origin new_topic
At this point, the branch is available in the "origin" repository and can be fetched and modified by others.
Updating local branch
After publishing it, the development of the branch may diverge: your local copy has commits you haven't pushed upstream and the upstream copy has new commits you haven't downloaded. The solution is rebasing the local branch with the remote one. First, make sure that the information on the origin repo is up-to-date:
$ git fetch
and then rebase the local branch with the remote one:
$ git checkout new_topic $ git rebase origin/remote_new_topic
Updating remote branch
After the local branch has been updated with the remote changes, it may be desired that the remote branch be update with the local changes too. To do this, push the local branch on the remote one. This operation will only succeed if the push operation is a fast forward operation, to prevent data loss:
$ git push origin new_topic
Deleting the local and the remote branches
If the local topic branch is no longer needed, it can be deleted with:
$ git branch -d new_topic
If this branch contains unique commits that haven't been merged into master yet (and the user still want to delete it), a stronger form of the command is required:
$ git branch -D new_topic
When the remote branch is no longer neeeded, the push command is used to delete it:
$ git push origin :remote_new_topic
This effectively deletes the remote branch, so it has to be used with care!
Rebasing is one of the most powerful features in Git but has to be used with care: it can ensure that the history of a project remains linear, which is easier to understand, but it also has the power to rewrite the history of a project. In a distributed developer environment this means that a lot of developers can end up with invalid commits if one of them decides to rebase the common commits.
For a branch that has diverged at some point, meaning there are both new local commits and new remote commits, rebasing the local vesion of the branch on the remote one works by first temporarily removing all local commits back to the most recent common commit, applying the remote commits and finally applying the new local commits on top.
The basic syntax of the rebase command is the following:
$ git rebase upstream [branch]
where: "upstream" is the remote branch to rebase the current active branch on. "Branch" is optional and, if provided, makes git do a:
$ git checkout branch
on that branch first.
Due to the fact that the pull command is setup to do a branch merge by default (the changes on the remote branch are first fetched into a temporary local branch and then merged with the local branch that has to be updated. At the point where two branches are merged a new merge commit is introduced) it is necessary to append the "--rebase" parameter to the pull command in order to do a rebase instead of a merge.