# Git Checkout vs. Reset vs. Revert: A Guide for Scientists

In one sentence: `git checkout` moves you or your files to another state without erasing history, `git reset` moves a branch pointer to rewrite local history, and `git revert` adds a new commit that cancels out an old one while leaving history intact. The rule of thumb that follows from this is simple. If the commit has been pushed to a shared repository that your collaborators pull from, use `git revert`. If the commit exists only on your machine and nobody else has built on it, `git reset` is the right tool. If you only want to look at an old version or restore a file, use `git checkout` or its modern replacements, `git switch` and `git restore`.

Most scientists learn Git by necessity, not by training. You inherit a lab pipeline, someone puts it on GitHub, and within a month you are staring at a mistake you need to undo. The three commands above are the ones that cause the most anxiety because they seem to overlap, and because one wrong flag can discard hours of work. This guide explains what each command actually does, how to choose between them, and how the choice plays out in real research settings such as analysis pipelines, manuscripts under revision, and shared repositories on GitHub.

## The Three Trees That Explain Everything

Every confusion about checkout, reset, and revert traces back to one thing. Git manages three distinct snapshots of your project at all times, and the three commands move content between them in different ways. The official Git documentation describes these as the three trees, and once you can name them, every command flag becomes predictable.

The first tree is the **working tree** (sometimes called the working directory). This is the set of files you actually see and edit in your file browser or editor. When you open `analyze.R` in RStudio, you are looking at the working tree.

The second tree is the **index**, also called the staging area. This is the snapshot Git will capture in your next commit. When you run `git add analyze.R`, you copy the current working-tree version of that file into the index. The index is why commits can contain exactly the changes you choose, rather than everything you happened to touch.

The third tree is **HEAD**. HEAD is a pointer, usually to a branch name, and the branch points at a specific commit. When people say "HEAD" they usually mean "the commit my branch currently refers to," which is the latest commit on the branch you have checked out.

With those three trees defined, the summary table below becomes the core of the whole comparison. Every flag you will ever use on these commands is described in terms of which trees it touches.

| Action | Moves HEAD or branch pointer? | Changes the index? | Changes the working tree? | Rewrites existing history? | Safe on a shared, pushed branch? | Typical research use |
|--|--|--|--|--|--|--|
| `git checkout <branch>` | Yes (moves HEAD) | No | Yes (syncs files to that branch) | No | Yes | Switch to a collaborator's branch to review code |
| `git checkout <commit>` | Yes (detached HEAD) | No | Yes | No | Yes | Look at the exact pipeline version used for a published figure |
| `git checkout, <file>` (or `git restore <file>`) | No | No | Yes (discards uncommitted edits to that file) | No | Yes | Throw away accidental edits to a script before committing |
| `git reset, soft <commit>` | Yes (moves branch) | Yes (staged to match) | No | Yes (local) | No | Combine several unpushed commits into one |
| `git reset, mixed <commit>` (default) | Yes (moves branch) | Yes (unstaged) | No | Yes (local) | No | Uncommit work so you can restage it file by file |
| `git reset, hard <commit>` | Yes (moves branch) | Yes | Yes (destroys uncommitted changes) | Yes (local) | No | Abandon a failed local experiment entirely |
| `git revert <commit>` | No | Yes (via new commit) | Yes (via new commit) | No | Yes | Undo a buggy commit that was pushed to the lab repository |

Read the table row by row and a pattern emerges. `checkout` is about *where you are*. `reset` is about *where your branch points*. `revert` is about *writing a counteracting change on top of history*. None of this requires memorization if you keep asking which trees a command touches.

## git checkout Explained

`git checkout` is the oldest of the three commands, and it does two jobs that the Git project eventually split apart because they confused so many people. The official Git documentation describes checkout as switching branches or restoring working-tree files, and that double meaning is exactly where beginners get hurt.

### Using checkout to move between branches and commits

The branch-switching form, `git checkout main` or `git checkout feature-variant-B`, moves HEAD to point at the branch you name and updates your working tree to match. Your uncommitted changes come along with you if they do not conflict, or Git refuses to switch and tells you to commit or stash them first.

The commit form, `git checkout a1b2c3d` (where the letters are the start of a commit identifier), puts you in **detached HEAD** state. HEAD no longer points to a branch. It points directly at one historical commit. This is a perfectly safe state for *reading*: you can run an old version of a pipeline, test whether a bug existed last March, or regenerate a figure from the exact code state used in a manuscript. It becomes dangerous only when you *commit* while detached, because those new commits belong to no branch and are easy to lose once you check something else out. If you find yourself committing in detached HEAD, create a branch first with `git switch -c notes-from-march`, then commit.

