Git without fear: commit, branch, remote explained, then the commands that save you
Code6 min read · 27 September 2026
You messed something up with Git. A commit on the wrong file, a file deleted by mistake, or the word “CONFLICT” showing up in your terminal with no idea what to do next. First thing to know: Git almost never actually deletes anything, even when it looks scary. Everything you’ve committed lives somewhere, recoverable. This article covers the three basic concepts, then the commands that get you out of the most common situations, all verified against Git’s official documentation.
Three words to understand Git
A commit is a snapshot of your project at a given moment: every file, exactly as it was when you saved. A branch is just a name pointing at a commit; when you add a new commit, that pointer moves forward automatically. A remote (usually named origin) is a copy of your repository hosted elsewhere, typically on GitHub: it’s what you sync with through git push and git pull.
Until you run git push, everything you do stays local, on your machine. That matters: most of the troubleshooting commands below only touch your local history, with zero risk for anyone else.
Undoing your last commit without losing your work
You committed too early, or with a messy message. Here’s the command:
git reset HEAD~1
HEAD~1 means “the commit right before the one you’re on.” By default, git reset runs in --mixed mode: it moves the branch pointer back, but leaves your working directory untouched. In practice, your commit disappears, but the content you had committed ends up back as unstaged changes, ready to be committed properly.
If you genuinely want to throw away the changes too (not just the commit), there’s git reset --hard HEAD~1. Be careful with --hard: it overwrites your working directory files to match the target commit, and tracked files that didn’t exist at that commit get removed. The official documentation is blunt about where the line is: never do this if you’ve already shared those commits with somebody else (in other words, if you’ve already pushed them to a remote other people use).
Local safety net: before every reset, Git automatically records where you were in a special reference called ORIG_HEAD, so you can back out if you ran the wrong command.
Recovering a file you broke or deleted by mistake
To restore a single file to its last-committed state, without touching anything else:
git restore path/to/file
By default, git restore restores the file from the index (whatever you already staged with git add), or from HEAD if you add --staged. You can also reach further back in history with the --source option:
git restore --source=HEAD~2 path/to/file
That brings the file back to how it looked two commits ago, without changing anything else in your project. It’s the safest tool when you want to undo changes to one specific file without touching your commit history.
Resolving a conflict without panicking
A conflict happens when Git merges two histories that changed the same lines differently (typically during a git merge or a git pull). Git opens the affected file and drops in markers:
<<<<<<< HEAD
# My Project
=======
# My Awesome Project
>>>>>>> feature-readme
Everything between <<<<<<< HEAD and ======= is your current version; everything between ======= and >>>>>>> feature-readme comes from the other branch. There’s no mystery to it: open the file, decide what to keep (one version, both, or a rewrite), then delete the three marker lines entirely. Once the file is clean, mark it as resolved and finish the merge:
git add path/to/file
git commit
If you want to check, at any point, which files still have unresolved conflicts, git status lists them under “both modified.”
Putting work aside without losing it: git stash
You’re mid-edit on some files but need to switch branches for something urgent, and you’re not ready to commit. git stash saves your local changes aside and resets your working directory to the last commit. Once the urgent thing is handled, you can bring them back:
git stash list
git stash pop
git stash list shows everything you’ve stashed, with the most recent as stash@{0}. git stash pop reapplies the latest one and removes it from the list. If you’d rather keep a copy in the stash just in case, use git stash apply instead: it reapplies the changes without deleting them from the stash.
The ultimate safety net: git reflog
Even after an overly hasty reset --hard, not everything is lost locally. Git keeps a log of every move HEAD makes on your machine, called the reflog:
git reflog
Each line corresponds to a state HEAD passed through, with a reference like HEAD@{2} (“where HEAD was two moves ago”). Once you’ve spotted the line right before your mistake, you can jump back to it:
git reset --hard HEAD@{2}
The reflog is local to your machine and isn’t shared with the remote: it’s your personal spare wheel, not to be confused with the history everyone else can see.
Switching branches cleanly: git switch
To move from one branch to another, the modern, unambiguous command is git switch:
git switch branch-name
To create a new branch and move onto it in a single command:
git switch -c new-branch
git switch was introduced to take over, specifically, from the older git checkout, which used to handle both switching branches and restoring files — two different jobs mixed into one command, and a common source of confusion. Today, git switch handles branches and git restore handles files, each with one clear job.
What you should never do: force-pushing a shared branch without knowing why
Here’s the single most important rule in this article. When you run git push, Git normally refuses to overwrite the remote history if your local history isn’t a direct continuation of it. The --force flag disables that protection. The concrete risk, spelled out in the official documentation: if you and somebody else both started from the same commit, and that person already pushed their own commits, a --force push from you can wipe their commits off the remote, because everyone now starts building on top of your version instead.
In practice: never run git push --force on a branch other people use, unless you know exactly what you’re doing and you’ve told them first. On a branch that’s entirely yours (say, your own feature branch nobody else has pulled), it’s harmless. If you do need to force-push a shared branch for a good reason (a coordinated rebase, for instance), prefer --force-with-lease: it checks that nobody has pushed new commits since your last sync before overwriting anything, which keeps you from accidentally erasing someone else’s work.
Key takeaways
- Commit = a snapshot of your project; branch = a movable pointer; remote = a copy hosted elsewhere (
origin). - Undo the last commit while keeping the changes:
git reset HEAD~1. - Restore one specific file:
git restore path/to/file(or--source=HEAD~2to go further back). - Resolve a conflict by editing the file, removing the
<<<<<<</=======/>>>>>>>markers, thengit add+git commit. - Stash without losing anything:
git stash, thengit stash poporgit stash list. - The local safety net:
git reflog, thengit reset --hard HEAD@{n}. - Switch branches:
git switch branch-name(or-cto create one). - Never run
git push --forceon a shared branch without being sure and without telling people;--force-with-leaseis safer.
Sources
- git-reset Documentation — git-scm.com · accessed 27 September 2026
- git-restore Documentation — git-scm.com · accessed 27 September 2026
- git-stash Documentation — git-scm.com · accessed 27 September 2026
- git-reflog Documentation — git-scm.com · accessed 27 September 2026
- git-push Documentation — git-scm.com · accessed 27 September 2026
- Pro Git — Basic Branching and Merging — git-scm.com · accessed 27 September 2026






