Git for SVN veterans: a survival guide
0. The only mental model you need
- SVN: one central timeline of revisions (r12345) on the server.
- Git: commits form a DAG on your machine. A branch is just a movable name pointing at a commit.
- A commit is a snapshot of the whole tree (not a per-file delta).
- 3 places changes can live:
- Working tree — your files on disk
- Index / staging area — what the next commit will record
- Commit history — recorded snapshots
+-------------+ git add +-------------+ git commit +------------+
| working | -----------> | index | -----------> | commits |
| tree | | (staging) | | (history) |
+-------------+ +-------------+ +------------+
^ |
| git restore FILE |
+<-------------------------------------------------------+
git restore --staged FILE
(unstages, keeps your edits)
Rule: when confused, run:
git status
git log --oneline --graph --decorate --all
1. The 20% of commands you will use 80% of the time
In the examples below, <path> means the actual file or directory name (e.g. src/foo.c),
<branch> means a branch name (e.g. main), and <commit> means a commit hash (e.g. a1b2c3d).
Inspect:
git status # your compass
git diff # unstaged changes
git diff --staged # what will be committed
git log --oneline --graph --decorate --all # commit graph
git blame FILE # who changed each line
Stage and commit:
git add <path> # stage changes
git commit -m "msg" # local snapshot
Branches:
git switch <branch> # switch to existing branch
git switch -c <new-branch> # create + switch
git branch # list branches
git branch -d <branch> # delete a merged branch
git merge <branch> # integrate branch
Sync with remote:
git fetch # download (safe, read-only)
git pull # fetch + rebase
git push # upload
Undo (safe defaults):
git restore <path> # discard unstaged edits
git restore --staged <path> # unstage (keeps edits)
git revert <commit> # undo via new commit (safe)
2. SVN → Git translation (roughly)
Checkout and update:
svn checkout URL -> git clone URL
svn update -> git pull
(safer: git fetch; inspect; then merge)
Status and diffs:
svn status -> git status
svn diff -> git diff
History:
svn log -> git log
svn blame FILE -> git blame FILE
Branches:
svn copy trunk branches/x -> git switch -c x
svn switch x -> git switch x
Merging:
svn merge -> git merge (or git rebase, see §6)
Undo:
svn revert FILE -> git restore FILE
svn merge -c -REV -> git revert <commit>
Key differences at a glance:
| Concept | SVN | Git |
|---|---|---|
| Repository | Central server database | Local .git folder (full clone) |
| Commit | Network upload | Local snapshot |
| Publish | (same as commit) | git push (separate step) |
| Revision ID | r1024 (sequential integer) |
a1b2c3d (SHA-1 hash) |
| Branch | Directory copy — O(N) | Pointer creation — O(1) |
3. The biggest gotcha: git commit is local
- In SVN, “commit” publishes to the shared server.
- In Git, “commit” records locally. Sharing happens with
git push.
Rule of thumb:
- Commit often locally (small, logical steps).
- Push when you want others to see your work.
4. Where did r12345 go?
SVN identifies commits by sequential integers: r12345.
Git identifies commits by SHA-1 hashes: a1b2c3d4e5f6...
What you use instead:
git log --oneline # shows: a1b2c3d Fix overflow in foo.c
git show a1b2c3d # full details of a commit
git log -S "search_string" # commits that added/removed this string
git log --grep="keyword" # commits whose message matches
git blame FILE # who last changed each line
If you need stable names for milestones:
git tag v2.1.0 # lightweight tag
git tag -a v2.1.0 -m "msg" # annotated tag (recommended)
5. Branches are cheap (and you should use them)
Branch workflow:
git switch -c feature-x
# ... edit, add, commit ...
git switch main
git merge feature-x
Key idea: branches are names/pointers, not server directories. Creating a branch costs almost nothing. Deleting a branch only removes the label; the commits remain until garbage-collected.
Publishing a branch: new branches only exist on your machine until you push:
git push -u origin feature-x # publish branch and set up tracking
git push # subsequent pushes just work
6. Merge vs rebase (simple policy)
On day 1, just use merge. You can learn rebase later when you need it.
- merge: preserves the true branch structure (adds a merge commit).
- rebase: replays your commits on top of a new base (creates new commit hashes).
Safe beginner policy:
- Use merge when integrating shared work.
- Rebase only your own unpublished branch to clean it up.
- Never rebase commits that others already pulled.
Rebasing a branch onto the latest main:
git fetch
git rebase origin/main # replay your work on latest main
git push
Note: pull.rebase true (see §13) makes git pull do this automatically. That is safe because it only replays your unpushed commits.
7. Resolving merge conflicts
When two branches modify the same lines, Git cannot merge automatically. It marks the conflicting sections in the file:
<<<<<<< HEAD
Line 1 (main version)
=======
Line 1 (branch version)
>>>>>>> topic
- Everything between
<<<<<<<and=======is your current branch - Everything between
=======and>>>>>>>is the incoming branch
To resolve:
- Open the file in your editor
- Delete the marker lines (
<<<<<<<,=======,>>>>>>>) - Keep the text you want (or combine both)
- Stage and commit:
git add FILE
git commit -m "Resolve conflict in FILE"
Check the state at any time:
git status # shows "both modified" for conflicted files
Conflicts are less common than people fear. Git auto-merges successfully most of the time.
8. Remotes: fetch vs pull vs push
Your repo Remote (e.g. GitHub)
+-----------+ git push +-----------+
| main |------------------->| main |
| | | |
| origin/ |<--- git fetch ----| |
| main | +-----------+
+-----------+
git pull = git fetch + git rebase (with pull.rebase true)
origin/mainis your local record of where the remote’s main was at last fetch. It updates only on fetch (or pull).
Safe sync habit:
git fetch
git log --oneline --graph --decorate --all # inspect
git merge origin/main # or: git pull
git push
9. Undo cookbook (triage)
A) “I edited a file, regret it” (not staged):
git restore <path>
B) “I staged the wrong thing”:
git restore --staged <path>
C) “I committed something bad, but it is already shared”:
git revert <commit> # creates a new undo-commit (safe)
D) “I committed something bad, not shared yet” (power tool):
HEAD~1 means “one commit before where I am now.”
git reset --soft HEAD~1 # undo last commit, keep changes staged
git reset --mixed HEAD~1 # undo last commit, keep changes unstaged
git reset --hard HEAD~1 # undo last commit, DISCARD changes
WARNING:
resetandrebaserewrite history. If others have pulled your commits, usegit revertinstead. Never force-push to a shared branch unless your team explicitly agrees to it.
E) “I need to switch branches but have uncommitted work”:
git stash # shelve your changes
git switch other-branch # do your work there
git switch - # switch back
git stash pop # restore your changes
10. .gitignore (set up early)
Create a .gitignore in your repo root. Git will skip matching files.
Starter for C projects:
# Compiled objects and libraries
*.o
*.so
*.a
*.dylib
# Build directories
build/
_build/
# Editor swap/backup files
*~
*.swp
.*.swp
# OS metadata
.DS_Store
git add .gitignore
git commit -m "Add .gitignore"
Important: .gitignore only affects files that Git is not already tracking. If you have already committed .o files, adding *.o to .gitignore will not remove them. To stop tracking a file that was already committed:
git rm --cached file.o # remove from Git's tracking, keep the file on disk
git commit -m "Stop tracking file.o"
11. Tip for LaTeX collaboration: semantic linefeeds
Git tracks changes by line. In LaTeX, one sentence per line makes diffs and merges much cleaner:
% Hard to review (Git sees 1 changed line for the whole paragraph)
Let $f$ be a function. It is continuous. We show that it is bounded.
% Easy to review (Git sees exactly which sentence changed)
Let $f$ be a function.
It is continuous.
We show that it is bounded.
- Merge conflicts drop dramatically.
git blameshows who wrote each sentence.- PDF output is identical (LaTeX ignores single newlines).
12. Common SVN-to-Git pitfalls
- Treating commit as publish — it is not.
- Ignoring the index — staging exists and is useful.
- Fear of branches — in Git, branches are the normal unit of work.
- Rewriting shared history — avoid unless your team has a clear protocol.
- Expecting revision numbers — Git uses commit hashes; use tags for named milestones.
- Forgetting .gitignore — compiled objects pollute the repo fast.
- Using
git add .orgit commit -a— these stage everything, including build artifacts, editor backups, and temporary files. Alwaysgit addspecific files by name.
13. Minimal recommended config
--global means “apply to all repos on this machine.” Without it, the setting applies only to the current repo.
git config --global user.name "Your Name"
git config --global user.email "you@example.com"
git config --global pull.rebase true # pull replays your unpushed commits on top (linear history)
git config --global fetch.prune true # auto-remove local refs to deleted remote branches
git config --global init.defaultBranch main # new repos start with branch "main"
Optional but handy alias:
git config --global alias.lg "log --oneline --graph --decorate --all"
# then use: git lg
14. Common error messages
“fatal: not a git repository”
- You are not inside a git repo. Run
git initorcdto the right directory.
“error: Your local changes would be overwritten”
- You have uncommitted changes that would conflict. Commit them first, or temporarily shelve them with
git stash(retrieve later withgit stash pop).
“CONFLICT (content): Merge conflict in FILE”
- Both branches modified the same lines. Edit the file, remove markers,
git add,git commit. See §7.
”! [rejected] main -> main (non-fast-forward)”
- Remote has commits you do not have. Run
git pullfirst, thengit push.
“fatal: refusing to merge unrelated histories”
- Two repos with no common ancestor. Usually means you cloned the wrong thing. Add
--allow-unrelated-historiesonly if you are sure.
“You are in ‘detached HEAD’ state”
- HEAD points to a commit, not a branch. Create a branch to keep your work:
git switch -c new-branch
15. If you remember only 5 things
git statusis your compass.- Commit is local, push is sharing.
- Branches are cheap pointers — use them.
- The staging area lets you choose what the next commit contains.
- For shared history, prefer
git revertover rewriting.
Resources
Official:
For mathematicians:
Tutorials:
When things go wrong:
- Oh Shit, Git!?! — plain-English recipes for common Git mistakes