A concrete research use case. Your paper describes results produced by pipeline version 3 months ago, and the pipeline has since changed. A reviewer asks how a number was produced. You run `git checkout v2.3` (a tag you created at the time), rerun the pipeline, and produce the identical figure. History is untouched. You are a visitor in the past, not an editor of it.

### Using checkout to restore files

The file form, `git checkout, results/table1.tsv`, discards uncommitted edits to that one file and restores the version from the index or, with `git checkout HEAD, results/table1.tsv`, the version from the last commit. This is a *destructive* action for uncommitted work. Git does not stage discarded edits anywhere recoverable, so anything you had typed into that file since the last commit is gone. That is the single most common way scientists lose work with these commands: typing `git checkout, .` intending to refresh a view, and wiping out a day of uncommitted edits.

### git switch and git restore, the modern replacements

Because checkout tried to do two unrelated jobs, the Git project introduced two focused commands in version 2.23. The Git project's own release documentation describes the split. `git switch` changes branches and handles detached HEAD explicitly (`git switch, detach a1b2c3d`), and `git restore` fixes the file-restoration job (`git restore results/table1.tsv` discards edits, `git restore, staged file` unstages a file without touching the working tree). The old commands still work everywhere and you will see them in older lab documentation, but for new habits, `switch` for moving between branches and `restore` for fixing files is unambiguous. The rest of this article uses `checkout` where the historical command matters and notes the modern equivalent where it differs.

## git reset Explained

`git reset` moves a branch pointer. That is the whole idea, and the three modes (`-soft`, `-mixed`, `-hard`) simply decide how much of the rest of the repository is brought along.

### What reset actually moves

Suppose your branch `main` points at commit F, and your history is A, B, C, D, E, F. You decide commits D, E, and F were a mistake and you want the branch to end at C. You run `git reset, hard C`. Git repoints the `main` branch reference at C. Commits D, E, and F still exist in your repository's object database, but no branch reaches them, so they become invisible to normal commands and eligible for eventual garbage collection. From the user's point of view, history shrank.

That is why `reset` is described as rewriting history. It does not delete objects immediately, which is why recovery is possible (covered below), but it changes which commits your branch claims as its past. If anyone else has based work on commits D, E, and F, repointing the branch out from under them creates exactly the kind of conflict chaos that ruins shared repositories.

### The three reset modes in terms of the three trees

`git reset, soft <commit>` moves the branch pointer only. Your index and working tree are untouched, so every change from the abandoned commits reappears as staged changes, ready to recommit. This is the mode for restructuring unpushed commits, for example squashing three incremental commits ("fix typo", "actually fix bug", "fix the fix") into one clean commit before opening a pull request.

`git reset, mixed <commit>`, which is the default when you type `git reset <commit>` with no flag, moves the branch pointer and resets the index to match it, but leaves the working tree alone. Changes from the abandoned commits reappear as unstaged edits. This is the mode for "I committed too early and want to choose my files again." You uncommit, then `git add` selectively and commit properly.

`git reset, hard <commit>` moves the branch pointer, resets the index, and forces the working tree to match. Anything uncommitted is destroyed, and commits after the target are cut off from the branch. It is the mode for "this local experiment was wrong from the start, I want my repository to look like it never happened." It is also the mode that most often destroys real work, because the working-tree portion of a hard reset is the part Git does not track anywhere else.

Two narrower uses of reset are worth knowing because they do not move a branch at all. `git reset <file>` (equivalently `git restore, staged <file>`) unstages a file, leaving its edits intact in the working tree. `git reset, hard` with no commit argument resets everything to the last commit and is the scorched-earth answer to "I have made a mess of my working tree and want it to exactly match HEAD." Both still discard uncommitted changes, so read your `git status` output before pressing enter.

### Recovering from a bad reset with the reflog

![A flowchart of a hard reset, running git reflog, checking whether the work was committed, and resetting back to the old identifier.](/article-images/illustrations/git-checkout-vs-reset-vs-revert-for-scientists-reflog-recovery.webp)

The safety net behind `reset` is the **reference log**, or reflog. Git records every position HEAD has occupied in your repository, locally, for months. The official Git documentation describes the reflog as Git's mechanism for recovering supposedly lost commits. After an accidental `git reset, hard`, run `git reflog`. You will see a list of recent HEAD positions with short messages such as `reset: moving to C`. Find the line representing the state before the mistake, note its identifier, and run `git reset, hard a1b2c3d` using that identifier. Your "lost" commits are back on the branch. The reflog is local to your machine and is not shared by push or pull, which means it saves you from your own resets but not from a collaborator's force-push (covered in the mistakes section).

