Gendi Notes

Git

Git tracks snapshots of your whole project, not changes to individual files — once that clicks, most of Git stops being confusing.

Level 1 guide gitversion-control

What is it?#

Git is a version control system. It records snapshots of your project over time, so you can see what changed, go back, and work on several things at once without them interfering.

Every developer has a complete copy of the history. You can commit, branch and search history with no network at all.

The one model you need#

Git has four places a file can be, and nearly every confusing Git moment comes from not knowing which one you are in.

WORKING DIR STAGING AREA LOCAL REPO REMOTE (your files) (next commit) (history) (GitHub) │ │ │ │ │── git add ─────→│ │ │ │ │── git commit ──→│ │ │ │ │── git push ──→│ │←─────────── git checkout ──────────│ │ │←────────────── git pull / fetch ──────────────────│
PlaceWhat it holdsCommand that moves things in
Working directoryFiles as they are right now(you edit them)
Staging area (index)What will go into the next commitgit add
Local repositoryCommitted history, on your machinegit commit
RemoteShared history on a servergit push

What it is made of#

ConceptWhat it is
CommitA snapshot plus a message, author and parent. Identified by a hash
BranchA movable pointer to a commit. Cheap — it is just a label
HEADWhere you are right now, usually the tip of a branch
RemoteA named URL for another copy, usually origin
TagA fixed label on one commit, for releases (v1.2.0)

Branches being just pointers is why creating one is instant and why having twenty costs nothing.

How to use it#

Starting out#

git init                              # start tracking a project here
git clone https://github.com/u/r.git  # copy an existing one

# Set your identity once, globally — commits are stamped with it
git config --global user.name "Your Name"
git config --global user.email "you@example.com"

The everyday loop#

This is 90% of Git use:

git status              # WHAT STATE AM I IN? Run this constantly
git diff                # unstaged changes
git diff --staged       # what's staged, i.e. what will be committed

git add file.js         # stage one file
git add .               # stage everything changed here
git commit -m "Fix login redirect"

git pull                # get others' work
git push                # publish yours

git status is the most useful command in Git. It tells you which of the four places your changes are in, and usually suggests the command you want next.

Branching#

git switch -c feature/login    # create a branch and move to it
git switch main                # move back
git branch                     # list local branches
git branch -d feature/login    # delete a merged branch

git switch is the modern command for changing branches. git checkout still works but does several unrelated jobs, which is why it confused people for a decade — switch (branches) and restore (files) split it up.

Merging vs rebasing#

Both bring another branch's work into yours. They produce different history.

MERGE — keeps what actually happened main A───B───────────M M is a merge commit with two parents \ / feature C───D───┘ REBASE — replays your commits on top, as if written later main A───B \ feature C'──D' C and D are NEW commits (different hashes)
MergeRebase
HistoryTruthful, shows the branchLinear, easier to read
Commit hashesUnchangedRewritten
Safe on shared branchesYesNo
git switch main && git merge feature/login    # merge
git switch feature/login && git rebase main   # rebase onto latest main

Undoing things — pick by what you want to undo#

This table is worth memorising; the wrong choice here is how work gets lost.

GoalCommandDestroys work?
Unstage a file, keep the editsgit restore --staged fileNo
Throw away edits to a filegit restore fileYes
Fix the last commit's messagegit commit --amendNo
Undo last commit, keep changes stagedgit reset --soft HEAD~1No
Undo last commit, keep changes unstagedgit reset HEAD~1No
Undo last commit and delete the changesgit reset --hard HEAD~1Yes
Undo a commit that is already pushedgit revert <hash>No

Stashing#

You are mid-change and need to switch branches urgently:

git stash               # put changes aside, clean the working directory
git stash list          # see what you stashed
git stash pop           # bring the most recent back and remove it from the stash
git stash apply         # bring it back but KEEP it in the stash

Looking at history#

