Commits
A good commit holds one logical change and says why it was made. This lesson shows how to choose exactly what goes into a commit, check it before you save it, fix the last one, keep junk out, and make sure it carries the right name.
The examples continue the trip-planner repository from lesson 1, with a twelve-line packing.txt.
See what you changed: git diff
You make two unrelated edits to packing.txt: you change Tickets to Train tickets near the top, and add Sunglasses at the bottom. git diff shows what changed in the working tree compared with the staging area:
git diffdiff --git a/packing.txt b/packing.txt
index 07ec381..6aba0a6 100644
--- a/packing.txt
+++ b/packing.txt
@@ -1,5 +1,5 @@
Passport
-Tickets
+Train tickets
Phone charger
Toothbrush
Rain jacket
@@ -10,3 +10,4 @@ Water bottle
Snacks
Book
Headphones
+SunglassesHow to read it:
- Lines starting with
-were removed, lines starting with+were added. A changed line shows as one removal and one addition. - Lines starting with a space are unchanged context, shown so you can see where the change is.
- Each
@@ … @@line starts a hunk: one block of nearby changes.-1,5 +1,5means "lines 1 to 5 before, lines 1 to 5 after".
This diff has two hunks, because the two edits are far apart.
| Command | Compares |
|---|---|
git diff | Working tree with the staging area: what you have not staged yet |
git diff --staged | Staging area with the last commit: what will be committed |
git diff HEAD | Working tree with the last commit: everything since then |
--cached is another name for --staged.
Stage part of a file
The two edits are two different changes, so they belong in two commits. You can stage one hunk and leave the other.
In a terminal, git add -p (for "patch") walks through each hunk and asks:
git add -p@@ -1,5 +1,5 @@
Passport
-Tickets
+Train tickets
Phone charger
Toothbrush
Rain jacket
(1/2) Stage this hunk [y,n,q,a,d,k,K,j,J,g,/,e,p,P,?]? y
@@ -10,3 +10,4 @@ Water bottle
Snacks
Book
Headphones
+Sunglasses
(2/2) Stage this hunk [y,n,q,a,d,K,J,g,/,e,p,P,?]? ny stages the hunk, n skips it, q stops, ? explains every letter. Now the same file is both staged and not staged:
git status --shortMM packing.txtCheck exactly what will be committed:
git diff --staged…
@@ -1,5 +1,5 @@
Passport
-Tickets
+Train tickets
Phone charger
…Only the tickets change. Commit it, then stage and commit the rest:
git commit -m "Say which tickets to pack"
git add packing.txt
git commit -m "Add sunglases to packing list"[main f11adbc] Say which tickets to pack
1 file changed, 1 insertion(+), 1 deletion(-)
[main 77774ef] Add sunglases to packing list
1 file changed, 1 insertion(+)In BranchPilot, select the file under Unstaged to see its diff, then select Stage hunk on the hunk you want. The file then appears under both Staged and Unstaged, the same as MM above.
TIP
Read git diff --staged (or the Staged view in BranchPilot) before every commit. It is the cheapest way to catch a stray debug line, a password or a file you did not mean to include.
Fix the last commit: amend
The second message has a typo. --amend replaces the most recent commit with a corrected one:
git commit --amend -m "Add sunglasses to packing list"
git log --oneline -2719f474 Add sunglasses to packing list
f11adbc Say which tickets to packThe commit has a new hash, 719f474 instead of 77774ef: amending makes a new commit and drops the old one from the branch. To add a forgotten file instead, stage it and run git commit --amend --no-edit to keep the message.
In BranchPilot, turn on Amend in the commit box. See Amend the last commit.
WARNING
Only amend commits you have not pushed. Once other people have the old commit, replacing it causes trouble for them. Lesson 4 explains why.
Write messages people can use
In six months, the message is the only explanation anyone has. A widely used convention:
Add sunglasses to packing list ← subject: what, in about 50 characters
The forecast says 30 degrees on Saturday ← blank line, then the body: why
and we will be outside most of the day.- Subject: one line, ideally 50 characters or fewer, never more than 72. No full stop at the end.
- Write it as a command: "Add", "Fix", "Remove", not "Added" or "Adding". Read it as "This commit will… add sunglasses to packing list."
- Body (optional): after a blank line, explain why the change was needed. The diff already shows what changed.
- One logical change per commit. "Fix login bug and rename variables and update logo" is three commits.
| Weak | Better |
|---|---|
fix | Fix crash when the packing list is empty |
changes | Say which tickets to pack |
WIP | Add draft day plan for Saturday |
To write a body, run git commit without -m. Git opens your text editor; write the subject, a blank line and the body, then save and close. In BranchPilot, use Commit subject and Description (optional); the counter turns amber past 50 characters and red past 72.
Keep files out: .gitignore
Some files should never be committed: settings with passwords, logs, build output, editor junk. A file called .gitignore at the top of the repository lists patterns Git should ignore.
git status --short?? .env
?? build/
?? debug.logCreate .gitignore with:
.env
*.log
build/Now Git stops offering those files:
git status --short?? .gitignoreCommit .gitignore itself, so everyone who works on the project gets the same rules.
| Pattern | Ignores |
|---|---|
.env | Any file or folder called .env |
*.log | Every file ending in .log |
build/ | Any folder called build, with everything in it |
/notes.txt | notes.txt at the top of the repository only |
!keep.log | Un-ignores keep.log, even though *.log matched it |
To find out why a file is ignored, ask Git:
git check-ignore -v debug.log.gitignore:2:*.log debug.log.gitignore does not untrack
Ignoring only affects files Git is not already tracking. If .env was committed before you added the rule, Git keeps tracking it. Stop tracking it with git rm --cached .env (the file stays on disk) and commit. The old commits still contain it, which matters a lot if it held a password: see Stay safe.
Your identity: name and email
Every commit records an author name and email from two settings:
git config --global user.name "Asha Rao"
git config --global user.email "asha@example.com"--global saves them in your user settings file (~/.gitconfig) for every repository. Without --global, run inside a repository, they apply to that repository only and override the global ones. To see which value wins and where it comes from:
git config --show-origin user.emailfile:.git/config asha.rao@work.exampleIf Git has no identity at all, the commit stops:
Author identity unknown
*** Please tell me who you are.
Run
git config --global user.email "you@example.com"
git config --global user.name "Your Name"
to set your account's default identity.
Omit --global to set the identity only in this repository.Why the wrong identity matters
The name and email are not a sign-in; Git does not check them. But hosting sites use the email to link each commit to an account, and the history is permanent once shared. Common accidents:
- Work commits under your personal email. Your private address is now in your employer's history, and the commits may not count as yours on the work account.
- Personal or open-source commits under your work email. Your employer's address appears in public projects.
- A placeholder identity like
root@localhostthat links to nobody.
Fixing an identity after a push means rewriting history, so it is far better to get it right first. Two habits help:
- Before your first commit in a new repository, run
git config user.emailand check the answer. - If you do not want your email public, hosting sites such as GitHub offer a private "noreply" address you can use as
user.email.
If you work as more than one person, for example work and personal accounts on Windows, DhivaLabs Shell gives each identity its own commit name and email, SSH key and history, and its guard blocks a commit or push when the repository belongs to another identity. See Commit identity and the Git guard.
To fix the author of the last commit, before you push: set the right identity, then run git commit --amend --reset-author --no-edit.
Check yourself
Question 1 of 6
You fixed a bug at the top of a file and left a debug line at the bottom. How do you commit only the fix?
What you learned
git diffshows unstaged changes;git diff --stagedshows what the next commit will contain.- A hunk is one block of nearby changes;
git add -por BranchPilot's Stage hunk stages one at a time. - A good commit is one logical change with a short subject in the command form and a body that says why.
git commit --amendreplaces the last commit; do it only before you push..gitignorekeeps untracked files out, but does not untrack files already committed.user.nameanduser.emailgo into every commit; check them before you commit in a new repository.
Next steps
- Branches and merging
- Stage changes and commit in BranchPilot