---
title: 'Reset Modes'
source: 'https://academia.sh/en/courses/introduction-to-version-control/reset-modes'
course: 'Introduction to Version Control'
language: en
updated: '2026-08-17T18:10:48+00:00'
license: 'CC BY-SA 4.0'
---

# Reset Modes

Moving the branch tip backward; the effect of the `--soft`, `--mixed`, and `--hard` modes on the three regions, lost content, and recovery through the reflog.

Amending moved the branch tip to a new commit attached to the same parent. **Reset**
moves the branch tip further back in history: one or more commits drop out of the
branch's reachable past. Reset has three modes, and the difference among them is which
regions are affected.

This lesson applies all three modes, one by one, to the same mistake.

## The Mistake

The term list is meant to be sorted alphabetically and is handed to a general-purpose
sorting tool. The result:

```
ağaç | tree
bağlı liste | linked list
dizi | array
karma tablosu | hash table
kuyruk | queue
küme | set
yığıt | stack
çizge | graph
öbek | heap
```

The order is wrong. "çizge" and "öbek" have dropped to the end of the list, and "küme"
comes after "kuyruk." The reason is that the sort is done by byte value, not by the
Turkish alphabet: as seen in the How Computers Work course, letters outside the ASCII
range are encoded in UTF-8 with more than one byte, and their first byte is greater than
every ASCII letter. The correct order requires a locale-aware comparison scheme.

Without the mistake being noticed, it is committed:

```bash
git commit -m "Terim listesini abecesel sırala"
```

```
[main d85a348] Terim listesini abecesel sırala
 1 file changed, 5 insertions(+), 5 deletions(-)
```

## What Reset Does

Reset consists of three steps, and the mode determines how many of them get applied:

1. **Move the branch tip.** Done in every mode.
2. **Make the staging area match the target.** Done in every mode except `--soft`.
3. **Make the working directory match the target.** Done only with `--hard`.

The first step touches history; the second and third steps touch content.

## `--soft`

```bash
git reset --soft HEAD~1
git log --oneline -n 1
```

```
18600c5 README'ye kullanım bölümü ekle
```

The commit dropped out of history. What happened to the content?

```bash
git status --short
```

```
M  terimler.txt
```

The change is standing in the staging area. Only the first step was applied: the branch
tip moved back, the staging area and the working directory were left as they were. The
result is the state of "the commit was never written, but the content is ready to be
committed."

```bash
git diff --staged --stat
```

```
 terimler.txt | 10 +++++-----
 1 file changed, 5 insertions(+), 5 deletions(-)
```

This mode is used to rearrange the scope of the last commit: the commit is undone, the
content is split the way it is wanted, and it is recommitted.

## `--mixed`

The commit is rewritten, and this time reset with the default mode:

```bash
git reset HEAD~1
```

```
Unstaged changes after reset:
M	terimler.txt
```

```bash
git status --short
```

```
 M terimler.txt
```

The mark moved to the second column: the content is no longer in the staging area, only
in the working directory. The first and second steps were applied. This is the default
mode even when `--mixed` is not written.

This mode undoes both the commit and the selection made in the staging area; it is used
when the decision of which files to commit together needs to be made from scratch.

## `--hard`

```bash
git reset --hard HEAD~1
```

```
HEAD is now at 18600c5 README'ye kullanım bölümü ekle
```

```bash
git status --short
```

The output is empty. The term list has also returned to its old state: the sort has
been completely undone. All three steps were applied.

This mode is **destructive** and takes two separate pieces of content down with it: the
content of the reset commits, and every uncommitted edit that was in the working
directory at the time. The first can be brought back from the reflog; the second cannot.
Looking at `git status`'s output before running `git reset --hard` is the only way to
avoid this second loss.

## Comparing the Three Modes

| Mode | Branch tip | Staging area | Working directory | Where the change stays |
|---|---|---|---|---|
| `--soft` | Moved | Untouched | Untouched | In the staging area |
| `--mixed` | Moved | Matched | Untouched | In the working directory |
| `--hard` | Moved | Matched | Matched | Nowhere |

The table reduces to a single sentence: the harsher the mode, the deeper the undo
reaches. The choice is made based on whether the commit's content should be preserved.

## Recovery

A reset commit stays in the object database and can be found through the reflog:

```bash
git reflog -n 6
```

```
18600c5 HEAD@{0}: reset: moving to HEAD~1
d85a348 HEAD@{1}: commit: Terim listesini abecesel sırala
18600c5 HEAD@{2}: reset: moving to HEAD~1
d85a348 HEAD@{3}: commit: Terim listesini abecesel sırala
18600c5 HEAD@{4}: reset: moving to HEAD~1
d85a348 HEAD@{5}: commit: Terim listesini abecesel sırala
```

The log has recorded the order the three modes were tried in exactly as it happened. It
is not a coincidence that the commit ID comes out as `d85a348` every time: as long as
the content, message, author, and date are the same, the ID is the same too. This is a
direct consequence of content-addressed storage.

The branch tip is moved back to the desired ID:

```bash
git reset --hard d85a348
```

```
HEAD is now at d85a348 Terim listesini abecesel sırala
```

The commit is back in history. In this example the sort really is wrong, so the final
decision is to drop it:

```bash
git reset --hard HEAD~1
```

```
HEAD is now at 18600c5 README'ye kullanım bölümü ekle
```

## The Form Given a Path

When `git reset` is given a path, its behavior changes entirely: the branch tip does not
move, only that path's record in the staging area is returned to its state at the
target.

```bash
git add terimler.txt
git status --short
```

```
M  terimler.txt
```

```bash
git reset terimler.txt
```

```
Unstaged changes after reset:
M	terimler.txt
```

```bash
git status --short
```

```
 M terimler.txt
```

This is the older form of what was done with `git restore --staged` in the previous
lesson. The same command name doing different things depending on whether it is given a
path explains why `git restore` was named separately.

## `ORIG_HEAD`

Before moving the branch tip, reset writes the old value to a file named `ORIG_HEAD`:

```bash
cat .git/ORIG_HEAD
```

```
2aff8c57391d20c90c05be4eb3f9a385fd140cf2
```

This name can be used like a ref; the shortest way to undo a reset done by mistake is to
go back to the `ORIG_HEAD` target without reading the reflog:

```bash
git reset --hard ORIG_HEAD
```

The file records only the last operation; it is overwritten on successive resets. Going
further back requires the reflog.

## The Difference Between Reset and Restoring a File

The two commands are confused because both are called "undoing." The distinction is
clear:

- `git restore` operates on a **path**; it does not touch history.
- `git reset` operates on a **ref**; it moves the branch tip.

If you want to return a file to an old state, use `git restore`; if you want to drop a
commit from history, use `git reset`.

Reset itself is also problematic on shared history: moving the branch tip back creates
incompatibility with copies that already have those commits. The previous lesson's rule
holds here too — shared history is not rewound.

## Summary

- Reset moves the branch tip; the mode determines whether the staging area and the
  working directory are also matched to it.
- `--soft` leaves the content in the staging area, `--mixed` in the working directory;
  `--hard` matches both to the target.
- `--hard` deletes uncommitted edits irrecoverably.
- Reset commits stay in the object database; they can be found and brought back through
  the reflog.
- The same content, message, author, and date always produce the same commit ID.

## Next Step

Reset and amending both work by rewriting history, and this is why they cannot be used
on shared commits. So what happens if a shared commit is wrong? The next lesson takes up
the tool that reverses a commit's effect without disturbing history — reverting.
