Lesson 10 / 15
Unstaging and Restoring Files
Undoing the staging-area record and the working-directory content separately; choosing a source, and which situations are recoverable.
Contents
The Basic Cycle was told in one direction: a change is made, staged, committed. This topic takes up the reverse direction. The first lesson defines the two narrowest-scoped operations; neither touches history, both affect only the working directory and the staging area.
The distinction has to be established from the start, because the two operations undo different things, and one costs more than the other.
Two Separate Kinds of Undoing
| Operation | Region affected | Source | What is lost |
|---|---|---|---|
| Unstaging | Staging area | Last commit | Nothing |
| Restoring a file | Working directory | Staging area or a commit | Unrecorded edits |
The first operation is reversible: unstaged content keeps standing in the working directory. The second is not — if the edit in the working directory was not stored anywhere, it is gone once overwritten.
The Mistake
While two terms are being added to the term list, an edit is also made to the search
script: the -x option is added to the grep call. This option requires the match to
cover the whole line, and it breaks the script:
./ara.sh yığıt
eşleşme yok: yığıt
The term is in the list, yet it cannot be found: -x requires the pattern “yığıt” to
equal the entire yığıt | stack line. Without the mistake being noticed, two changes are
staged together:
git add .
git status --short
M ara.sh M terimler.txt
The term addition should be kept; the edit in the script should be undone.
Unstaging
git restore --staged ara.sh git status --short
M ara.sh M terimler.txt
ara.sh’s mark moved from the first column to the second: the file is no longer in the
staging area, it is changed only in the working directory. The command returned the
staging-area entry to its state at the last commit; it did not touch the working
directory.
To confirm this, the diff is taken:
git diff
diff --git a/ara.sh b/ara.sh
index 582ddde..fd7e235 100755
--- a/ara.sh
+++ b/ara.sh
@@ -6,7 +6,7 @@ if [ $# -ne 1 ]; then
exit 1
fi
-if ! grep -i -- "$1" terimler.txt; then
+if ! grep -ix -- "$1" terimler.txt; then
echo "eşleşme yok: $1" >&2
exit 2
fi
The edit is still standing. At this point there are two options: fix the edit by hand, or undo it entirely.
Restoring the Working Directory
git restore ara.sh
git status --short
M terimler.txt
./ara.sh yığıt
yığıt | stack
The script works again. git restore returned the file to its state in the staging area;
and since the staging area is identical to the last commit, the result is the file’s
state at the last commit.
This command is destructive. The edit it undoes was never stored anywhere; it had no record in the object database or in the staging area. After the command runs, that text cannot be brought back. As a rule, it should not be run without being certain the edit to be undone is really unwanted; if there is any doubt, the change should first be staged or put in the stash. The stash is the subject of this topic’s fifth lesson.
The remaining change is committed:
git commit -m "Öbek ve dizi terimlerini ekle"
[main bfe57d3] Öbek ve dizi terimlerini ekle 1 file changed, 2 insertions(+)
Choosing the Source
By default, git restore’s source is the staging area. The --source option makes
another commit the source:
git restore --source=HEAD~1 terimler.txt git diff --stat
terimler.txt | 2 -- 1 file changed, 2 deletions(-)
The file returned to its state at the previous commit; two lines were removed. This is a
way to inspect a past version or bring back a single file. The change is only in the
working directory; history stays as it was, and git restore terimler.txt returns to the
latest state.
The regions the command affects can be chosen explicitly:
| Form | Affected |
|---|---|
git restore <path> |
Working directory |
git restore --staged <path> |
Staging area |
git restore --staged --worktree <path> |
Both |
The third row returns a file entirely to its state at the last commit.
Bringing Back a Deleted File
Deletion is a change too, and it is undone with the same tool. If the term list is deleted by mistake:
git status --short
D terimler.txt
The D mark is in the second column: the file has been removed from the working
directory, but its record in the staging area is still standing. Since the record
carries a blob ID, the content is in the object database:
git restore terimler.txt
git status --short
The second command prints nothing; the file has come back. If the deletion was staged
too (if D appears in the first column), it is necessary to unstage first, then
restore; --staged --worktree does both in a single command.
This is a direct consequence of the previous section’s criterion: the deleted file’s content was tracked, so it was in the object database. When an untracked file is deleted, it cannot be brought back.
Older Forms
The same jobs can be done with older commands, and these forms are common in documentation:
git reset HEAD terimler.txt # unstaging git checkout -- terimler.txt # restoring the working directory
The first command prints this notice:
Unstaged changes after reset: M terimler.txt
The problem with the two older forms is that the commands are overloaded: git reset is
also the command that rewinds history, git checkout is also the command that switches
between branches. The same name producing very different results makes it hard to read
which operation is being done from the command. git restore and git switch were
defined to name this distinction. The older forms remain valid; this course will use the
new names.
What Can Be Recovered
The limit of the undo tools reduces to a single criterion: was the content written to the object database?
| State | In the object database | Recoverable |
|---|---|---|
| Committed content | Yes | Yes |
| Staged content | Yes (as a blob) | Yes |
| Working-directory-only edit | No | No |
| Untracked file | No | No |
The second row can be unexpected: the moment git add runs, the content is written as a
blob and stays in the database even if no commit follows. Even content that has been
unstaged and then overwritten can still be read with git cat-file, as long as its ID is
known. An edit that was never staged, by contrast, leaves no trace at all.
The practical consequence is this: a change worked on over a long stretch is protected against a destructive command if it is staged from time to time. This is the staging area’s second function, beyond preparing for a commit.
Summary
- Unstaging affects the staging area, restoring a file affects the working directory.
git restore --stagedreturns the record to its state at the last commit and loses no data.git restoreundoes the edit in the working directory destructively.- With
--source, a commit can be chosen as the source;--staged --worktreerestores both regions at once. - The criterion for recoverability is whether the content was written to the object database; staging provides this guarantee.
Next Step
These tools undo changes that have not yet been committed. What happens if a commit that has already been written is missing something or has a mistake? The next lesson takes up amending the last commit, why this operation produces a new object, and in which situations it should not be used.
To keep your progress and take notes, Log in
My notes
Log in to take notes.