Git Reference
Volume 1 — Core Developer Skills
Git is the version control system behind every Traxs repo. This chapter covers the mental model, the day-to-day commands, and the branch/PR workflow used across RoundTrip, Waypoint, and Relay. Read it top to bottom once, then use it as a lookup afterward.
1. The Three-State Model
Everything in Git makes more sense once you internalize that a file moves through three states:
- Working directory — the files on disk as you're editing them.
- Staging area (the "index") — a holding area where you build up exactly what the next commit will contain.
- Repository — the committed history stored in
.git.
git add doesn't save anything permanently — it just marks a change as "include this in the next commit." This is why you can git add half a file's changes and leave the rest for a later commit.
2. Configuring Git
git config --global user.name "Pete Carroll"
git config --global user.email "pete@traxsgroup.com"
git config --global init.defaultBranch main
git config --global core.editor "code --wait"
git config --list # show all effective settings
git config --list --show-origin # show which file each setting came from
--global applies to every repo on the machine; drop it (just git config user.email "...") to override for a single repo — useful if a repo needs a different identity.
3. Starting a Repository
git init # start a new repo in the current directory
git clone https://github.com/Traxs-dev/RoundTripAPI.git # copy an existing remote repo
git clone git@github.com:Traxs-dev/RoundTripAPI.git # same, over SSH instead of HTTPS
HTTPS clones prompt for credentials (or a token) on push; SSH clones use your SSH key (see the SSH & Key Management chapter) and don't prompt at all once your key is set up.
4. The Basic Workflow
git status # what's changed, what's staged, what branch you're on
git add file1.cs file2.cs # stage specific files
git add . # stage everything changed in and below the current directory
git add -p # interactively choose which hunks to stage — useful when one file has two unrelated changes
git commit -m "Add leave request validation"
git push # push the current branch to its remote
git pull # fetch and merge the latest from the remote
git status is the command you should run before and after almost every other Git command until the three-state model is second nature — it always tells you exactly where you stand.
5. Branching
git branch # list local branches, * marks the current one
git branch -a # list local and remote branches
git branch feature/WAY-41-example # create a branch without switching to it
git switch feature/WAY-41-example # switch to it (modern syntax)
git checkout feature/WAY-41-example # switch to it (classic syntax, still everywhere)
git switch -c feature/WAY-41-example # create and switch in one step (modern)
git checkout -b feature/WAY-41-example # create and switch in one step (classic)
git branch -d feature/WAY-41-example # delete a branch (only if merged)
git branch -D feature/WAY-41-example # force-delete a branch (even if unmerged)
switch and restore are newer, narrower replacements for the overloaded checkout command — both do the same job, use whichever your muscle memory prefers. This handbook uses both interchangeably since you'll see both in the wild.
6. Merging
git switch main
git merge feature/WAY-41-example
Two outcomes:
- Fast-forward — if
mainhasn't moved since the branch was created, Git just moves the pointer forward. No merge commit, linear history. - Three-way merge — if both branches have diverged, Git creates a merge commit with two parents.
Resolving a merge conflict
git merge feature/WAY-41-example
# CONFLICT (content): Merge conflict in LeaveRequestHandler.cs
Open the file — Git marks the conflicting section:
<<<<<<< HEAD
current code from the branch you're on
=======
incoming code from the branch being merged
>>>>>>> feature/WAY-41-example
Edit the file to the correct final version, remove the <<<<<<</=======/>>>>>>> markers, then:
git add LeaveRequestHandler.cs
git commit
git status during a conflict always lists exactly which files still need resolving — trust it over trying to remember.
7. Rebasing
Rebasing replays your branch's commits on top of another branch instead of merging the two histories together, producing a linear history with no merge commit.
git switch feature/WAY-41-example
git rebase main
If a commit conflicts during rebase:
# fix the conflicting file
git add file.cs
git rebase --continue
# or, to back out entirely:
git rebase --abort
Merge vs. rebase — when to use which:
| Situation | Use |
|---|---|
Bringing your feature branch up to date with main before opening a PR | rebase — keeps history linear and easy to read |
Combining a completed feature branch back into main | merge (often via a PR's "squash and merge" or "merge commit" button) |
| The branch has already been pushed and others are working off it | merge, never rebase — rebasing rewrites commit hashes and breaks anyone who's already pulled |
Rule of thumb: never rebase a branch that's already been pushed and shared. Rebase freely on a branch that's still local-only or that only you are working on.
Interactive rebase (cleaning up commits before a PR)
git rebase -i HEAD~3 # interactively edit the last 3 commits
Opens an editor listing the commits with an action per line (pick, reword, squash, drop, ...). Reordering lines reorders commits; changing pick to squash folds a commit into the one above it — useful for turning a messy string of "wip", "fix typo", "actually fix it" commits into one clean commit before a PR.
8. Remotes
git remote -v # list remotes and their URLs
git remote add origin git@github.com:Traxs-dev/RoundTripAPI.git
git remote set-url origin git@github.com:Traxs-dev/RoundTripAPI.git # change an existing remote's URL
git fetch # download remote changes without merging them
git fetch origin # fetch from a specific remote
git pull # fetch + merge in one step
git push -u origin feature/WAY-41-example # push and set the upstream tracking branch (only needed the first time)
git push # after -u has been set once, plain push/pull work without arguments
fetch is the safe one — it updates your local view of the remote without touching your working files. pull is fetch + merge, so it does touch your working files. If you want to look before you leap, fetch then git log main..origin/main to see what's incoming before merging.
9. Viewing History
git log # full commit history
git log --oneline # one line per commit
git log --oneline --graph --all # visual branch graph, all branches
git log -p file.cs # history of a specific file, with diffs
git show <commit-hash> # full details of one commit
git diff # unstaged changes vs. the last commit
git diff --staged # staged changes vs. the last commit
git diff main..feature/WAY-41-example # everything different between two branches
git blame file.cs # who last changed each line, and in which commit
git blame is not about assigning fault — it's the fastest way to find the commit (and its message/ticket) that introduced a specific line, so you can go read the reasoning behind it.
10. Undoing Changes
This is the section worth bookmarking — it covers the difference between commands that are safe and commands that discard work.
git restore file.cs # discard uncommitted changes to a file (safe: only affects working directory)
git restore --staged file.cs # unstage a file, keep the edits (safe)
git checkout -- file.cs # classic-syntax equivalent of git restore file.cs
git commit --amend -m "Corrected message" # rewrite the most recent commit's message or contents
git commit --amend --no-edit # add currently staged changes to the last commit without changing its message
git reset --soft HEAD~1 # undo the last commit, keep changes staged
git reset --mixed HEAD~1 # undo the last commit, keep changes unstaged (default mode)
git reset --hard HEAD~1 # undo the last commit AND discard the changes entirely
git revert <commit-hash> # create a NEW commit that undoes a previous commit — safe for shared/pushed history
reset vs. revert: reset --hard rewrites history and destroys the commits it removes — only use it on local, unpushed commits. revert adds a new commit on top that undoes an earlier one, leaving history intact — this is the correct tool once something has already been pushed or merged into main.
11. Stashing
Stashing sets aside uncommitted work temporarily, without committing it — useful when you need to switch branches but aren't ready to commit.
git stash # stash all uncommitted changes
git stash push -m "WIP: leave balance calc" # stash with a descriptive label
git stash list # see all stashes
git stash pop # reapply the most recent stash and remove it from the stash list
git stash apply # reapply the most recent stash but keep it in the stash list
git stash drop # delete a stash without applying it
12. Tags
git tag v1.4.0 # lightweight tag on the current commit
git tag -a v1.4.0 -m "M14 billing release" # annotated tag — stores author, date, and message; preferred for releases
git push origin v1.4.0 # tags don't push automatically — push them explicitly
git push origin --tags # push all tags at once
git tag -l "v1.4.*" # list tags matching a pattern
Use annotated tags (-a) for anything marking an actual release — they carry metadata a lightweight tag doesn't.
13. .gitignore
.gitignore tells Git which files to never track — build output, secrets, local settings.
bin/
obj/
node_modules/
.env
appsettings.Development.json
*.user
.DS_Store
If a file is already tracked, adding it to .gitignore won't stop tracking it — untrack it explicitly first:
git rm --cached appsettings.Development.json
Then commit that removal. The file stays on disk; Git just stops watching it.
14. Useful Aliases
Add these to ~/.gitconfig (or run each as a git config --global alias.X "..." command) to shorten commands you'll type constantly:
git config --global alias.st status
git config --global alias.co checkout
git config --global alias.br branch
git config --global alias.lg "log --oneline --graph --all"
git config --global alias.last "log -1 HEAD"
git config --global alias.unstage "restore --staged"
After this, git lg gives you the full visual branch graph without typing the flags every time.
15. The Traxs Branch and PR Workflow
This is the actual pattern used across RoundTrip and Waypoint:
git switch main
git pull
git switch -c feature/WAY-41-endpoint-authorization
# ... make changes, commit as you go ...
git push -u origin feature/WAY-41-endpoint-authorization
Then open a PR into main. A few rules that keep this workflow clean:
- Branch naming:
feature/WAY-NNN-short-descriptionfor Waypoint work,feature/TRA-NNN-short-descriptionfor RoundTrip or cross-product work — the ticket ID makes it trivial to trace a branch back to Linear. - One PR at a time: PRs are merged sequentially, not in parallel, to avoid stacking conflicting changes against a moving
main. - Rebase before opening the PR, not after — if
mainhas moved since you branched,git rebase mainon your feature branch keeps the diff clean and avoids a noisy merge commit. - After merge: the pipeline deploys from
mainautomatically. Mark the Linear ticket Done only after production verification, not just after the merge lands.
16. Troubleshooting Playbook
| Symptom | Likely cause | What to do |
|---|---|---|
fatal: not a git repository | You're not inside a repo directory, or .git got deleted | cd into the correct directory; confirm with git status |
Your branch is ahead/behind 'origin/main' by N commits | Local and remote have diverged | git pull to bring them together; git push if you're only ahead |
| Merge conflict markers left in a file after resolving | Forgot to remove <<<<<<</=======/>>>>>>> before committing | Search the file for <<<<<<< before staging; re-edit and re-add |
Accidentally committed to main directly | Working on the wrong branch | If unpushed: git branch feature/xyz then git reset --hard origin/main on main to move the commit onto the new branch. If pushed: coordinate before rewriting shared history |
git push rejected: "fetch first" | Remote has commits you don't have locally | git pull (or git fetch + git merge/rebase) before pushing again |
| Rebase conflict, unsure how to proceed | Mid-rebase state is unfamiliar | git rebase --abort returns you to the pre-rebase state with zero risk; then retry more carefully |
| Committed a secret (API key, connection string) | Staged and committed before noticing | Rotate the credential immediately — removing it from a later commit does not remove it from history. Treat any committed secret as compromised. |
| Detached HEAD state | Checked out a commit hash or tag directly instead of a branch | git switch -c temp-branch-name to save your place, or git switch main to abandon it if you made no changes |
| Large file won't push, remote rejects it | File exceeds the host's size limit | Remove it from the commit; use Git LFS or external storage (Azure Blob) for large binaries instead |
17. Quick Reference
| Category | Command | What it does |
|---|---|---|
| Status | git status | What's changed and staged |
| Staging | git add -p | Stage selected hunks interactively |
| Commit | git commit --amend --no-edit | Add staged changes to the last commit |
| Branching | git switch -c name | Create and switch to a new branch |
| Merging | git merge branch | Merge a branch into the current one |
| Rebasing | git rebase main | Replay current branch on top of main |
| Rebasing | git rebase -i HEAD~3 | Interactively edit the last 3 commits |
| Remotes | git fetch | Download remote changes without merging |
| Remotes | git push -u origin branch | Push and set upstream tracking |
| History | git log --oneline --graph --all | Visual history of all branches |
| History | git blame file | Who last changed each line |
| Undo | git restore file | Discard uncommitted changes (safe) |
| Undo | git reset --hard HEAD~1 | Discard the last commit entirely (local only) |
| Undo | git revert <hash> | Safely undo a pushed commit with a new commit |
| Stash | git stash pop | Reapply and remove the latest stash |
| Tags | git tag -a v1.0 -m "msg" | Create an annotated release tag |
Part of the Traxs Engineering Handbook — Volume 1: Core Developer Skills. Companion chapters in this volume: Bash Reference, Git Troubleshooting, SSH & Key Management.