## git revert Explained

`git revert` solves a different problem. When a bad commit has been pushed to a repository other people use, rewriting history is not an option. What you need is a way to cancel the bad change while leaving the historical record honest. Revert does exactly that.

### What revert actually does

Running `git revert a1b2c3d` tells Git to compute the *inverse* of that commit. If the bad commit added three lines, the revert removes exactly those three lines. If it renamed a function, the revert renames it back. Git creates a *new* commit containing this inverse patch, with a default message such as `Revert "Add lysis buffer step"`. The bad commit remains in history, and the new commit follows it. Anyone who pulls sees a normal, ordinary commit that happens to undo a previous one.

This is why revert is the correct answer for shared branches. It never changes any commit anyone already has. Collaborators do not need to rebase, force-pull, or wonder why their history looks different from yours. On GitHub, where research groups commonly share pipelines through pull requests, revert is also how you back out a merged pull request that turned out to break a downstream step: revert the merge commit, and the pull request's changes leave the main branch while remaining visible in history.

### Practical details that matter

If the bad commit touched several unrelated files, `git revert` will commit the whole inverse at once. If you want to inspect and adjust first, use `git revert, no-commit a1b2c3d`, which applies the inverse changes to your working tree and index and lets you commit them yourself, possibly after trimming parts you want to keep.

If the bad commit is in the middle of a stack of later changes that touched the same lines, Git cannot compute a clean inverse and reports a conflict, the same as a merge conflict. You resolve it by editing the conflicted files, staging them with `git add`, and running `git revert, continue`. Conflicts during revert are more common the longer you wait, which is an argument for reverting a broken change promptly rather than after six further commits have piled on top of it.

Reverting a **merge commit** is a special case worth flagging for anyone maintaining a lab repository. Undoing a merge with a plain revert can be undone again only awkwardly, because Git records that those changes were already merged. The official Git documentation discusses the complications of reverting merges. For lab repositories, the practical guidance is to revert merge commits deliberately and with the understanding that re-merging the same branch later requires extra steps, or to coordinate with whoever owns the repository before doing it.

## git checkout vs. git reset vs. git revert in Practice

![A yes or no path that asks whether the commit was pushed, then whether you only want to look, ending at revert, reset, or checkout.](/article-images/illustrations/git-checkout-vs-reset-vs-revert-for-scientists-undo-triage.webp)

The difference between git checkout, reset, and revert for scientists comes down to four questions. Answer them in order and the correct command picks itself.

**Question 1: Has anyone else seen this commit?** If the commit exists on a shared remote such as your lab's GitHub repository and anyone may have pulled it, `revert` is the only safe undo. Rewriting shared history with reset and a force-push makes every collaborator's local repository inconsistent with the remote, and resolving that mess reliably costs far more time than an extra revert commit. If the commit is purely local, `reset` is cleaner because it leaves no confusing "Revert" marker in history.

**Question 2: Do you want history rewritten or history extended?** Reset rewrites. Revert extends. This is not a style preference. Rewriting invalidates every clone based on the old history, extending does not. The rule the question forces you to confront is that the two commands are only interchangeable when the commits in question are private.

**Question 3: Do you want to change anything at all, or just look?** If your goal is to inspect an old version, test a specific pipeline revision, or restore a single file, `checkout` (or `switch` and `restore`) is the right family. Neither reset nor revert is designed for looking, and using reset to "visit" an old commit is how detached-HEAD confusion and accidental hard resets happen.

**Question 4: Which tree is actually wrong?** If only uncommitted edits in the working tree are bad, `git restore <file>` or `git checkout, <file>` fixes it without touching commits. If only the index (staging) is wrong, `git restore, staged` or `git reset <file>` fixes it without touching the working tree. If the problem is committed but unpushed, `git reset, soft` or `-mixed` lets you rebuild. Only when the problem is committed, pushed, and wrong does `revert` become mandatory.

A compact scenario table:

