• Four areas where git stores information - stash —–> working area —–> index —-> repository
  • For every command, understand how it moves information between these areas, how does the repository change because of this
  • Git repository - inside .git, mostly importantly .git/objects
    • Kinds of objects - blob(files), tree(folders), commit(every git commit). All objects are immutable. Objects are linked. Every commit is a snapshot of the working area at a point in time. Commmits point to trees that point to blobs
    • A branch is a reference/pointer to a commit. A commit refers to parent commit - giving the entire history of commits. So a branch refers can give you the history of commits
    • Special pointer called HEAD that points to a branch(usually current branch), which means it indirectly points to a commit(current commit)
    • Some commits can be unreachable (no branch pointing to them), and git will garbage collect them
  • Index stands between working area and repository(.git/index), aka staging area. Its a binary file
    • In a clean state, the working area and repository are aligned. They contain the same stuff, meaning the current commit is aligned.The repository could contain other commits and other objects
    • As a mental model, assume the index contains everything from working directory in a clean state, not just the changes.
      • So git diff doesnt return anything (diff between working directory and index )
      • git diff --cached also doesnt return anything (diff between index and repository)
  • Moving data from left to right - git add, git commit, git mv
  • Moving data from right to left
    • What happens when you git checkout branch_other
      • HEAD points to brach_other, so current branch and current commit are different, no data change in repository, just change in HEAD pointer
      • Current data from HEAD is copied to working directory and index, so all three areas are in sync. This happens only in a clean state. Otherwise, changes in index and working directory from old branch are carried forward to the new branch
      • This can also be used to discard changes in working directory and keep it in sync with the index git checkout -- <filename>
    • git rm --cached`<filename> to remove from index, but keep in working area. Use git rm generally to Remove files from the index, or from the working tree and the index. git rm will not remove a file from just your working directory
  • git reset
    • Changes in repository: It moves a branch, it doesnt move HEAD. It just moves current branch to point to a different commit.
    • By default its a --mixed. Copy changes from repository to index. Using --hard option copies changes to both working directory and index. --soft option doesnt make any changes to index or working area. Only changes current branch to a different commit.
    • Unreachable commits can be garbage collected by git
    • git rm --cached is not the only way to remove files from index. git reset HEAD -> Step 1 of moving the branch to the commit that HEAD points to is moot because branch is already doing that. Step 2 is moving the changes in that commit to index. The result is nothing but unstaging changes. A hard reset will move everything to working directory. All changes in working directory and index are in sync with current commit. Distructive Command
  • The stash (the fourth area). Your personal area, exclusive called by the git stash command. No other command messes with the stash. Use to store stuff to set aside like a clipboard, and get back to it later


  • Stage and commit with one command, only works for previously staged files - git commit -am <message>
  • Reset changes to commit one before the current HEAD(last commit), and keep files staged - git reset --soft HEAD^


  • See all diffs in your branch compared to another branch, say develop - git diff --name-only develop...
  • Diffs without whitespaces - git diff -w
  • Diffs that show changed words instead of lines - git diff --word-diff


  • List all branches sorted by most recent commits - git branch --sort=-committerdate
  • Similar to above, with local branches - git for-each-ref --count=10 --sort=-committerdate refs/heads/ --format="%(refname:short)"


  • Who has committed how much to a project - git shortlog -sn --all --no-merges or git shortlog -sn --since='10 weeks' --until='2 weeks'
  • Praise/Blame people git blame -L5,10 _components.buttons.scss
  • See summary of all work - git log --all --oneline --no-merges
  • Remind yourself what you’ve been upto - git log --all --oneline --no-merges --author=<your email address>