Basic Git: Clone, Commit, Push, Pull
Lesson 1 introduced the four zones. This lesson puts commands on the arrows between them. By the end you'll have a complete, repeatable workflow for every coding session — from cloning a repo for the first time to getting a teammate's changes into your local copy.
By the end of this lesson, you will:
- Clone a GitHub repository to your local machine and understand what that action creates on disk
- Use
git statusto read the state of your working directory and staging area at any point - Stage changes with
git addand create a commit with a meaningful message - Push commits to GitHub and pull a teammate's commits into your local repo
- Write commit messages that follow the Conventional Commits format used by Team 2910 and most professional FRC teams
- Configure a WPILib-appropriate
.gitignoreso build artifacts never reach the repository
Commands Are the Arrows
In Lesson 1 you built a mental model of four zones: working directory, staging area, local repository, and remote. Git commands are the arrows that move your changes between those zones. Every command in this lesson corresponds to one of those arrows — and knowing which zone your changes are in at any moment is how you know which command to run next.
The workflow tracer below steps through a complete FRC coding session from first clone to first push. Work through it before reading the individual command sections — the whole picture makes each piece easier to place.
A Complete FRC Session, Step by Step
The Commands in Depth
git clone — copying a remote repo to your machine
git clone downloads a repository from GitHub (or any remote) and creates a local copy with the full commit history. It also automatically sets up the remote — Git remembers the URL you cloned from as origin, so future push and pull commands know where to send and receive changes.
Cloning sets up everything — the files, the .git folder, and the remote reference. After that first clone, you use git pull to get updates. A common mistake is cloning the same repo again after a computer restart instead of just running git pull. You end up with two copies and confusion about which one to edit. Clone once, pull often.
git status — reading the current state
git status is the most important command in your daily workflow. It tells you which files have changed in your working directory, which changes are staged for the next commit, and whether your local branch is ahead of or behind the remote. Run it constantly — before staging, before committing, before pushing. It costs nothing and tells you everything.
git add — moving changes to the staging area
Staging is a deliberate step: you choose exactly which changes belong in the next commit. This lets you make multiple unrelated edits in a session and commit them as separate, focused snapshots — "add intake motor" as one commit, "fix dashboard label typo" as another.
git commit — creating a permanent snapshot
A commit takes everything in the staging area and writes it to the local repository as a permanent, named snapshot. The -m flag attaches your message. Every commit gets a unique SHA hash — a 40-character fingerprint — that lets Git (and you) refer back to exactly this state forever.
git push — sending your commits to GitHub
git push uploads your local commits to the remote repository. Until you push, your commits exist only on your machine — a laptop that gets lost, broken, or wiped takes your unpushed commits with it. Push at the end of every session, and consider pushing after every significant commit during long sessions.
git pull — getting your teammates' changes
git pull downloads commits from the remote and merges them into your local branch. Run it at the start of every session and whenever a teammate tells you they pushed something. If you edited the same lines a teammate also changed, Git will alert you to a merge conflict — Lesson 3 covers resolving those.
git log — reading the commit history
The commit history is the most useful debugging tool you didn't know you had. When something breaks, git log shows you every change made and when. The --oneline flag gives a compact view perfect for scanning a build session's changes.
Read the log above from bottom to top — that's the actual sequence this robot's code was built in. When the swerve drive broke during testing, the team ran git diff a1b2c3d 2e9f563 to see exactly what changed between the two commits and found the FL/FR swap in under two minutes.
Commit Messages: The Difference Between a Log and a Story
A commit message is the only explanation future-you — or a teammate at competition — will have for why a change was made. The message lives in the permanent history of the repo. It costs nothing to write a good one and costs time to have written a bad one.
Team 2910 follows the Conventional Commits format, which is standard across professional software engineering and most competitive FRC teams:
The scope in parentheses is optional but strongly encouraged on a robot repo — it lets you scan the log and immediately know which mechanism each commit touches without reading the full description.
Commit Message Workshop
The messages below were pulled from real FRC repos (names changed). Select any one to see why it creates problems and what a better version looks like.
The .gitignore File: Keeping Build Artifacts Out
A .gitignore file tells Git to never track certain files or folders. In a WPILib project, the build system generates hundreds of megabytes of compiled class files, Gradle caches, and simulation outputs. None of these belong in the repository — they're regenerated automatically on every build, they change constantly, and including them buries actual code changes in noise. Every FRC repo should have a .gitignore committed before any other files.
build/
.gradle/
bin/
out/
# WPILib simulation
simulation/
*.halsim
# IDE files
.vscode/
.idea/
*.iml
# OS files
.DS_Store
Thumbs.db
# Vendor library caches
vendordeps/*.json.bak
The single most common Git-related pull request problem I see during code review is a team that committed their build/ directory. A typical WPILib build directory is 80–200 MB. Pushing it bloats the repository, makes cloning take minutes instead of seconds, and fills every git diff with thousands of lines of compiled bytecode changes. Worse, it hides the actual code changes — a PR that touched three Java files shows as "847 files changed" because every compiled output was regenerated. A five-line .gitignore in the first commit prevents this for the life of the project.
When you create a new project with the WPILib VS Code extension, a .gitignore is included automatically. It covers the most important patterns. Before your first git add ., run git status and verify that build/ and .gradle/ are not listed as untracked files. If they appear, your .gitignore is missing or in the wrong location.
The Daily Habit: Starting and Ending Every Session
Good Git hygiene is about consistent habit, not heroic effort. Every FRC programmer on 2910 follows the same pattern at the start and end of every coding session:
The most common conversation I have with teams at competition about Git goes like this: "Our robot code was working, someone pushed something last night, and now autonomous is broken." I ask them to run git log --oneline -5 and show me the screen. Within thirty seconds we've identified the breaking commit. Then it's git revert <sha> or git checkout <sha> -- filename.java and the issue is resolved before the next match. Teams that don't commit frequently can't do this — they have one commit from the start of the week and no way to identify what changed. Commit after every meaningful unit of work. The overhead is thirty seconds. The insurance value is hours.
🔌 System Check
- Run
git pullbefore touching any file at the start of every session. Editing files while your local repo is behind the remote is the leading cause of merge conflicts. A 10-second pull at the start prevents an hour of conflict resolution later. - Run
git statusbefore everygit addand before everygit push. It's free information about your current state. Committing the wrong files or pushing an unexpected change because you didn't check is avoidable. - Commit one logical change per commit — not one commit per session. "Added everything for today" is not a commit message. A commit should represent a single, describable, reversible change. If you need to revert one thing tomorrow, you want to revert one commit — not undo a day's work.
- Never commit build artifacts. Verify
build/and.gradle/are in.gitignorebefore the first push to a new repo. Once build artifacts are in the history, they're difficult to remove without rewriting commits. - Push before you leave the shop. "I'll push it later" has ended competition robots. A laptop left at home, a battery that died, a failed drive — any of these takes your local commits with them. The repo on GitHub is your backup. Use it.
- Use
git log --onelineas a diagnostic tool, not just a historical record. When autonomous breaks, the first thing to run is the log. The breaking commit is almost always visible in the last five entries.
Knowledge Check
Click an answer to check your understanding.
Robot.java and run git commit -m "update" without running git add first. What is the result?git push origin main and confirmed it succeeded. The next morning you find the build/ directory was included in that push. What almost certainly caused this, and how do you prevent it on the next project?Your First Real Commit
This prompt puts your WPILib project from Unit 0 under version control from scratch. Every step is a real terminal command — do them in order, in a terminal, in your project folder.
- Initialize the repo. Open a terminal in your WPILib project folder and run
git init. Then rungit status. You should see every project file listed as untracked. Note how many files appear — this is why the next step matters. - Verify your .gitignore. Check whether a
.gitignorealready exists in your project root (WPILib creates one). Open it and confirmbuild/and.gradle/are present. If they're missing, add them. Rungit statusagain —build/should no longer appear in the untracked list. - Stage the right files. Run
git add src/ build.gradle settings.gradle gradlew gradlew.bat .gitignore. Then rungit statusand confirm only source files and project configuration files are staged — not build output directories. - Make your first commit. Write a commit message that follows the Conventional Commits format:
git commit -m "chore: initial WPILib project setup". Rungit log --onelineto confirm the commit appears. - Connect to GitHub. Create a new repository on GitHub (do not initialize with a README — you already have commits). Follow GitHub's instructions to add the remote and push:
git remote add origin <your-url>followed bygit push -u origin main. - Make a meaningful second commit. Open
Robot.javaand add a comment with your team number, the season year, and your name. Stage it, write a proper commit message (docs(robot): add team attribution header), and push. Verify it appears on GitHub. - Practice the log. Run
git log --oneline. You should see two commits. Practice runninggit diff <sha1> <sha2>between your two commits. Identify which lines changed. - Bonus: Ask a teammate to clone your repo, add a comment to a different file, commit with a proper message, and push. Then pull their change. Observe what
git log --onelineshows afterward — whose commit comes first, and why?