| Situation | Command |
|--|--|
| A colleague needs the buggy commit removed from the shared main branch | `git revert <commit>` |
| You committed to your local branch and want to uncommit and restage | `git reset, mixed HEAD~1` |
| You want to squash your last three unpushed commits into one | `git reset, soft HEAD~3`, then one commit |
| You want to throw away all uncommitted local changes | `git restore .` or `git reset, hard` (after checking `git status`) |
| You want to see the code as it was when a figure was made | `git checkout <tag-or-commit>` (or `git switch, detach`) |
| You edited the wrong file and want it back to the committed version | `git restore <file>` |
| A merged pull request broke the pipeline on GitHub | `git revert -m 1 <merge-commit>` |

The `HEAD~1` and `HEAD~3` notation means "one commit before HEAD" and "three commits before HEAD." It is the most convenient way to refer to recent history without copying commit identifiers.

## Worked Scenarios from Research Life

Abstract rules become real habits through examples. These five scenarios cover the situations that generate the most panic in laboratory settings.

### Scenario 1: You pushed a broken commit to the lab pipeline repository

You edit `quality_filter.sh`, commit, and push. Within an hour, a labmate reports that the sequencing QC step fails for everyone. The commit is on the shared remote. The fix is a revert:

```
git revert HEAD
git push origin main
```

The first command creates a new commit that inverses your broken one. The second shares it. Both of you are unblocked, history shows exactly what happened and when, and nobody had to force anything. If you later fix the filter properly, you make a normal new commit. The revert and the fix both remain in the record, which is what you want in science: the ability to reconstruct not only the final state but the sequence of events that produced it.

### Scenario 2: You made three sloppy local commits and want one clean one

You have been iterating on a variant-calling script. Your local history reads "wip", "fix", "actually works now", and you want a single commit that says "Tune variant filtering thresholds" before sharing. Nobody else has these commits.

```
git reset --soft HEAD~3
git commit -m "Tune variant filtering thresholds"
```

The soft reset folds all three commits' changes into your index. The single new commit captures them all. This pattern, reset-then-recommit, is the workhorse for preparing readable pull requests, and readable pull requests are what make peer review of lab code feasible.

### Scenario 3: You committed too early and the wrong files came along

You committed your analysis notebook together with a 2 GB intermediate file you never meant to track. It is local only. Use a mixed reset to uncommit while keeping the files:

```
git reset --mixed HEAD~1
git restore --staged intermediates/tmp_counts.h5
echo "intermediates/" >> .gitignore
git add analyze.ipynb .gitignore
git commit -m "Add variant analysis notebook"
```

The mixed reset unstages everything, `restore, staged` keeps the large file out of the next commit, and the `.gitignore` entry prevents a repeat. (For large data files that genuinely must be versioned, the Git project documents Git LFS as the standard extension, but that is a separate topic from undo operations.)

### Scenario 4: A reviewer asks you to reproduce results from an old code state

You tagged your repository `v1.2` when the manuscript was submitted. Months later, a reviewer questions a figure. You do not want to disturb your current work, so you do it in a separate directory:

```
git worktree add ../paper-v1.2-check v1.2
cd ../paper-v1.2-check
snakemake --cores 4 figures/figure3.pdf
```

The `git worktree` command, documented by the Git project, checks out a second copy of the tagged state in a new folder so your main working directory stays on your current branch. No checkout gymnastics in your active directory, no reset, no risk. When you are done, `git worktree remove ../paper-v1.2-check` cleans up. This is the safest pattern for reproducibility checks and it never touches your history at all.

### Scenario 5: You ran a hard reset and your work vanished

You meant to reset one file and instead ran `git reset, hard HEAD~2`, losing two unpushed commits. Stop making changes and use the reflog:

```
git reflog
# find the line before the reset, note its identifier
git reset --hard a1b2c3d
```

Your commits reappear on the branch. This works because `reset, hard` repoints the branch rather than deleting commit objects, and the reflog remembers where the branch pointed before. Two limits apply. First, changes that were never committed at all are not recovered by the reflog, because the reflog tracks commit positions, not working-tree edits. Second, reflog entries expire after a retention period that Git defines per repository, so recover promptly rather than weeks later.

## Common Mistakes and Limitations

These are the errors that show up repeatedly when scientists apply undo commands, with the specific prevention for each.

**Treating reset and revert as synonyms.** They are not, and the difference is who else has the commits. Reset on a pushed branch followed by `git push, force` is the single most damaging sequence in collaborative Git. Every collaborator who has pulled now has commits that the remote says do not exist, and reconciling requires either rebasing their work or, worse, force-pushing over their changes. Modern Git defaults to a safer variant, `-force-with-lease`, which refuses the push if the remote moved since your last fetch, but the underlying problem, rewriting shared history, remains. The rule stands: pushed means revert, private means reset.

