السجل والفروقات (diffs)
في هذا الدرس 11 موضوعات
هذا الدرس متاح حاليًا باللغة الإنجليزية فقط، ولم تُنشر نسخته العربية بعد.
Lesson Overview
You can now record snapshots. This lesson is about reading them back. Three commands do almost all of the looking: git status (what is the state right now), git log (what has been recorded), and git diff (what exactly changed). Together they answer the questions every developer asks many times a day: "What did I just change?", "What is about to go into my commit?", and "What happened last week?".
These are read-only commands. None of them changes your files or your history, so you can run them as often as you like. That makes them the safest way to build confidence with Git.
You need a repository with a few commits (lesson L02). The examples below use a small Account class that grows over three commits. The commands were run with Git 2.44; hashes, dates, and some wording will differ on your machine.
Learning Objectives
By the end of this lesson you will be able to:
- Use
git statusandgit status -sto see untracked, modified, and staged files. - List history with
git log,git log --oneline, and a limit such as-5. - Read the output of
git diff: the file header, the@@hunk header, and the-and+lines. - Show unstaged changes with
git diffand staged changes withgit diff --staged, and say why they differ. - Check what a particular commit changed with
git show. - Follow a safe habit:
statusanddiffbefore every commit.
Written Explanation
Our example history
Imagine the Account class from the Bank Accounts project, built over three commits:
aaf0772 Ignore withdraw larger than balance
60242ac Add withdraw method
f605473 Add Account class with depositYour hashes will be different. We will look at this history in several ways.
git log: the list of commits
git logcommit aaf077208112526fd8eba4b39a969d05fba1cdd9
Author: Sara Student <sara@example.com>
Date: Wed Nov 4 06:42:30 2026 +0200
Ignore withdraw larger than balance
commit 60242ac58e4436bb5d1679c878c43930e2a19bca
Author: Sara Student <sara@example.com>
Date: Wed Nov 4 06:42:30 2026 +0200
Add withdraw method
commit f6054739a5622a83e0f743a2b31dec68e8f91e7f
Author: Sara Student <sara@example.com>
Date: Wed Nov 4 06:42:29 2026 +0200
Add Account class with depositNewest first. Each entry is one commit: its full hash (a long identifier Git computes for the commit; it is unique, and you can refer to it by its first few characters), the author, the date, and the message. This is the "who, when, why" from lesson L01. If the output is longer than your screen, Git shows it in a pager: press q to quit.
The full format is thorough but long. Most of the time you want the compact form:
git log --onelineaaf0772 Ignore withdraw larger than balance
60242ac Add withdraw method
f605473 Add Account class with deposit--oneline prints an abbreviated hash and the first line of the message. This is also where good messages pay off: this list is only useful if each line says something. To limit the number of commits, add -n or just a number:
git log --oneline -2aaf0772 Ignore withdraw larger than balance
60242ac Add withdraw methodgit log --oneline -5 shows the last five commits, and git log --oneline -3 -- Account.java shows only commits that touched that file.
git show: one commit in detail
git show --stat --oneline HEADaaf0772 Ignore withdraw larger than balance
Account.java | 4 +++-
1 file changed, 3 insertions(+), 1 deletion(-)HEAD means "the commit you are currently on" (the latest one, for now). --stat summarises which files changed and how many lines. Without --stat, git show prints the full diff of that commit, which brings us to diffs.
git diff: what changed, line by line
A diff compares two versions of the text and shows the lines that differ. Edit deposit to use a longer form, without staging anything:
git diffdiff --git a/Account.java b/Account.java
index 077584d..34f2619 100644
--- a/Account.java
+++ b/Account.java
@@ -2,7 +2,7 @@ public class Account {
private double balance;
public void deposit(double amount) {
- balance += amount;
+ balance = balance + amount;
}
public void withdraw(double amount) {How to read it:
--- a/Account.javaand+++ b/Account.java: the old version (a) and the new version (b).@@ -2,7 +2,7 @@: a hunk header. It means "starting at line 2 of the old file, 7 lines are shown; starting at line 2 of the new file, 7 lines are shown".- Lines starting with a space are unchanged context.
- A line starting with
-was removed. A line starting with+was added. A changed line appears as one-and one+.
The index line (with the hashes) is Git's internal bookkeeping; you can ignore it for now. If your terminal supports colour, removed lines are usually red and added lines green.
Unstaged versus staged: two different diffs
Because of the three areas (lesson L02), there are two natural comparisons:
| Command | Compares | Answers |
|---|---|---|
git diff | working tree against staging area | What have I changed that is not yet staged? |
git diff --staged | staging area against last commit | What will go into my next commit? |
Continue the example: stage the change.
git add Account.java
git diffThis prints nothing, because there is no difference between the working tree and the staging area any more. Now:
git diff --stagedprints the same diff as before. The change did not vanish; it moved to the staged side. This is the single most common point of confusion for beginners: "git diff shows nothing, did my change disappear?" Run git diff --staged before you worry. (--cached is a synonym.)
You can also compare two commits: git diff HEAD~2 HEAD --stat compares the commit two steps back (HEAD~2) with the latest one.
git status: the summary
git status -s after editing the file but before staging:
M Account.javaThe left column is the staging area, the right column is the working tree. A space on the left and M on the right means "modified, not staged". After git add, it becomes M (modified on the left, staged). git status without -s says the same in sentences and suggests commands.
The safe habit
Before each commit:
git status # which files are involved?
git diff # what exactly is unstaged?
git diff --staged # what exactly will be committed?It takes ten seconds and catches the commit that includes a debugging line, a half-finished edit, or a file that should not be there. Reading the diff of your own work is also the cheapest code review you will ever get.
Examples
Example 1: What did I just do? (simple)
You come back to a project after a break and do not remember where you stopped.
git status -s
git log --oneline -3status shows if anything is half-done; log shows the last three steps. Two commands, thirty seconds, and you know where you are.
Example 2: Checking before commit (practical)
You changed Account.java. Before committing:
git diffYou notice a line System.out.println("DEBUG " + balance); that you added while testing. You delete it, run git diff again to confirm it is gone, and then:
git add Account.java
git diff --staged
git commit -m "Ignore withdraw larger than balance"Without the diff, the debugging line would be in your project history permanently.
Example 3: Finding when something changed (realistic)
A teammate reports that withdrawals larger than the balance are now silently ignored. Is that intended? Search the history of the file:
git log --oneline -3 -- Account.javaaaf0772 Ignore withdraw larger than balance
60242ac Add withdraw method
f605473 Add Account class with depositThe newest message says it was a deliberate choice. To see exactly what that commit did:
git show aaf0772You read the diff and see the if (amount <= balance) check was added. You now know when, who, why, and how. Whether that behaviour is a good design (silently ignoring is debatable) is a separate discussion, but at least it is not a mystery.
Backend Insight
In backend work, a bug report often arrives as "it worked last week". Commands from this lesson turn that into a search: git log --oneline to list candidates, git show to read what each did, and git diff between two commits to see everything that changed over a period. This is how teams find the change that caused an incident, and why precise messages matter: they let the log be skimmed at speed.
The same habit protects you at the other end. Backend repositories can contain configuration with database addresses and other sensitive values. Running git status and git diff --staged before every commit is how you notice them before they enter a history that is hard to clean.
Common Mistakes
Mistake 1: "git diff shows nothing, so nothing changed"
- Incorrect: "The diff is empty, so my edit was lost."
- Correct: "
git diffshows only unstaged changes. I staged it, so I needgit diff --staged."
Mistake 2: Committing without looking
What goes wrong: debug lines, stray files, or half-finished edits end up in history. How to avoid it: git status then git diff --staged before every commit.
Mistake 3: Being stuck in the pager
When git log output is long, Git shows a pager and the prompt does not return. Press q to leave it.
Mistake 4: Confusing hash and message
The short hash identifies a commit; the message only describes it. Two commits can have identical messages, so use the hash to refer to a specific one.
Exercises
Level A: Foundation
A1. Which command lists past commits, newest first, one line each?
أظهر الحل A1
A1. git log --oneline.
A2. What do the - and + mean at the start of a line in a diff?
أظهر الحل A2
A2. A line starting with - was removed (it exists only in the old version); a line starting with + was added (it exists only in the new version).
A3. Which command shows changes that are staged but not yet committed?
أظهر الحل A3
A3. git diff --staged (or git diff --cached).
Level B: Application
B1. In a repository with at least three commits, show only the last two commits in compact form. Write the command and what the output looks like.
أظهر الحل B1
B1. git log --oneline -2. Output is two lines, each an abbreviated hash and a message, newest first.
B2. Edit one line of a tracked file. Run git diff, then git add that file, then run git diff again and git diff --staged. Describe the three outputs and explain the difference.
أظهر الحل B2
B2. The first git diff shows the change (working tree differs from staging area). After git add, git diff shows nothing, because the working tree and staging area now match. git diff --staged shows the same change as the first diff, because staging now differs from the last commit.
B3. Read this hunk header: @@ -10,6 +10,8 @@. What does it tell you about the size of the change?
أظهر الحل B3
B3. The old version shows 6 lines from line 10, the new version shows 8 lines from line 10, so two more lines are present in the new version (for example, two lines were added).
Level C: Challenge
C1. You want to know every commit that touched Bank.java, and then exactly what the most recent one changed. Write the commands.
أظهر الحل C1
C1.
git log --oneline -- Bank.java
git show <hash-of-the-newest-one>Replace the placeholder with the first hash from the list. git log --oneline -1 -- Bank.java shows only that newest commit.
C2. A teammate runs git diff, sees nothing, and says "Git lost my edit". Their git status -s shows M Bank.java. Explain what happened and how they can see the change.
أظهر الحل C2
C2. M in the left column means the change is staged. git diff compares the working tree with the staging area, which now match, so it prints nothing. git diff --staged shows the change; the edit is not lost.
Mini Challenge
In a repository of yours with at least three commits, produce a short "report" using only Git commands (copy the real output into a text file):
- The one-line history of the whole project.
- The full details of the middle commit.
- A diff of an edit you make but have not staged, and then the same edit staged.
Add one sentence explaining which command you would use to answer: "What will my next commit contain?"
Check your work: your report has three real outputs, and the sentence names git diff --staged.
Summary & Next Lesson
Key takeaways
git log --onelinelists history compactly;-nlimits the count;-- filelimits to a file.git showdisplays one commit.- A diff shows removed lines with
-and added lines with+; the@@header tells where. git diffis unstaged;git diff --stagedis what the next commit will contain.- Run
git statusandgit diffbefore every commit.
Next lesson
Next is "Branches": you will create a separate line of commits so you can work on a feature without touching the working version.
Self-check
- Which command lists the commits?
- Which command shows staged changes?
- After
git add,git diffprints nothing. Why? - What does
HEADmean? - How do you leave the pager in
git log?
أظهر الإجابات
git log(orgit log --onelinefor the compact form).git diff --staged.- It compares the working tree with the staging area, and they are now the same.
- The commit you are currently on, usually the latest one.
- Press
q.
References
- Pro Git book, "Recording Changes to the Repository". It supports the definitions of
git diff(unstaged) andgit diff --staged(staged against last commit), and the two-columngit status -sformat. - Git documentation,
git log. It supports--oneline(abbreviated hash and title) and-n <number>limiting the commits shown. I read only the first part of this long page. - Not verified from an official page: the pager behaviour (
qto quit) and the detailed meaning of the@@hunk header; both are from running the commands and general Git knowledge. All outputs above were produced with Git 2.44 in a scratch repository.
التطبيق
طبّق هذا الدرس بمختبر الوحدة وتمارينها واختبارها.
تعليم الدرس كمكتمل اختياري ويمكنك التراجع عنه في أي وقت. يبقى تقدمك محفوظًا في هذا المتصفح.