EduFlow
Git & GitHub
0%

Section 4 · Professional Habits

Stash and .gitignore

15 min4 min readSpot the bug

Lesson at a glance

Park unfinished work with git stash and bring it back later, and write a .gitignore that keeps dependencies, build output, secrets and OS clutter out of your repository.

  1. 1Stash: a drawer for unfinished work
  2. 2.gitignore: files Git should never track
  3. 3How patterns work
  4. 4Ignoring doesn’t untrack

No video here — just the real thing: a written lesson, runnable examples, a quiz and practice.

Two small tools keep a working tree under control. git stash gives you a drawer for work that isn’t ready to commit. .gitignore tells Git which files it should never track at all. Both prevent the same kind of accident: the wrong thing ending up in a commit.

Stash: a drawer for unfinished work

You’re halfway through the portfolio’s contact form on the contact-form branch when someone points out a typo on the live home page. You need main, now. But git switch main refuses, because your edits to index.html would be overwritten, and you don’t want to commit a half-built form.

Stash it:

Terminal
git stash push -m "contact form: fields done, validation next"
git status        # nothing to commit, working tree clean

Your changes, staged and unstaged, are saved in a stash entry and removed from the working tree. Now fix the typo:

Terminal
git switch main
# fix, commit, push
git switch contact-form
git stash pop

pop reapplies the most recent stash and deletes it. You’re back exactly where you were.

The other stash commands you’ll use:

Terminal
git stash list                  # stash@{0}: On contact-form: contact form: fields done…
git stash show -p stash@{0}     # the diff inside a stash
git stash apply stash@{1}       # reapply but keep the stash
git stash drop stash@{1}        # delete one stash
git stash push -u -m "…"        # include untracked (new) files too

That last flag matters. By default stash only saves changes to tracked files. A brand-new contact.js stays in your folder, untouched, which surprises people when they pop and it isn’t “restored”. Use -u whenever you’ve created files.

Stashes aren’t tied to a branch: you can pop one onto any branch, which is occasionally handy and occasionally a surprise. If you realise the stashed work deserves its own branch after all, git stash branch contact-validation creates a branch at the commit where you stashed, applies the stash there and drops it, which sidesteps conflicts with anything that has changed since.

If pop hits a conflict, Git applies what it can, marks the conflict as usual, and keeps the stash instead of dropping it. Resolve, git add, and run git stash drop once you’re sure.

.gitignore: files Git should never track

Some files belong in your project folder but never in history:

  • dependencies you can reinstall, such as node_modules/;
  • build output you can regenerate, such as dist/;
  • secrets and machine-specific settings, such as .env;
  • clutter from your OS and editor, such as .DS_Store on macOS.

List them in a file called .gitignore at the repository root and commit it, so everyone on the project shares the rules:

.gitignore
# Dependencies
node_modules/

# Build output
/dist/

# Local environment and secrets
.env
.env.*
!.env.example

# OS and editor files
.DS_Store
*.log

Ignored files disappear from git status and git add . skips them.

How patterns work

Each line is a pattern, matched against paths relative to the .gitignore file’s folder:

  • # starts a comment, but only at the beginning of a line. Blank lines are ignored.
  • *.log matches any file ending in .log, in any folder.
  • A trailing / matches directories only: node_modules/.
  • A leading / anchors the pattern to this folder: /dist/ ignores the root dist but not src/dist.
  • **/ matches any depth: **/fixtures/*.json.
  • ! re-includes something an earlier line excluded: !.env.example keeps the template for other developers. It can’t re-include a file whose parent folder is excluded, because Git never looks inside an ignored folder.

When a file is ignored and you don’t know why, ask Git:

Terminal
git check-ignore -v dist/app.js
Text
.gitignore:5:/dist/	dist/app.js

It prints the file, line number and pattern responsible.

For clutter that only your machine creates, don’t burden every project’s .gitignore. Git also reads a global ignore file, ~/.config/git/ignore, which is a good home for .DS_Store and editor folders. GitHub keeps a collection of starter .gitignore templates for most languages, and offers one when you create a repository.

Ignoring doesn’t untrack

.gitignore only affects untracked files. If .env was committed before you ignored it, Git keeps tracking it. Remove it from the index and commit, which keeps your local file:

Terminal
git rm --cached .env
git commit -m "Stop tracking .env"

Your working tree is now clean and your repository holds only what it should. Next you’ll make what it holds readable: commit messages, tags and releases.

Key takeaways

  • git stash push -m "…" saves your uncommitted changes and cleans the working tree; git stash pop brings them back and removes the stash.
  • git stash skips untracked files unless you add -u (--include-untracked).
  • .gitignore only affects untracked files; to stop tracking a committed file, run git rm --cached and commit.
  • In .gitignore, a trailing / matches directories only, a leading / anchors to that folder, and ! re-includes a file.
  • A secret that was ever committed and pushed must be revoked and replaced, because history still contains it.

Further reading

Check your understanding

4 questions

Question 1 of 4

You’re halfway through the contact form when an urgent typo fix is needed on main. git switch main refuses because it would overwrite your changes. What’s the quickest clean route?

Question 2 of 4

You stashed, switched branches, and came back. git stash pop restored your edits to contact.html but your new file contact.js is missing. Why?

Question 3 of 4

You committed .env last week. Today you add .env to .gitignore, but git status still shows .env as modified. Why?

Question 4 of 4

Which .gitignore line ignores the dist folder at the project root but not a src/dist/ folder?

Practice

Spot the bug

Fix the portfolio's .gitignore

This .gitignore sits at the root of the portfolio repository, which contains index.html, styles.css, projects.html, a .env with an API key, secrets.json, and macOS .DS_Store files in several folders. Three lines don’t do what their author intended. Select them.

Select the line(s) you think are wrong, then check.