**Running `git reset, hard` without reading `git status` first.** Hard reset destroys uncommitted changes, and uncommitted changes are the one category Git cannot recover from its object database. The habit that prevents this is mechanical: before any destructive command, run `git status` and confirm you can name every modified and untracked file it lists. If you cannot, commit or stash (`git stash push`) first. Stashing saves uncommitted work as a recoverable snapshot, which makes almost any mistake afterwards reversible.

**Confusing checkout's two jobs.** The classic accident is running `git checkout <old-commit>` to look at history, forgetting you are in detached HEAD, making commits there, then checking out a branch and seeing the commits "disappear." They are not gone, they are simply not on any branch, and `git reflog` or the identifier Git printed when you detached will find them. The modern fix for this confusion is to use `git switch`, which refuses casual detachment and makes the detached state explicit.

**Committing in detached HEAD state during conference-deadline panic.** Related to the above. If you notice you are detached (`git status` says so on every line), run `git switch -c rescue-branch` before doing anything else. That pins your commits to a named branch immediately.

**Assuming revert "deletes" a commit.** Revert leaves the original commit in history and adds an inverse. Some people then search their log for the bad commit, cannot find it removed, and conclude revert failed. The correct mental model is a ledger entry and a correcting entry, both visible.

**Reverting a revert and getting lost.** You can revert a revert commit, and that restores the original changes, but stacks of reverts-of-reverts become hard to read in a shared lab repository. If a change is going to come back anyway, it is usually clearer to make the fix forward as a new commit and note in the message which reverted commit it supersedes.

**Expecting these commands to manage untracked files.** Untracked files, files Git has never been told about, are largely invisible to checkout, reset, and revert. A hard reset will not delete an untracked 40 GB intermediate directory. The command for that is `git clean`, which is destructive and should be run first with `git clean -n` (a dry run that only lists what would be removed). Knowing which undo command covers which file category prevents the "I reset and my disk is still full" surprise.

**Believing any of this substitutes for pushing and backing up.** The reflog saves local mistakes. It does nothing if your laptop fails. Commits that exist only on one machine are the research equivalent of an unbacked-up notebook, and the fix is the same one your institution's data policy already implies: push to a shared remote regularly.

**A general limitation.** All undo operations here operate at the level of committed snapshots and tracked files. They do not adjudicate *scientifically* wrong states. A pipeline can be perfectly versioned and still produce the wrong result because of an upstream metadata error. Version control preserves provenance, it does not verify correctness, and neither Git nor GitHub replaces validation of the analysis itself.

## A Repository Policy for Research Labs

Because undo behavior interacts with collaboration, it belongs in your lab's infrastructure policy, alongside backup schedules and data-retention rules. A short written policy prevents most of the mistakes above. The following five rules are a practical starting point for a lab using GitHub.

1. **Protected main branch.** Configure the main branch on GitHub so that force-pushes and history rewrites are not permitted, and require pull requests with at least one review before merge. This makes the pushed-means-revert rule automatic rather than a matter of memory.
2. **Rewrite only private branches.** Contributors may rebase or reset their own feature branches freely before opening a pull request. After a pull request is opened or a branch is shared, changes to it happen through new commits or reverts only.
3. **Revert, never force-push, on anything shared.** If a merged change breaks the pipeline, the fix on the main branch is `git revert`. Note the revert in the pull request thread so reviewers see why.
4. **Tag release states.** Tag the exact commit used for each submission and each published result (`git tag manuscript-v2-submission`). Reproducibility questions are then answered by checking out a tag, which never requires any undo operation at all.
5. **Status before destructive commands.** Any use of `git reset, hard`, `git restore`, or `git clean` is preceded by `git status`. This costs five seconds and prevents the most common form of irreversible data loss in Git.

Written down, these rules give a new lab member the answer to "git checkout or reset?" before they are confident enough to improvise one, and they make the difference between checkout, reset, and revert a matter of policy rather than folklore.

## Frequently Asked Questions

### Will git reset delete my commits permanently?

No, not immediately. Reset moves the branch pointer, and the abandoned commits remain in your repository until Git's garbage collection removes them, which is typically weeks later. Until then, `git reflog` lists the previous HEAD positions and you can restore the commits with `git reset, hard <identifier>` using the identifier from before the mistake. The exception is uncommitted changes destroyed by `git reset, hard`, which the reflog cannot recover.

### When should I use git revert instead of git reset?

