Skip to main content

HEAD 💀

HEAD is just a special pointer which points to current state (commit) of our repo.

Reflog

reflog is a special log which only stores the moving history of HEAD pointer.

Why it is useful ?

🤔Problem

This will be an interesting set of tasks to do, but can be quite useful in understanding reflog.

  1. create a new branch off of master, call it baz.
  2. add one commit to baz. Do it in a new file baz.md
  3. switch back to master and delete baz (git branch -D baz from earlier)
  4. can you bring back from the dead the commit sha of baz?

Moving HEAD

We can also move HEAD relative to its position, to walk back commits. We use a special syntax with ~n to give relative position of commits wrt to current commit.


git checkout HEAD~3

Reset

Let's define the states you mentioned:

  1. Repository (Committed): This is your local commit history. Each commit is a snapshot of your project. HEAD points to the latest commit on your current branch.
  2. Staged (Index): This is where you prepare your next commit. When you git add a file, its changes are moved to the Staging Area.
  3. Working Directory (Unstaged Changes): These are the actual files on your disk that you are currently editing. Changes here are tracked by Git if the file is tracked, but they are not yet part of the Staging Area or a commit.
  4. Removed (Clean Slate): This implies that changes in the Working Directory (and possibly Staging Area) that are not committed are discarded, making the Working Directory match a specific commit (often HEAD).

We can reset current state of repo to some previous state.

there are 2 options to reset to a previous state

git reset <target_commit>

# or

git reset --soft <target_commit>

# or

git reset --hard <target_commit>

--soft: The Repo branch now points to <target_commit>. Work from commits after <target_commit> is moved to the Staging Area; any pre-existing Staging Area work also remains staged there. The Working Dir (your current files with any unstaged changes) and Untracked (new) files are untouched.

--mixed (This is the default one): The Repo branch now points to <target_commit>. Work from commits after <target_commit> AND any pre-existing Staged work are moved to the Working Dir as unstaged changes (the Staging Area itself is reset to match <target_commit>). Pre-existing unstaged changes in the Working Dir and Untracked (new) files are untouched.

--hard: The Repo branch now points to <target_commit>. Work from commits after <target_commit>, any pre-existing Staged work, AND any pre-existing unstaged changes in the Working Dir (for tracked files) are all DISCARDED. The Staging Area and Working Dir become a Clean Slate, matching <target_commit>. Untracked (new) files are usually untouched.

Nobody can remember that, so here is mental model for it.

Thinking 🤔

What happens to files that are untracked, how to remove them

Clean

git reset is good to move HEAD to some previous state, but what about we want to clean our untracked files also. to do that we use

git clean -f -d -x
git clean -f
git clean -f -d
git clean -X

-n or --dry-run: Shows what would be deleted.

-f or --force: Actually deletes the files. Use with caution!

-d: Also remove untracked directories (by default, it only removes untracked files).

-x: Also remove files ignored by Git (normally, git clean only removes untracked files that are not ignored).

-X: Only remove files ignored by Git.

-i or --interactive: Shows files to be deleted and allows you to choose which ones to remove interactively.

In summary, git clean helps you remove files from your working directory that Git isn't tracking, allowing you to maintain a clean and predictable project state. Always use the dry-run option (-n) before using the force option (-f) to avoid accidentally deleting important files.

Restore

git restore is a command primarily used to **undo changes in your unstage files from the staging area. In short, it helps you:

  1. Discard local changes in your working files, reverting them to how they were in the staging area or in the last commit.
  2. Unstage files, moving them from the staging area back to just being modified (but not staged) in your working directory.
git restore <file_name>

Revert

Revert is like anti-commit of <provided_commit>, basically it will not change any history but will add an anti-change which will remove the changes of the <provided_commit>.


git revert <SHA>

cherry-pick 🍒

We can bring only one commit from one branch to another branch ny cherry picking that commit.


git cherry-pick <commit SHA>

info

cherry-pick is one of the most useful command of git, because there will certainly be cases where a change has such a bad divergence and the merge conflict is so bad, that only thing is to hand move (cherry-pick) the commits across branches. (😩 damn merges !!)