Lesson 27 · Recovery
Reset: soft, mixed and hard
Move a branch back one commit three ways and see what each mode does to the branch, the staging area and your files, so you pick the one that keeps the work you want.
- Level: Advanced
- 11 min read
- 6 min video
- Updated
- Before this lesson: Predict what your next commit will contain, Read history without moving HEAD
Progress saved in this browser.
Playing loads the video from YouTube (privacy-enhanced mode).
What you will learn
- Say what each reset mode moves: the branch, the index, and the files on disk.
- Protect committed work and uncommitted work before a destructive mode.
- Read the status output that each mode leaves behind.
- Know which files a hard reset can overwrite, including untracked ones.
Before you start
You are on private/reset, a branch that starts at the merged page M from lesson 18 ("See your work clearly."). It has one commit above M, C, which changes the heading to "Review changes with confidence." A branch rescue/before-reset already points at C. After that commit you edited the page again, to "Understand each saved change.", and you have not staged or committed it. You also have an untracked note, docs/signup-hint.md. You want to move private/reset back to M.
Everything is local and on the Free plan (GitTree asks you to sign in): no hosting account, no provider, no internet. Every identity is fictional (example.com). Never run this lesson in a real project. The hard-reset copy is disposable.
Make the changes in GitTree or with the native Git commands, not both in the same copy. Reading the result is always safe. The menu labels come from GitTree 2.0's own strings and the native commands were run with Git 2.43 in disposable copies. The GitTree steps were not run on macOS, Windows or Linux.
Concept and state effects
A reset moves the current branch to another commit. The mode decides how much more it touches. Soft moves only the branch: the index and your files stay as they were, so the difference shows up as staged changes. Mixed moves the branch and replaces the index with the target: your files stay, so the difference shows up as unstaged changes. Hard moves the branch, replaces the index and rewrites your tracked files to the target. Your uncommitted edits to tracked files are gone.
The rescue branch keeps the commit C, so the committed heading can be found again. It does not keep the newer edit, which was never committed. Commits can be found through the reflog; unsaved edits cannot, because they were never in Git. Protect them yourself before any destructive mode.
Hard reset also overwrites an untracked file when the target has a tracked file at the same path. An untracked file that is not in the way, like docs/signup-hint.md here, is left alone. That is an observation about this project, not a promise about every untracked file.
In all three modes the branch is the only ref that moves: rescue/before-reset, other branches and anything on a server stay as they were.
GitTree asks first. Its reset dialog says what will stay, and for a hard reset it says everything it removes is saved under refs/ogt/trash first so Undo can restore it. A reset run in the terminal makes no such snapshot.
Prepare the exact project state
Start from a separate ordinary copy of lesson 18's merged result M and leave your original untouched. Create the branch, save SARA as the heading commit and branch the rescue ref at it. Then save OMAR unstaged and DOC_HINT as a new file. Keep a copy of OMAR and the note outside Git, then make three identical copies, one each for soft, mixed and hard.
Complete file inputs
Save only at the phase named below. These are full UTF-8/LF bodies with a final newline; never paste Markdown fences. Unchanged runnable files inherit the named input. Versions in separate variants must not overwrite the original.
index.html — MERGED
<!doctype html>
<html lang="en">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>GitTree Features — course demo</title>
<link rel="stylesheet" href="styles.css">
</head>
<body>
<header class="site-header">
<a href="#main">GitTree Features</a>
</header>
<main id="main" tabindex="-1">
<section class="hero" aria-labelledby="hero-title">
<p class="eyebrow">GitTree Learn demo project</p>
<h1 id="hero-title">See your work clearly.</h1>
<p id="hero-copy">Choose one change, then check what Git saved.</p>
</section>
<section class="features" aria-labelledby="features-title">
<h2 id="features-title">Follow your work</h2>
<div class="cards">
<article class="feature-card">
<h3>History</h3>
<p>Read commits and branches together.</p>
</article>
<article class="feature-card">
<h3>Changes</h3>
<p>Review the exact content selected for a commit.</p>
</article>
<article class="feature-card">
<h3>Recovery</h3>
<p>Inspect the scope of a recovery point before using it.</p>
</article>
</div>
</section>
<section aria-labelledby="plans-title">
<h2 id="plans-title">Choose the workflow you need</h2>
<div class="cards">
<article class="feature-card">
<h3>Local Git</h3>
<p>Local Git workflows work without signing in.</p>
</article>
<article class="feature-card">
<h3>Connected workflows</h3>
<p>Provider integrations and Nour require Pro or an applicable trial.</p>
</article>
</div>
</section>
</main>
<footer><p>Built by a fictional team for GitTree Learn. Review one change at a time.</p></footer>
<script type="module" src="site.js"></script>
</body>
</html>index.html — SARA
<!doctype html>
<html lang="en">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>GitTree Features — course demo</title>
<link rel="stylesheet" href="styles.css">
</head>
<body>
<header class="site-header">
<a href="#main">GitTree Features</a>
</header>
<main id="main" tabindex="-1">
<section class="hero" aria-labelledby="hero-title">
<p class="eyebrow">GitTree Learn demo project</p>
<h1 id="hero-title">Review changes with confidence.</h1>
<p id="hero-copy">Choose one change, then check what Git saved.</p>
</section>
<section class="features" aria-labelledby="features-title">
<h2 id="features-title">Follow your work</h2>
<div class="cards">
<article class="feature-card">
<h3>History</h3>
<p>Read commits and branches together.</p>
</article>
<article class="feature-card">
<h3>Changes</h3>
<p>Review the exact content selected for a commit.</p>
</article>
<article class="feature-card">
<h3>Recovery</h3>
<p>Inspect the scope of a recovery point before using it.</p>
</article>
</div>
</section>
<section aria-labelledby="plans-title">
<h2 id="plans-title">Choose the workflow you need</h2>
<div class="cards">
<article class="feature-card">
<h3>Local Git</h3>
<p>Local Git workflows work without signing in.</p>
</article>
<article class="feature-card">
<h3>Connected workflows</h3>
<p>Provider integrations and Nour require Pro or an applicable trial.</p>
</article>
</div>
</section>
</main>
<footer><p>Built by a fictional team for GitTree Learn. Review one change at a time.</p></footer>
<script type="module" src="site.js"></script>
</body>
</html>index.html — OMAR
<!doctype html>
<html lang="en">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>GitTree Features — course demo</title>
<link rel="stylesheet" href="styles.css">
</head>
<body>
<header class="site-header">
<a href="#main">GitTree Features</a>
</header>
<main id="main" tabindex="-1">
<section class="hero" aria-labelledby="hero-title">
<p class="eyebrow">GitTree Learn demo project</p>
<h1 id="hero-title">Understand each saved change.</h1>
<p id="hero-copy">Choose one change, then check what Git saved.</p>
</section>
<section class="features" aria-labelledby="features-title">
<h2 id="features-title">Follow your work</h2>
<div class="cards">
<article class="feature-card">
<h3>History</h3>
<p>Read commits and branches together.</p>
</article>
<article class="feature-card">
<h3>Changes</h3>
<p>Review the exact content selected for a commit.</p>
</article>
<article class="feature-card">
<h3>Recovery</h3>
<p>Inspect the scope of a recovery point before using it.</p>
</article>
</div>
</section>
<section aria-labelledby="plans-title">
<h2 id="plans-title">Choose the workflow you need</h2>
<div class="cards">
<article class="feature-card">
<h3>Local Git</h3>
<p>Local Git workflows work without signing in.</p>
</article>
<article class="feature-card">
<h3>Connected workflows</h3>
<p>Provider integrations and Nour require Pro or an applicable trial.</p>
</article>
</div>
</section>
</main>
<footer><p>Built by a fictional team for GitTree Learn. Review one change at a time.</p></footer>
<script type="module" src="site.js"></script>
</body>
</html>docs/signup-hint.md — DOC_HINT
Unfinished signup hint: use fictional data only.In GitTree
Open the palette with Command+Shift+P (Ctrl+Shift+P on Ubuntu). Reset is on a commit's right-click menu, under the submenu Reset private/reset to This Commit.
- Build the branch, the rescue ref, the unstaged edit and the note as the next section shows. Keep a copy of the edit and the note outside Git. Make three identical copies and open them in three tabs.
- Soft copy. In the graph, right-click M (the commit below C, not the branch tip) and open Reset private/reset to This Commit. Choose Soft: Keep All Changes Staged. The confirmation dialog says every change since then stays staged and no file changes. Choose Reset private/reset.
- Check the soft result: the branch is on M, the page on disk still says "Understand each saved change.", and the staged and unstaged lists both hold
index.html. - Mixed copy. Choose Mixed: Keep Changes in the Working Folder on M. The dialog says every change stays in your working copy, unstaged. Choose Reset private/reset. The branch is on M, the page on disk is the same edit, and the change is unstaged only.
- Hard copy. Only after you saved the edit and the note elsewhere, choose Hard: Discard All Changes… on M. The dialog is a warning: it lists what is removed and says it is kept under
refs/ogt/trashfirst. Read it. The default is Cancel. Choose Discard and reset private/reset. - Check the hard result: the branch is on M, the page is M's heading and the changes list shows only the untracked note. The notice says "Reset to" and the commit.
- Compare the three copies and
rescue/before-reset, which is still on C. Do not push any of them.
The reset commands are disabled on the commit the branch is already on, and when no branch is checked out.
For every ordinary commit in the course: Summary is the stated subject, Description is empty and the options Amend Previous Commit, Skip Hooks, Add Signed-off-by, Different Author, Push After Commit and Allow Empty Commit stay off.
In the terminal
In a separate copy of lesson 18's result:
git switch --create private/resetSave SARA as index.html, then:
git add -- index.html
git commit --quiet -m "feat: reset snapshot example"
git branch rescue/before-resetSave OMAR as index.html without staging and DOC_HINT as docs/signup-hint.md. Keep a copy of both outside Git, then make three identical copies. In each one:
TARGET_SHA="$(git rev-parse rescue/before-reset^)"Soft copy only:
git reset --quiet --soft "$TARGET_SHA"Mixed copy only:
git reset --quiet --mixed "$TARGET_SHA"Hard copy only, in its disposable copy:
git reset --quiet --hard "$TARGET_SHA"In each copy read:
git rev-parse HEAD
git show :index.html
git status --shortEvery HEAD is M. The index holds SARA after soft and M's page after mixed and hard. The file on disk is OMAR after soft and mixed and M's page after hard. The statuses were:
Soft:
MM index.html
?? docs/signup-hint.mdMixed:
M index.html
?? docs/signup-hint.mdHard:
?? docs/signup-hint.mdThe terminal reset made no GitTree snapshot. git reflog still lists C, but OMAR is nowhere in it. In a separate backed-up lab, a hard reset to a commit that has a tracked docs/signup-hint.md overwrote an untracked file at that path.
Result
Where you end: all three branches are on M. Soft: the index holds SARA and the file holds OMAR. Mixed: the index holds M and the file holds OMAR. Hard: both hold M. The untracked note remains in each copy and rescue/before-reset is still on C.
Common mistakes
- Treating the rescue branch as a backup of newer, uncommitted work.
- Using hard reset to tidy a checkout without saving the edits first.
- Expecting soft reset to leave nothing staged.
- Resetting a branch you have already pushed, then pushing it over a teammate's work.
If something goes wrong
Use the rescue ref to find the committed heading again, and your outside copies for the edit and the note. In GitTree, a hard reset made through the app saved a snapshot first, so Undo can restore it. A reset made in the terminal did not.
Check your understanding
Answer each question, then read why. Questions marked “Required” count toward completing the lesson.
0 of 6 correct
Answer the required questions correctly to complete the lesson.
Checked in this browser.
Practice
Run the three read-backs in each copy and fill a table: where the branch points, what the index holds, what the file holds. Then say which mode you would use to redo the commit's message, which to unstage everything, and which to discard everything.
Your own confirmation: the site cannot see your computer.
To complete the lesson, answer the required questions correctly and confirm the practical exercise.
Recap
- Soft moves the branch only.
- Mixed also resets the index.
- Hard also rewrites your files.
Related
Glossary terms introduced
Reset — إعادة تعيين; soft — ناعمة; mixed — مختلطة; hard — كاملة; rescue branch — فرع حفظ.
Video transcript
The narration of the video, cue by cue.
Show the transcript
- Move a branch back, and choose how much else changes.
- Soft moves the branch. Mixed adds the index. Hard adds your files.
- So the difference is staged, unstaged, or gone.
- Build one start: a commit, a rescue branch, an unsaved edit and a note.
- Make three identical copies, and write down the ID of M.
- The edit was never committed. Keep a copy outside Git.
- The graph shows M, then C, and the rescue branch on C.
- Right-click M, open the reset submenu, and choose Soft.
- The dialog says every change stays staged, and no file changes.
- The branch is on M now. C is still on the rescue branch.
- The staged list has the old commit. The unstaged list has your edit.
- The file on disk still has your edit.
- Mixed copy: same menu, choose Mixed.
- This dialog says the changes stay, unstaged.
- Now index.html is only unstaged.
- Your edit is still in the file.
- Before hard, save the edit and the note somewhere else.
- Hard copy: choose Hard, with the dots that mean a warning.
- The dialog lists what is removed, and says it is saved first. Cancel is the default.
- Choose discard and reset.
- Only the note is left. The page is M's again.
- In the terminal, the first read is the commit. All three are M.
- git show with a colon reads the index. Soft keeps the old page.
- The status is different in each copy.
- The rescue branch is still on the older commit.
- And the file on disk: your edit twice, M's heading once.
- Change the input: no outside copy, and hard in the terminal.
- The reflog lists commits. The unsaved edit is nowhere in it.
- And hard overwrites an untracked file, if the target has one there.
- Soft and mixed lose nothing. Hard in the app is saved first.
- Practice: fill a table of branch, index and file for each mode.
- Next, undo a shared commit without rewriting history, with revert.