How to Contribute Code#

Note

You’ll need to familiarize yourself with setting up a development environment and building FlightGear in order to contribute code. See Developing on the codebase if you do not already have a working setup. Some understanding of Git will also be necessary; this free, online book is quite useful.

The most efficient way to contribute changes to the FlightGear code base is to file a merge request (this doesn’t apply to aircraft or add-ons, which are managed differently). We’ll first give an overview of the process including its main prerequisites, then explain each step in more detail.

Overview#

The basic workflow for first-time contributors to a FlightGear Git repository is:

  1. Fork the repository. Fork the relevant FlightGear repository into your GitLab account. You will need to know which repository contains the code you are trying to change. Familiarizing yourself with the code base and the purpose of each repository is strongly recommended.

  2. Set up a local clone. Prepare a clone of the repository on your hard disk that is convenient for getting updates from the upstream repository and pushing changes to your fork. You’ll also use this clone to perform test builds.

  3. Build the project. If you haven’t already done so, this will be the time to set up your development environment so that you can build FlightGear.

  4. Create a new branch. Create a branch on your clone to isolate your changes. Use a clear and descriptive name for your branch (e.g., fix-menubar-typo or add-new-joystick-configs).

  5. Make changes. Make the changes on your branch in small, focused commits. Each commit should be self-contained and represent one logical change.

  6. Test and double-check. Before you submit your changes to the FlightGear team for review, double-check your work. Ensure that your code builds and that tests pass.

  7. Rebase and push. Check if the upstream repository was updated in the meantime. If so, rebase your work on its latest state and perform a final test run to make sure everything still works fine.

  8. Submit a merge request. Open a merge request (MR) to propose your changes for review. Be sure to use the Merge Request Template to provide necessary context for reviewers. Feel free to ask on the developer mailing list if you’re unsure whom to add as a reviewer.

  9. Code review. Once you have created a merge request, other developers will review your work, give feedback, and sometimes request changes be made. This is a crucial part of the development process, as it helps reduce bugs and improves code quality.

  10. Clean up. If your merge request was applied, pull your changes from the upstream branch and delete the local branch you created for the merge request.

In order to present these steps in more detail, we’ll now assume that you intend to make your first contribution to the SimGear repository (and thus, that you haven’t already forked it). Except for the target branch name which may differ, the process would be the same for any Git repository of the FlightGear project.

Fork the Repository#

For what follows, you’ll need to create a GitLab account if you don’t already have one. Once you are logged into your account, go to the repository home page (here in our example) and click on the Fork button as shown in forking-the-upstream-repo; after filling some information, this will lead to the creation of a copy of the upstream repository in your own GitLab namespace under https://gitlab.com/YourUserName/.

Once you’ve clicked on the button, a new page is loaded as shown in entering-fork-metadata. The Project name will be prominent but it’s only a label—choose it as you wish (“My SimGear fork” in the example). For the Project URL, you’ll want to select your GitLab username after the initial portion https://gitlab.com/.

The Project slug is the final part of the base URL for the fork you’re about to create; let’s choose flightgear-simgear so that all your forks of repositories of the FlightGear project are named flightgear-something. This way, they will be easy to distinguish from non-FlightGear repositories you might want to publish under https://gitlab.com/YourUserName/. Beware that if you modify the Project name, the GitLab user interface automatically modifies the Project slug; so, better fill them in this order: Project name then Project slug.

There are a few fields left to enter. If you choose to include only the default branch, you’ll save a little amount of space but might have to fetch other upstream branches later. Give your fork public visiblity so that reviews can take place. When ready, click on the Fork project button to actually create your fork of the upstream repository.

Set Up a Local Clone#

