HEAD 💀
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 ?
This will be an interesting set of tasks to do, but can be quite useful in understanding reflog.
- create a new branch off of
master
, call itbaz
. - add one commit to
baz
. Do it in a new filebaz.md
- switch back to
master
and deletebaz
(git branch -D baz from earlier) - 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:
- 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.
- Staged (Index): This is where you prepare your next commit. When you git add a file, its changes are moved to the Staging Area.
- 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.
- 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.
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:
- Discard local changes in your working files, reverting them to how they were in the staging area or in the last commit.
- 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>
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 !!)