git log --oneline --graph --decorate -20   # compact visual history
git log -p file.js                          # how one file changed over time
git log --author="Ahmed"
git blame file.js                           # who last changed each line, and when
git show <hash>                             # everything about one commit

When things go wrong#

Merge conflicts#

Git stops and marks the file when both sides changed the same lines:

<<<<<<< HEAD
const timeout = 3000;        ← your version
=======
const timeout = 5000;        ← incoming version
>>>>>>> feature/login

Edit the file to what it should be, delete all three marker lines, then:

git add file.js       # marks the conflict resolved
git commit            # (during a merge) or: git rebase --continue

To back out entirely: git merge --abort or git rebase --abort.

Other common situations#

SituationFix
rejected — non-fast-forward on pushSomeone pushed first. git pull --rebase, then push
Committed a secretRotate the secret immediately, then clean history. It is in the remote already
Committed to the wrong branchgit reset --soft HEAD~1, switch branch, commit again
Accidentally committed a huge fileRemove and amend if unpushed; otherwise git filter-repo
Detached HEADYou are on a commit, not a branch. git switch -c fix to keep the work

Two files that save you trouble#

.gitignore — never commit generated files, dependencies or secrets:

.gitignore
node_modules/
dist/
.env
*.log
.DS_Store

.gitattributes — normalise line endings across Windows/Linux teams:

.gitattributes
* text=auto
*.sh text eol=lf

Without the second one, a shell script committed on Windows gets CRLF line endings and fails on Linux with \r: command not found — an error that names the wrong problem entirely.

Interview corner · الأسئلة اللي بتتسأل#

Explain the difference between git reset, git revert, and git checkout.

They operate on different things, which is the real answer:

CommandMoves / changesRewrites history?Use when
git resetthe branch pointerYesThe commits are local only
git revertcreates a new commitNoThe commits are already pushed
git checkout / restorefiles in your working treeNoYou want to discard edits, or inspect an old version
before: A ─── B ─── C ← main, HEAD git reset --hard B → A ─── B ← main, HEAD (C is orphaned — findable via reflog) git revert C → A ─── B ─── C ─── C' ← main (C' undoes C; both remain in history)
A secret was committed and pushed two weeks ago. What do you do, in order?

Rotate the secret first. Everything else is second.

The order matters and getting it wrong is the failed answer:

  1. Revoke and reissue the credential. It is in the remote, in every clone, in forks, in CI logs, and possibly in a mirror or backup. Assume it is compromised — because it is.
  2. Remove it from the code so the new secret does not follow it in, and move it to a secret manager or an environment variable.
  3. Then, optionally, purge history with git filter-repo (or BFG) and coordinate a force-push, because every collaborator must re-clone.
  4. Add a guardrail so it cannot recur: a pre-commit hook or CI scanning step (gitleaks, trufflehog), plus branch protection.
How do you find which commit introduced a bug in a 2,000-commit history?

git bisect — a binary search over history. It finds the culprit in about 11 steps for 2,000 commits, instead of 2,000.

git bisect start
git bisect bad                  # the current commit is broken
git bisect good v1.4.0          # this tag was known good

# Git checks out the midpoint. Test it, then tell Git:
git bisect good     # or: git bisect bad
# repeat — Git halves the range each time

git bisect reset                # return to where you started

And if the test can be scripted, do not do it by hand at all:

# Any non-zero exit means "bad". Git runs it on each candidate.
git bisect start HEAD v1.4.0
git bisect run npm test

Key takeaways#

  • Four places: working dir → staging → local repo → remote. git status tells you which one you are in.
  • Branches are pointers. Creating them is free.
  • Merge keeps history, rebase rewrites it. Only rebase your own unpushed work.
  • reset for local commits, revert for pushed ones.
  • --hard and git restore <file> are the only two commands here that delete work. Everything else is recoverable.
  • git reflog finds commits you thought you destroyed.
  • git bisect run finds the commit that broke it, automatically.

Last updated 2026-09-08