Since we want to pull updates from the upstream repository, it is convenient to clone it to your hard disk and modify the clone so that pushes go by default to your fork (which is online under https://gitlab.com/YourUserName/). Cloning the upstream SimGear repository can be done with:

git clone https://gitlab.com/flightgear/simgear.git

Tip

If you use download_and_compile.sh and it manages the repository you want to contribute to (this is obviously the case for SimGear), there is no need to create a new clone: you can simply use the repository clone it created on your disk.

Now, let’s add a Git remote that points to your fork of the upstream repository. We configure this remote so that pushing to it uses SSH authentication. We also configure your repository clone so that pushes go to your fork by default.

git remote add flo https://gitlab.com/frougon/flightgear-simgear.git
git remote set-url --push flo git@gitlab.com:frougon/flightgear-simgear.git
git config remote.pushDefault flo

In the above commands, replace flo (name of the created remote) with an appropriate name of your choice; also replace frougon with your GitLab username.

Build the Project#

Make sure you can build FlightGear using the repository clone set up in the previous step and that the resulting executables run normally. This way, you’ll be able to properly test any changes you later make in this clone.

Note

The following steps will have to be repeated for each “self-contained changeset” that you intend to contribute.

Create a New Branch#

Create a branch based on origin/next that tracks origin/next and make sure it is up-to-date. Instead of new-branch-name, choose a name that makes it clear what the changes in the created branch are supposed to do.

git checkout -b new-branch-name origin/next
git pull

Note

Here, origin is a remote that points to the upstream repository you cloned from, and next is the name of the development branch in the SimGear repository (this is also the case for FlightGear and FGData). If you were to contribute to a different repository such as FlightGear documentation, the branch to base your work on might have a different name (e.g., main).

Make Changes#

Commit the desired changes to the branch you created in the previous step. If you need help with Git, this online book is a great resource.

Each commit message should start with a single, not too long summary line (no more than 72—80 characters if possible), then a blank line, then normal explanations. Example commit message:

HID: allow sending output reports from Nasal

- make watched properties only react on a value change
- refactor the larger usage enums to their own file

Like here, it is useful when the beginning of the first line is short and makes it clear to readers which part of the code (subsystem, class, etc.) is affected by the changes.

Test and Double-check#

Rebuild FlightGear with your changes, carefully test. Build the FlightGear test suite and verify that the tests still pass. This can be done by running make test_suite or ninja test_suite from the FlightGear build directory (not the source repository!).

Use commands like:

  • git status to check the state of your working directory and repository;

  • git log -p to proofread your commit diffs and messages;

  • git commit --amend to modify the most recent commit on the branch;

  • git rebase -i ⟨ref⟩ to modify commits located further in the ancestry graph (namely, descendants of commit ⟨ref⟩; see the git rebase manual page for explanations).

The gitk program is not essential but can be nice for examining commits and visualizing the commit graph. If gitk appears to see local changes that really aren’t there, run git status then rerun gitk.

The pre-commit and clang-format programs are useful to run code quality checks and apply the project formatting rules. Some of the configured pre-commit hooks will for instance check for common mistakes including typos, mixed whitespace or line endings, and so on. If you’ve installed the pre-commit hooks in your repository clone, pre-commit will be automatically run every time you commit.

Note

In most cases, the GitLab CI runs the pre-commit and clang-format checks as part of the automatic verifications that need to pass, before a merge request can be applied.

Rebase and Push#

If the upstream branch you started from has changed in the meantime, your work needs to be rebased on top of its latest state. This can be done with the following command:

git pull --rebase

In case someone was working on the same files as you, this may trigger conflicts (so it’s a good idea to first announce what you’re going to work on in order to minimize friction and benefit from the insight of experienced people). Conflicts don’t happen very often and it’s not the end of the world when they do. Again, this Git book is a very useful resource in such cases.

If the rebasing did grab upstream changes, perform a final build-and-test run to be sure everything works fine. Finally, push the branch to your fork:

git push

With no additional arguments, this pushes the current branch to the remote specified with the remote.pushDefault setting, i.e. to your clone if you followed the above instructions. Once the push is successful, Git will show a URL; following it will start the next step.

Submit a Merge Request#

The web page opened from the URL output by Git when you pushed to your fork allows to create a merge request from the branch that was pushed. From this page, select the proper target branch: for development code in SimGear, that would be next. Select yourself as an assignee (meaning that you are going to shape the merge request into its final form). Select one or more reviewers to look at it—you can ask on the flightgear-devel mailing-list if unsure, or just leave the field as Unassigned. Don’t worry too much about the milestone (a priori, next should do unless the merge request is specifically a fix for a release branch). Select applicable labels, etc.

Regarding the Delete source branch when merge request is accepted option, we advise you to make sure it is enabled, otherwise your fork will soon have tons of branches. What this option does is the following: when the branch from your merge request is merged into the upstream branch, GitLab will automatically delete the merge request branch (that you pushed) from your fork. This happens online at GitLab, not in your local clone. Thus, even after this occurs, the branch will still be present locally in your clone, until you delete it yourself (cf. below).

Finally, the Squash commits when merge request is accepted option can be used in case you pushed several commits but would rather have them coalesced into a single one when the merge request is applied. This is something that can be done locally using Git before pushing (in particular, with git rebase -i), however the option is still useful in case commits are added to the merge request after the initial push, be it by you or by reviewers.

Code Review#

After a few minutes, hours or days, you’ll receive feedback from the FlightGear developers about your merge request. Reviewing merge requests requires expertise and takes some time, so please carefully read the remarks and suggestions, follow up on the questions and requests for changes.

Clean Up#

Once the branch is merged, update the local branch of your clone that tracks the upstream branch your merge request went to (this is the next branch in our SimGear example):

git checkout next
git pull --rebase

(Normally, the --rebase option shouldn’t be necessary here as you shouldn’t have any local commits on top of the upstream ones in this branch, however it doesn’t hurt and can make things easier if you’ve been forgetful.)

You can now delete the local branch you created earlier to avoid cluttering your local clone with legacy, unneeded branches:

git branch -d new-branch-name

In case this branch hasn’t been merged exactly as is into the upstream branch (same commit contents and metadata), Git will warn and refuse to delete the branch unless you insist using -D. If this happens, you’ll have to evaluate yourself (by using git log -p, by comparing files…) if deleting your local branch new-branch-name is really the right thing to do. In the likely case that what was merged is a strict improvement over what you have in new-branch-name, then deleting is the way to go.

Tip

If you really, really messed up and deleted the branch before realizing that it was a mistake, git reflog is likely to save you: among other things, it shows the commit hashes corresponding to previous positions of the tips of various branches. As long as no garbage collection occurred in the meantime (git gc), the commit hashes are all you need to restore “lost commits”: simply create a branch or tag from the desired commit (before doing do, you may want to use git show ⟨hash⟩ to see the commit for a given hash, or git log ⟨hash⟩ to examine its ancestry).

From time to time, you may also want to run git fetch -p flo (replace flo with the name of a remote that points to your fork, cf. Set Up a Local Clone). This removes the flo/... branches from your local clone that have been deleted from your fork at GitLab due to the Delete source branch when merge request is accepted option on the merge request page (note that for instance, flo/new-branch-name and new-branch-name are different branches in your clone; they’ll both clutter the display when using git log or gitk until you delete them).