Git’s error messages are precise, complete, and written for somebody who already understands the model. That combination makes them ideal input for an assistant and makes the situation dangerous: the person asking is, by definition, the person who does not know what is happening.
This is the article in the cluster where a wrong answer can destroy work. It is built around one rule, and the rest is detail.
Supply these five things
Section titled “Supply these five things”The difference between a useful answer and a dangerous guess is entirely in the input. Every time:
- The command you ran. Exactly, including flags.
- The complete output. Not “it failed” — the actual text, including the hints.
git status. The current state.- Your branch state.
git log --oneline -5andgit branch -vv. - What you were trying to achieve. The intended end state, not the command you thought would get there.
The fifth is the one people omit and the one that most changes the answer. “I ran git reset and my
changes are gone” has several different remedies depending on whether you wanted to undo a commit,
unstage a file, or discard local edits — and the output alone does not say which.
git branch -vvWhat it doesPrints the branch, its upstream tracking relationship, and how far ahead or behind it is.
Why we run itMost push and pull confusion is a tracking or divergence problem, and this is the one command that shows it.
Expected resultA line per branch: name, short hash, upstream in brackets with ahead/behind counts, and the last commit subject.
Read the hints
Section titled “Read the hints”Git’s error messages usually contain the answer. A rejected push, in full:
To /path/to/upstream.git ! [rejected] main -> main (non-fast-forward)error: failed to push some refs to '/path/to/upstream.git'hint: Updates were rejected because the tip of your current branch is behindhint: its remote counterpart. If you want to integrate the remote changes,hint: use 'git pull' before pushing again.hint: See the 'Note about fast-forwards' in 'git push --help' for details.Four lines of hint: explaining the cause and the remedy. Pasting only ! [rejected] throws away
most of the information — and a model given only that fragment will produce a generic answer covering
several causes, of which yours is one.
Paste the whole thing. It costs nothing and it is the difference between a diagnosis and a list of possibilities.
The problems, and what makes each safe
Section titled “The problems, and what makes each safe”Detached HEAD
Section titled “Detached HEAD”The most common confusing state and among the least dangerous.
You are in 'detached HEAD' state. You can look around, make experimentalchanges and commit them, and you can discard any commits you make in thisstate without impacting any branches by switching back to a branch.$ git statusHEAD detached at d25ae62nothing to commit, working tree cleanWhat it means. HEAD points at a commit rather than a branch. Nothing is broken; commits you make here belong to no branch and become unreachable when you leave.
Safe resolution. If you made no commits, git switch - returns you. If you did, create a branch
first: git switch -c recovery-branch. Both are non-destructive.
Where AI helps. Explaining what happened and which of the two you are in.
Where to be careful. A suggestion to git checkout main while you have uncommitted work in a
detached state — check git status first.
Rejected push
Section titled “Rejected push”What it means. Read the hints. non-fast-forward means the remote has commits you do not.
Safe resolution. git pull --rebase or git pull, then push. Which depends on your team’s
history policy — see rebase vs merge.
The dangerous suggestion. git push --force. It resolves the error by overwriting whatever is on
the remote, including a colleague’s work.
If you genuinely need to force — after an intentional rebase of your own branch — use the safer form:
git push --force-with-leaseThis refuses if the remote has moved since you last fetched, which is exactly the case where
--force destroys somebody’s work.
“My commits are gone”
Section titled ““My commits are gone””Almost always false, and the reflog is why.
git reflogWhat it doesShows every position HEAD has occupied in this repository, most recent first.
Why we run itA commit is unreachable, not deleted. The reflog records where HEAD has been, which is how you find it again.
Expected resultOne line per movement: hash, HEAD@{n}, the action and its description.
Real output from a repository where somebody checked out a previous commit and came back:
01cad27 HEAD@{0}: checkout: moving from d25ae62c897b0f83df6715086f40e81d00264ab0 to maind25ae62 HEAD@{1}: checkout: moving from main to HEAD~101cad27 HEAD@{2}: commit: twod25ae62 HEAD@{3}: commit (initial): oneEvery state HEAD has been in, with hashes. Recovery is git switch -c recovered <hash> — creating a
branch, which is non-destructive and reversible.
This is the highest-value AI interaction in the whole article. Reflog output is dense and unfamiliar; asking “which of these is the state before I ran the reset?” is a reading question with a checkable answer, and the recovery command it leads to creates rather than destroys.
Note the limit: the reflog is local and expires. It does not help with something that was never in your repository.
Rebase or merge conflicts mid-operation
Section titled “Rebase or merge conflicts mid-operation”What it means. Git stopped partway and is waiting.
git statustells you which operation is in progress and what it wants. Every one of them has an abort:
git rebase --abortgit merge --abortgit cherry-pick --abortThe safe default when confused is to abort. It returns you to where you started. Ask questions from a clean state rather than from halfway through an operation you do not understand.
See merge conflict resolution for resolving rather than aborting,
including the rebase inversion that makes --ours and --theirs mean the opposite of what you expect.
Wrong branch
Section titled “Wrong branch”Committed to main instead of a feature branch. Common, and entirely recoverable.
The safe shape: create the branch you meant to be on at the current commit, then move main back.
git switch -c feature/my-workgit switch maingit reset --hard origin/mainThe second command is destructive to local main and safe here only because origin/main is the
state you want and your work is now on feature/my-work. That conditional is exactly the kind of
thing to confirm before running — and exactly what a suggested command will not state.
Authentication failures
Section titled “Authentication failures”fatal: Could not read from remote repository.
Please make sure you have the correct access rightsWhat it means. Ambiguous by design — wrong credentials, no credentials, no access, or the repository does not exist.
Where AI helps. Narrowing it, given git remote -v and whether you are on SSH or HTTPS.
Where to be careful. Suggestions to change your credential configuration. See Git credentials and SSH keys — and never paste a token or a private key into a chat while debugging.
Confusing status output
Section titled “Confusing status output”Not an error, and a frequent source of “what is Git telling me”.
git statusThe states that confuse people, and what each means:
| Status says | Means |
|---|---|
Changes not staged for commit | Modified in the working tree, not added |
Changes to be committed | Staged; the next commit includes these |
Untracked files | Git has never seen these |
Your branch is ahead of 'origin/main' by 2 commits | You have commits to push |
Your branch and 'origin/main' have diverged | Both moved; you need to merge or rebase |
both modified / UU | An unresolved conflict |
HEAD detached at <hash> | Not on a branch |
Pasting git status and asking “what does this mean, and what are my options?” is a genuinely good
use of AI — it is a reading-comprehension question about unfamiliar output with a checkable answer, and
the answer names the state rather than proposing a change.
The follow-up that keeps it safe: ask for the options and their consequences rather than for the command to run.
Large or slow repository operations
Section titled “Large or slow repository operations”Occasionally the problem is not an error but a repository behaving badly — a clone that takes twenty
minutes, a git status that takes ten seconds.
The diagnostics are read-only and safe to run:
{/* Object counts and pack statistics */}git count-objects -vH{/* Repository size on disk */}du -sh .gitCommon causes worth knowing before asking: large binaries committed at some point in history, a
missing .gitignore letting build output in, or a repository that has never been repacked.
The remedies range from harmless (git gc) to history-rewriting (removing large objects), and the
second category belongs to the same rules as
removing a secret — including coordinating with everyone who has a clone. See also
Git maintenance.
Command risk, and what to do about it
Section titled “Command risk, and what to do about it”A rough classification worth internalising, because it determines how much verification a suggestion needs.
| Risk | Commands | Before running |
|---|---|---|
| Safe | status, log, diff, reflog, show, branch -vv | Nothing. Run them freely |
| Reversible | switch, checkout <branch>, stash, switch -c | Glance at git status |
| Local rewrite | reset, rebase, commit --amend, stash drop | Know what you lose; note your reflog position |
| Shared destruction | push --force, push --delete, branch -D on shared work | Understand fully, or do not run it |
The read-only row is where AI diagnosis should spend most of its time. A useful framing when asking:
Give me read-only commands to diagnose this first. Do not suggest anything that changes state until I have shown you the output.
That single instruction converts the interaction from “here is a fix” to “here is a diagnosis”, which is the correct order and the one that produces fewer accidents.
Why AI is unusually good at this, and unusually risky
Section titled “Why AI is unusually good at this, and unusually risky”Both halves are worth understanding, because they come from the same property.
Good, because Git’s errors are dense and standardised. The messages have not changed much in years, the states are finite, and the diagnostic commands are the same every time. That is close to ideal input: a well-defined problem space with abundant public discussion of every failure mode.
Risky, because the person asking cannot evaluate the answer. Everywhere else in this cluster you can check the output — a commit message against a diff, a summary against the commits it cites. Here, the whole reason you are asking is that you do not know what is happening, which means you cannot tell a correct fix from a plausible one.
That asymmetry is why this article is structured around process rather than answers. The five inputs, the read-only-first instruction, the backup branch and the risk table are all mechanisms for being safe while uncertain — because “verify the answer” is not available to you in the moment it matters.
The corollary worth carrying: the time to learn Git’s model is not while something is broken. The fundamentals and workflows pillars are what make you able to evaluate a suggestion, and AI assistance is a supplement to that understanding rather than a replacement for it.
Taking a backup costs nothing
Section titled “Taking a backup costs nothing”Before any operation in the bottom two rows:
{/* A branch pointing at the current state, in case you need to come back */}git branch backup/before-rebaseThat is one command, it creates a named reference to your current commit, and it makes the entire
operation reversible with git reset --hard backup/before-rebase.
For the working tree as well:
git stash push -u -m "before troubleshooting"Neither is sophisticated. Both remove the consequence from the category of decisions you are making while confused, which is the category you should be trying to empty.
Troubleshooting with an agent
Section titled “Troubleshooting with an agent”Copilot CLI can run the diagnostic commands itself rather than asking you to
paste output. For troubleshooting specifically, that changes the ergonomics substantially — gathering
status, log, reflog and branch -vv is most of the work, and an agent doing it produces a much
better-informed first answer.
It also removes the friction that was doing useful work. Pasting output is slow, and slowness is what makes you read it.
The configuration that keeps the benefit without the risk:
Allow the read-only commands. git status, log, diff, reflog, show, branch are safe to
run without asking, and letting them run makes diagnosis fast.
Approve state-changing commands individually. Every reset, rebase, checkout and push
should be an explicit decision, especially while you are confused about the state.
Never use --allow-all-tools for troubleshooting. This is the exact scenario the approval prompt
exists for. You are in an unfamiliar state, and the commands that resolve unfamiliar states are the
destructive ones.
The general principle from the CLI cluster applies with unusual force here: generating a command is research; running it is a decision. Troubleshooting is when that distinction is easiest to lose, because you want the problem to be over.
When to stop and ask a person
Section titled “When to stop and ask a person”Some situations are worth escalating rather than debugging, and recognising them early is cheaper than recovering afterwards.
Anything involving a shared branch’s history. If the fix involves force-pushing something other people have pulled, that is a conversation before it is a command — see when not to rebase.
Anything where you cannot state what you would lose. The rule at the top of this page. Not knowing is a reason to ask, not a reason to try.
Anything in a repository you cannot afford to break. The calculus changes when there is no disposable copy.
Anything where you have already tried three suggested fixes. Compounding attempts on a state you did not understand initially is how a recoverable problem becomes an unrecoverable one. Stop, take a backup branch, and describe the whole sequence to somebody.
That last one is worth watching for in yourself. The failure pattern is not one wrong command; it is four, each responding to the mess made by the last, with the reflog getting longer and the mental model getting worse.
Common mistakes
Section titled “Common mistakes”Pasting the error without the hints. The hints usually contain the answer.
Omitting what you were trying to do. The same output has different remedies depending on intent.
Running a suggested --force push. Use --force-with-lease, and only after establishing whose
commits are on the remote.
Believing commits are gone. Check the reflog first. They almost never are.
Continuing a rebase you do not understand. --abort returns you to a known state.
Not taking a backup branch. One command, and it makes the next mistake recoverable.
Pasting credentials while debugging authentication. The error text is enough; the token is not needed.
Accepting a reset --hard because the explanation was fluent. The explanation is generated by the
same system as the command.
A worked diagnosis
Section titled “A worked diagnosis”Putting the process together on a real situation: you rebased a branch, something went wrong, and you are not sure what state you are in.
Step 1 — gather, do not act.
git statusgit log --oneline -5git branch -vvgit reflog | head -20Four read-only commands. Nothing has changed.
Step 2 — describe the goal, not the command.
I was rebasing
featureontomain. Something went wrong and I am not sure what state I am in. Here isgit status,git log --oneline -5,git branch -vvand the last 20 reflog entries. What state am I in, and what are my options? Do not suggest anything that changes state yet — I want to understand first.
Step 3 — check the diagnosis yourself. The answer should name a state you can confirm: mid-rebase,
detached, diverged, clean. git status says which; if the diagnosis does not match what status says,
stop and re-ask.
Step 4 — take the backup.
git branch backup/pre-fixStep 5 — ask for options with consequences.
Given that state, what are my options, and what does each one lose?
Step 6 — pick, then confirm you can state the effect. If you cannot, ask what the command does before running it.
Step 7 — verify. git log --oneline -5 and git status again. Did the result match the
prediction? If not, git reset --hard backup/pre-fix puts you back.
Seven steps, of which five are read-only and one is a single-command backup. The whole process takes two minutes and turns an unfamiliar state into a reversible decision — which is the entire objective.
Mental model
Section titled “Mental model”Git rarely loses anything; it makes things unreachable. Most troubleshooting is finding the reference you lost rather than recovering data — which is why the safe commands are the diagnostic ones, and why the reflog is the first place to look rather than the last.
What you learned
Section titled “What you learned”- Supply the command, the full output,
git status, branch state, and your intent — all five - Git’s
hint:lines usually contain the remedy, and are the part people trim git branch -vvshows tracking and divergence, which is most push confusion- Detached HEAD is recoverable with
git switch -c; nothing is broken - The reflog records every HEAD position, and is how “lost” commits are found
--force-with-leaserefuses when the remote has moved;--forcedoes not- Every interrupted operation has an
--abortthat returns you to a known state - Ask for read-only diagnostics first, and share the output before accepting a fix
- A backup branch is one command and makes the next step reversible
Exercise
Section titled “Exercise”Use a disposable repository. Break it deliberately.
-
Commit twice, then
git checkout HEAD~1. Read the detached HEAD message. Predict: are your commits still reachable? -
Commit while detached, then
git switch main. Predict: where did that commit go? Find it withgit reflog. -
Recover it onto a branch with
git switch -c recovered <hash>. -
Clone your repository to a second directory. Commit in both, push from one, then push from the other. Read the full rejection including hints. Predict: what does
git branch -vvshow? -
Ask an assistant for a fix, giving only
! [rejected]. Then ask again with the full output plusstatusandbranch -vv. Compare. -
Run
git reset --hard HEAD~2, then recover using the reflog. Predict: what does the reflog entry for the reset look like? -
Try
git push --force-with-leaseon a branch whose remote has moved. Predict: does it refuse? -
Delete both copies.