Use revert whenever the commit you want to undo has been pushed to a repository other people pull from, such as a shared GitHub repository. Revert cancels the change with a new commit and leaves history intact, so collaborators' clones stay consistent. Use reset only for commits that exist only on your own machine, where a clean rewrite of history is preferable to a visible revert commit.

### What is the difference between git checkout and git switch?

They switch branches identically, but Git split the old checkout command into two focused commands in version 2.23. `git switch` changes branches and makes detached HEAD explicit, while `git restore` handles the file-restoration job that checkout used to do. The old commands still work, but switch and restore are less error-prone because each does one thing.

### How do I undo git reset, hard?

Run `git reflog` to see the record of recent HEAD positions, find the entry from before the reset, and run `git reset, hard <identifier>` pointing at that entry. This restores commits that the reset removed from your branch. It does not recover working-tree changes that were never committed, so act promptly and avoid making new changes in the meantime.

### Is it safe to rewrite history on a shared repository branch?

No. Rewriting history on a branch that others have pulled forces every collaborator to reconcile their local copy against a remote that no longer matches, and the usual workaround, force-pushing, can overwrite their work. The safe pattern for shared branches is to add new commits or use `git revert`. Reserve history rewriting, such as reset and rebase, for private local branches.

### What is detached HEAD state and how do I fix it?

Detached HEAD means HEAD points directly at a specific commit rather than at a branch, which happens after `git checkout <commit>` or checking out a tag. It is safe for inspecting and running old code. To leave it without losing anything, check out a branch as you normally would. If you made commits while detached that you want to keep, create a branch at your current position first with `git switch -c <new-branch-name>`.

<script type="application/ld+json">
{
  "@context": "https://schema.org",
  "@type": "FAQPage",
  "mainEntity": [
    {
      "@type": "Question",
      "name": "Will git reset delete my commits permanently?",
      "acceptedAnswer": {
        "@type": "Answer",
        "text": "No, not immediately. Reset moves the branch pointer, and the abandoned commits remain in your repository until Git's garbage collection removes them, which is typically weeks later. Until then, git reflog lists the previous HEAD positions and you can restore the commits with git reset, hard followed by the identifier from before the mistake. The exception is uncommitted changes destroyed by git reset, hard, which the reflog cannot recover."
      }
    },
    {
      "@type": "Question",
      "name": "When should I use git revert instead of git reset?",
      "acceptedAnswer": {
        "@type": "Answer",
        "text": "Use revert whenever the commit you want to undo has been pushed to a repository other people pull from, such as a shared GitHub repository. Revert cancels the change with a new commit and leaves history intact, so collaborators' clones stay consistent. Use reset only for commits that exist only on your own machine, where a clean rewrite of history is preferable to a visible revert commit."
      }
    },
    {
      "@type": "Question",
      "name": "What is the difference between git checkout and git switch?",
      "acceptedAnswer": {
        "@type": "Answer",
        "text": "They switch branches identically, but Git split the old checkout command into two focused commands in version 2.23. git switch changes branches and makes detached HEAD explicit, while git restore handles the file-restoration job that checkout used to do. The old commands still work, but switch and restore are less error-prone because each does one thing."
      }
    },
    {
      "@type": "Question",
      "name": "How do I undo git reset, hard?",
      "acceptedAnswer": {
        "@type": "Answer",
        "text": "Run git reflog to see the record of recent HEAD positions, find the entry from before the reset, and run git reset, hard pointing at that entry. This restores commits that the reset removed from your branch. It does not recover working-tree changes that were never committed, so act promptly and avoid making new changes in the meantime."
      }
    },
    {
      "@type": "Question",
      "name": "Is it safe to rewrite history on a shared repository branch?",
      "acceptedAnswer": {
        "@type": "Answer",
        "text": "No. Rewriting history on a branch that others have pulled forces every collaborator to reconcile their local copy against a remote that no longer matches, and the usual workaround, force-pushing, can overwrite their work. The safe pattern for shared branches is to add new commits or use git revert. Reserve history rewriting, such as reset and rebase, for private local branches."
      }
    },
    {
      "@type": "Question",
      "name": "What is detached HEAD state and how do I fix it?",
      "acceptedAnswer": {
        "@type": "Answer",
        "text": "Detached HEAD means HEAD points directly at a specific commit rather than at a branch, which happens after checking out a commit or a tag. It is safe for inspecting and running old code. To leave it without losing anything, check out a branch as you normally would. If you made commits while detached that you want to keep, create a branch at your current position first with git switch -c followed by a new branch name."
      }
    }
  ]
}
</script>