Protecting Main: Team Git Workflow
Everything in this unit has built to one principle: main is always competition-deployable. Not "probably fine," not "worked last time we checked" — deployable right now, without hesitation, on any machine, in any pit. This lesson explains the technical and process tools that make that guarantee possible across a full season.
By the end of this lesson, you will:
- Configure GitHub branch protection rules that enforce review requirements and prevent accidental pushes to
main - Create and push annotated Git tags to mark competition-ready releases
- Execute the competition-day hotfix workflow — make a targeted fix and deploy without disrupting the stable codebase
- Apply Team 2910's full season Git workflow from kickoff through championship
- Explain what force-pushing is, why it rewrites history, and why it must never be done on shared branches
The Principle: main Is Always Deployable
Every lesson in this unit has built toward one working rule: main is the branch you deploy to the robot. It contains only code that has been reviewed, tested, and approved. No half-finished features. No experimental changes. No "I'll fix this later" shortcuts.
This sounds strict. In practice it's liberating — because when something breaks at competition, you know with certainty that checking out main gives you a working robot. The debugging question becomes "what changed since the last tag" rather than "is any part of main broken."
Three tools enforce this principle across a season:
- Branch protection rules — prevent pushing directly to
mainand require approved PRs - Release tags — pin specific commits as named, reachable competition states
- The hotfix workflow — a defined process for emergency changes during competition
Branch Protection Rules
GitHub's branch protection rules are configured in your repository settings under Branches → Branch protection rules → Add rule. They enforce your team's process at the infrastructure level — even a repository admin cannot bypass them without explicitly removing the rule. Click each rule to understand what it does and why an FRC team needs it.
In your repository: Settings → Branches → Add branch protection rule. Set the branch name pattern to main. Enable the rules your team needs. The settings described above are the minimum Team 2910 recommends for any competition robot repository. More advanced teams also configure required status checks (CI) that run build and lint checks automatically on every PR.
Release Tags: Naming a Moment in History
A Git tag is a permanent, human-readable name attached to a specific commit. Unlike branches, tags don't move — they're a fixed pointer to one moment in history. Teams use tags to mark competition-ready states: the code that was on the robot during qualifications, the version that won eliminations, the state deployed to the practice robot on Thursday.
An annotated tag — created with -a — includes a message, a tagger name, and a timestamp. It's the equivalent of a signed document. A lightweight tag is just a pointer with a name, no metadata. Use annotated tags for competition releases.
At a regional I watched a team's autonomous routine work perfectly in practice matches and then break in quals. Between practice and quals they had merged a "quick fix" for an unrelated mechanism that accidentally changed a constant in Constants.java. They had a tag from before the fix — git checkout v1.0-practice -- Constants.java restored the working constant in thirty seconds. Without the tag, they would have had to audit every constant by hand. With it, they were back on the field for their second qual match with working autonomous.
The Season Workflow, From Kickoff to Championship
The workflow below describes Team 2910's Git process across a full season. Every stage maps back to the tools from Lessons 2–5. Select any stage to see what the correct Git action is — and what happens when teams without a defined workflow face the same moment.
The Competition Weekend Timeline
The competition weekend is where every Git habit either pays off or doesn't. The timeline below shows the critical Git touchpoints and what each one is protecting.
Freeze main and tag the release
All open PRs are reviewed and merged or explicitly deferred. main is tagged: git tag -a v1.0-regional-1 -m "build going to competition" and pushed. From this point forward, nothing merges to main unless it has been physically tested on the practice robot and reviewed by a mentor.
Test and observe, commit nothing
Practice matches are for tuning and observation. Keep notes on what needs changing. Only commit tuning adjustments after they've been verified on the practice field — use feature branches, not direct edits to main. At the end of the day, tag again if significant tuning was merged: v1.1-regional-1-thursday.
Emergency fix window: hotfix branch only
Between matches, the pit window is 8–12 minutes. The only code changes allowed are hotfixes: branch from main → make the minimum change → deploy → verify → get review → merge. No new features. No refactors. No "while we're in here." Every change must be reversible to the tagged state in under two minutes.
Tag before every risk
If the team wants to try a new autonomous path before eliminations, tag the current state first: v1.2-elims-safe. Test the new path in a practice match. If it works, merge and tag the result. If it doesn't, git checkout v1.2-elims-safe restores the working state in five seconds. Never go into eliminations without a named safe state.
Document and unfreeze
Update the README with what was deployed, what worked, and what to improve. Tag the final competition state: v1.3-regional-1-final. Unfreeze development — resume the normal PR workflow for the next event cycle.
The Hotfix Workflow
A hotfix is the smallest possible change needed to restore competition functionality. The entire workflow takes under ten minutes when the team has practiced it. Here it is step by step:
The hotfix step that gets skipped under pressure is step 6 — the mentor review. When you have eight minutes before your next match, asking someone to look at a one-line change in Constants.java feels unnecessary. I've seen it take thirty seconds. I've also seen a programmer skip that review, merge a "one-line fix" that changed the wrong constant, and spend the next three matches debugging a problem they just introduced. The hotfix workflow is designed to be fast enough that the review is never the bottleneck. The constant it saves is the one you didn't realize you were breaking.
Force Push: The One Command That Rewrites History
git push --force overwrites the remote branch with your local version, discarding any commits on the remote that aren't in your local history. On a personal branch you own alone, this is occasionally useful. On any shared branch — especially main — it is destructive and usually irreversible.
Branch protection rules prevent force-pushing to main automatically. But the rule matters on all shared branches — a force-push to a feature branch someone else has pulled is just as disruptive. The rule of thumb: if another programmer has ever pulled or checked out a branch, never force-push it.
Team Configuration: gitconfig and Identity
Every commit is signed with the author's name and email from their local Git configuration. These appear in the commit log, in PR metadata, and in GitHub's contributor statistics. Setting them correctly is the difference between a commit attributed to "your name" and one attributed to "student@students-macbook.local."
Every new programmer on Team 2910 completes these steps before their first commit: (1) Install Git and set user.name and user.email matching their GitHub account. (2) Create a GitHub account with their real name and a permanent email. (3) Add their SSH key or configure HTTPS credentials to their GitHub account. (4) Clone the team repository, create a test branch, make a test commit, open a draft PR, and close it. This five-step onboarding takes under an hour and catches configuration issues before they appear mid-season.
Unit 3 Summary: The Complete Workflow
Every lesson in this unit is a layer in a single system. Here is how they stack:
🔌 System Check
- Branch protection is configured before build season begins. Not before the first competition — before the first day someone might accidentally push directly to
main. Protection rules set at the start prevent the habits that bypass them from ever forming. - Every programmer's
user.nameanduser.emailmatch their GitHub account. Commits attributed to "Unknown User" or a local machine hostname can't be traced, can't be credited, and look unprofessional in the repo history that represents your team to the FRC community. - The team has a named tag for every competition build. Not just "main at the time of competition" — an explicit tag with a date, event, and brief description. Tagged releases are the foundation of competition-day debugging and recovery.
- The hotfix workflow is practiced before competition, not learned during it. Run a hotfix drill in the shop: identify a fake bug, branch from a tag, fix it, review it, merge it, tag the result. The first time should not be in a pit window with a referee watching.
- No force-pushes on any shared branch, ever. Configure branch protection to enforce this on
main. Establish it as a team norm for feature branches. The habit protects both the code and the trust between programmers. - The README documents the tag naming convention. Future programmers should be able to look at
v1.2-regional-2-elimsand understand immediately what it represents. Document the convention so it survives programmer turnover.
Knowledge Check
Click an answer to check your understanding.
main because it introduced a bug. They suggest running git push --force origin main after resetting locally. What is the correct approach and why?Configure, Tag, and Run a Hotfix Drill
This is the Unit 3 capstone prompt. It brings together every lesson — protecting a branch, tagging a release, and executing a complete hotfix cycle under simulated time pressure.
- Configure branch protection. Open your team's robot repository (or your practice repo from Lessons 2–4) on GitHub. Navigate to Settings → Branches → Add rule. Set the pattern to
main. Enable: Require a pull request, require at least 1 approval, dismiss stale reviews when new commits are pushed, and block force pushes. Verify the settings by attempting a direct push to main from your local machine — it should be rejected. - Set your Git identity. Run
git config --global user.nameandgit config --global user.emailand verify they match your GitHub account. If they don't, update them now. Confirm by making a commit and viewing it on GitHub — your name should appear as the author. - Tag the current state as a practice competition release. Ensure
mainis clean and at a reasonable state. Rungit tag -a v1.0-practice-event -m "Practice event build — [today's date]". Push the tag. Verify it appears in your repository's Releases or Tags section on GitHub. - Simulate a competition bug. On a teammate's machine (or in a second terminal window), introduce a deliberate problem: change one constant in
Constants.javato an incorrect value, commit it directly to a feature branch, get it merged via PR, and push. The currentmainnow has a "bug." - Run the hotfix drill — set a timer for 10 minutes. Starting from a clean
main, identify the broken constant, branch (hotfix/fix-constant), fix it, stage, commit, ask your teammate for a 60-second review, merge tomain, push, and tag the result (v1.1-practice-event). Document how long each step took. - Recover to the pre-bug state using the tag. Run
git checkout v1.0-practice-event -- src/main/java/frc/robot/Constants.java(without the hotfix). Verify the file is at the original value. This simulates the "revert to safe state" recovery path without the hotfix. - Write a brief post-drill report. Answer: How long did the hotfix take? Which step took the most time? What would you change to be faster next time? Where in the workflow did you feel uncertain about the correct Git command?
- Bonus: Look at Team 2910's competition robot repository on GitHub. Find the tag list (Repository → Tags). How many tags exist across seasons? What naming pattern do they use? Does the naming convention tell you anything about how their competition seasons went? Write two paragraphs comparing their tagging approach to the one described in this lesson.