Git and GitHub
Contributing to Betaflight involves preparing your development environment and making a fork of the repository and working with Git. This document gives some instructions on how to handle Git.
Look in development/building for installation notes for your environment.
Getting Started
Clone your fork to your development machine
First make a fork of the repository you want to work on from the GitHub website.
git clone https://github.com/<your-username>/betaflight.git
To clone a specific branch:
git clone -b <branch-name> https://github.com/<your-username>/betaflight.git
SSH vs HTTPS
The examples in this guide use HTTPS URLs. If you prefer SSH (avoids entering credentials on each push), set up an SSH key by following GitHub's SSH guide, then use SSH URLs instead:
git clone git@github.com:<your-username>/betaflight.git
To switch an existing remote from HTTPS to SSH:
git remote set-url origin git@github.com:<your-username>/betaflight.git
Configure your identity
Configure this to have the correct author in your commits:
git config --global user.name "Your Name"
git config --global user.email "your@email.domain"
If you omit to configure this you get a warning and have to use the following commands to rectify:
git config --global --edit
git commit --amend --reset-author
Recommended global configuration
Windows
git config --global core.autocrlf true
Linux/macOS
git config --global core.autocrlf input
Cross-platform
git config --global core.safecrlf warn
git config --global core.whitespace cr-at-eol
git config --global core.filemode false
Set up remotes
git remote add upstream https://github.com/betaflight/betaflight.git
git remote -v
Daily Workflow
Create a branch and start making changes
Always create feature branches from upstream master, not your local master:
git fetch upstream
git checkout -b <branch-name> upstream/master
Stage files and commit
git add .
git commit -m "message"
git push origin <branch-name>
Note: git commit -am stages and commits tracked files in one step, or you can specify individual files.
Write good commit messages
A clear commit message helps reviewers and makes the project history useful. Follow these guidelines:
- Use the imperative mood in the subject line: "Add gyro filter" not "Added gyro filter"
- Keep the subject line under 72 characters
- Separate the subject from the body with a blank line
- Use the body to explain what and why, not how
Example:
Add deadband support for RC channels
Without a deadband, small stick noise causes unnecessary PID updates.
This adds a configurable deadband threshold per channel.
Amend your last commit
If you need to update your most recent commit (fix a typo, add a missed file), amend it instead of creating a new commit. Only do this before the PR is merged — amending rewrites the commit and requires a force push:
git commit --amend
git push origin <branch-name> --force-with-lease
--force-with-lease is a safer alternative to --force. It refuses to push if someone else has pushed to the branch since your last fetch, preventing you from accidentally overwriting their work.
Stash work in progress
If you need to switch branches but aren't ready to commit:
git stash
To restore your stashed changes:
git stash pop
To see all stashes:
git stash list
Building and Testing Before You Push
Always build and run unit tests locally before pushing your changes. This catches issues before CI does.
make TARGET=BETAFLIGHTF4 # Build for a specific target
make test # Run all unit tests
make junittest # Run unit tests with JUnit output
After pulling upstream changes or switching branches, always clean before building to avoid stale object files:
make clean
make TARGET=BETAFLIGHTF4
See Test Coverage for details on generating coverage reports.
Keeping Up to Date
Update master branch with upstream and sync your fork
git checkout master
git fetch upstream
git merge --ff-only upstream/master
git push origin master
If the merge fails because you have local commits on master, you can reset to match upstream exactly. This will discard any local commits on master:
git reset --hard upstream/master
git push origin master --force-with-lease
Update your local branch with upstream changes
git checkout <branch-name>
git pull --rebase upstream master
Update submodules (config)
When working on firmware sometimes we need to reset the config submodule to match the master branch as it should not be included in any PR.
git fetch upstream
git checkout upstream/master -- src/config
git submodule update src/config
git commit -m "Reset src/config submodule pointer"
Working with the config repository
Board configurations live in a separate repository. If you're adding or updating a target, you'll need to work with both repos:
git clone https://github.com/<your-username>/config.git
cd config
git remote add upstream https://github.com/betaflight/config.git
Submit config changes as a separate PR to the config repo. Do not include config submodule changes in firmware PRs. See Manufacturer Requirements for full submission guidelines.
Resolve merge conflicts
When rebasing or merging, you may encounter conflicts. Git adds conflict markers to the affected files — <<<<<<< HEAD, =======, and >>>>>>> upstream/master — separating your changes from the incoming changes.
To resolve:
- Open the conflicting files and edit them to keep the correct code
- Remove the conflict markers
- Stage the resolved files:
git add <resolved-file>
- Continue the rebase or merge:
git rebase --continue # if rebasing
git merge --continue # if merging
To abort and start over:
git rebase --abort
Undoing Changes
Unstage a file
git restore --staged <file>
Discard changes to a specific file
This permanently discards uncommitted changes to a file:
git restore <file>
Undo an unpushed commit (keep changes)
git reset HEAD^
Discard all uncommitted changes to tracked files
git reset --hard HEAD
To also remove untracked files and directories (e.g., build artifacts). This cannot be undone:
git clean -fd
Revert a commit
To undo a commit that has already been pushed by creating a new commit that reverses the changes:
git revert <commit-sha>
git push origin <branch-name>
This is safer than rewriting history on shared branches because it preserves the commit log.
Remove unwanted commits from a pushed branch
Use interactive rebase to remove or edit specific commits:
git checkout <branch-name>
git rebase -i origin/<branch-name>~2
git push origin <branch-name> --force-with-lease
If this fails, back up your changed files (or use git stash), then reset and recommit:
git reset --hard HEAD~
git stash pop
git add .
git commit -m "Make new commit"
git push origin <branch-name> --force-with-lease
Inspecting Changes
See uncommitted changes
git diff # Unstaged changes
git diff --staged # Staged changes (ready to commit)
See commit history for a file
git log -- src/main/cms/cms.c
View a compact commit history
git log --oneline --graph --decorate
See what changed in a specific commit
git show <commit-sha>
Compare two branches
git diff master..<branch-name>
Working with release tags
Betaflight uses version tags (e.g., 4.1.1, 2025.12.0) to mark releases. To list available tags:
git tag
To checkout a specific release (this puts you in detached HEAD state — safe for inspecting or building, but not for committing):
git checkout 2025.12.0
To create a branch from a tag if you intend to make changes:
git checkout -b <branch-name> 2025.12.0
To see which tag you're closest to:
git describe --tags
Tags are used with bisection to narrow down which release introduced a bug.
Working with Pull Requests
Creating a pull request
Before creating a PR:
- Never create a PR from your
masterbranch — PRs from master are automatically closed. Always use a feature branch. - Keep PRs focused — each PR should address one thing only. Smaller PRs are easier to review and merge.
- Rebase onto latest upstream before opening the PR to avoid conflicts.
- Run
make testto ensure unit tests pass.
Once your branch is pushed:
- Go to your fork on GitHub
- Click "Compare & pull request"
- Write a clear description of what the PR does and why
- Reference any related issues (e.g., "Fixes #1234")
After the PR is created, GitHub Actions will automatically build your changes and report any errors. See Development for more details on the review process.
Quickly testing a PR
To fetch and test someone else's PR locally:
git fetch upstream pull/<pr-number>/head:<pr-number>
git checkout <pr-number>
Squash your commits
Note the number of commits in your PR, then run an interactive rebase:
git rebase -i HEAD~<number-of-commits>
- You should see a list of commits, each commit starting with the word "pick".
- Make sure the topmost, first commit says "pick" and change the rest below from "pick" to "squash". This will squash each commit into the previous commit, which will continue until every commit is squashed into the first commit.
- Save and close the editor.
- It will give you the opportunity to change the commit message. What you see is a single message containing all of the commit messages. Edit these as you wish.
- Save and close the editor again.
- Important: If you've already pushed commits to origin, and then squash them locally, you will have to force the push to your branch.
Finally update with:
git push origin <branch-name> --force-with-lease
Commit to a PR from another contributor
Sometimes you want to make changes to an existing PR. Before doing so, ask permission from the contributor. The contributor must also have "Allow edits from maintainers" enabled on their PR.
In the example, substitute the contributor name, project, and branch:
git remote add <contributor> https://github.com/<contributor>/betaflight.git
git fetch <contributor>
git checkout -b <branch-name> <contributor>/<branch-name>
Make your changes, commit, and push back to their fork:
git push <contributor> <branch-name>
The original author can then pull the changes to their local branch with:
git pull origin <branch-name>
Checkout work on another machine
If you have pushed a branch from one machine and want to continue working on it from a different clone:
git fetch origin
git checkout -b <branch-name> origin/<branch-name>
Managing Development Branches
When working on multiple development branches, if your local repo is ahead of master, a new PR will include these commits. To resolve this issue:
Fix an existing branch
git fetch upstream
git checkout <branch-name>
git rebase -i upstream/master
In the editor, delete all commits not part of the PR and save the file.
git push origin <branch-name> --force-with-lease
Advanced
Cherry-pick a commit
To apply a specific commit from another branch onto your current branch:
git cherry-pick <commit-sha>
This is useful when you need a specific bug fix from another branch without merging everything.
Sign your commits with GPG
See Managing commit signature verification on GitHub.
When using commit, add the -S flag to sign the commit and enter the passphrase you have chosen before.
Bisection
Use git bisect to find the commit that introduced a bug:
git bisect start
git bisect bad 4.1.2
git bisect good 4.1.1
Git will automatically check out a commit halfway between the two versions. Build and test it, then tell git the result:
git bisect good # if the bug is not present
git bisect bad # if the bug is present
Repeat until git identifies the offending commit. When finished:
git bisect reset
Useful Git aliases
Add these to your ~/.gitconfig to speed up common operations:
[alias]
st = status
co = checkout
br = branch
lg = log --oneline --graph --decorate --all
unstage = restore --staged
last = log -1 HEAD
amend = commit --amend --no-edit
See Also
- Development Guide — general contribution guidelines, PR process, and coding principles
- Coding Style — code formatting requirements
- Test Coverage — unit test and coverage details
- Building — setting up your build environment