April 28, 2025
For a very simple “go back to the last known good state” workflow, you have two easy options:
# 1. Keep a stable branch (or tag) and work on a feature branch
-
When your code is working, make sure it’s on
main
(or another branch you call “stable”):git checkout main # ...confirm everything here is a clean, working version... git pull origin main
-
Create a new branch for your experiments:
git checkout -b feature/experiment
Now you can code and commit however you like on
feature/experiment
. If you break something:-
To abandon the experiment entirely, just switch back to
main
(which still holds the last stable commit):git checkout main
-
If you want to start that feature branch over from scratch, you can delete it and re-create it:
git branch -D feature/experiment git checkout -b feature/experiment
Meanwhile,
main
always stays at your last stable code. When your feature is ready, you can merge it back (or rebase) ontomain
. -
# 2. Tag each stable commit and checkout the tag when needed
If you prefer to stay on main
(or another single branch) and just mark exact commits:
-
After you’ve made a commit that you know is fully working, tag it:
git tag stable-v1.0
-
Keep committing on
main
as you experiment. If you break something and want to return to that tagged state:git checkout stable-v1.0
(⚠️ You’ll be in a “detached HEAD” at that point. If you want to resume normal work from there, make a new branch first, e.g.:)
git checkout -b rollback-and-fix
-
When you’re ready to get back to the latest tip of
main
, just:git checkout main
# Why branching (option 1) is usually the simplest
main
always points at your last stable code. You never have to remember SHA-1 hashes.- You can freely experiment in a feature branch, commit as often as you like, and if nothing works, you simply drop that branch and return to
main
. - No detached-HEAD states, no risk of accidentally losing work (assuming you pushed your branches to origin or at least committed locally).
# Quick commands for “I just messed up—restore to last commit”:
If you’ve already committed something on main
and then realize “Ugh, that commit breaks everything,” you can do:
git reset --hard HEAD~1
That force-moves main
one commit back (discarding the broken commit). But be careful—anything only in that last commit is gone unless you saved it elsewhere.
Summary
- Easiest long-term: Keep
main
(or astable
branch) as your always-working copy. Create a new branch for each experiment. - Tag-and-checkout: Tag every stable point (e.g.
git tag stable-v1.0
), thengit checkout stable-v1.0
to revert. But remember that puts you in detached HEAD.
Most people find the “branch for experiments, keep main
pristine” workflow the most straightforward for frequently jumping back to a known good version.
# Merge in new feature branch into main
To merge a feature branch into your main (or any target) branch, you can do something like this:
-
Make sure your work is committed on the feature branch
git status # (should show no uncommitted changes; if there are, stage & commit them) git add . git commit -m "Finish work on my-feature-branch"
-
Switch to the target branch (e.g.,
main
)git checkout main
-
Update
main
from the remote (if you have one)git pull origin main
This ensures you’re merging into the latest copy of
main
. -
Merge your feature branch into
main
git merge my-feature-branch
-
If there are no conflicts, Git will fast-forward or create a merge commit automatically.
-
If you see a conflict message, open the conflicted files, resolve them, then do:
git add <file-you-fixed> git commit
(Git will prompt you to confirm the merge commit message.)
-
-
Push the updated
main
back to the remotegit push origin main
-
(Optional) Delete the now-merged feature branch Locally:
git branch -d my-feature-branch
On the remote (if you pushed it there earlier):
git push origin --delete my-feature-branch
If you’re working solo, you don’t need a pull request—just merge locally and push.