HEAD and reflog
HEAD in Git
In Git, HEAD is a pointer that refers to the current branch or commit your working directory is based on. It represents the current state of your repository and plays a crucial role in navigating and managing changes.
-
HEAD as a Pointer:
- HEAD typically points to the tip (latest commit) of the current branch.
- Example: If you are on the
main
branch,HEAD
points to the latest commit onmain
.
-
Detached HEAD:
- A detached HEAD occurs when
HEAD
points directly to a commit instead of a branch. - This can happen when you check out a specific commit:
git checkout <commit-hash>
- Changes made in a detached HEAD state are not linked to any branch and need to be explicitly committed to a branch if you want to retain them.
- A detached HEAD occurs when
-
HEAD and Branches:
- When you switch branches using
git checkout
orgit switch
, the HEAD pointer moves to the latest commit of the branch you switch to.
- When you switch branches using
-
Symbolic Reference:
- HEAD is a symbolic reference, meaning it indirectly refers to a commit through a branch name. For example:
ref: refs/heads/main
- HEAD is a symbolic reference, meaning it indirectly refers to a commit through a branch name. For example:
Commands Involving HEAD
-
Viewing HEAD:
cat .git/HEAD
This will display the branch or commit that HEAD points to.
-
Resetting HEAD:
- Reset HEAD to a previous commit:
git reset <commit-hash>
- Reset HEAD and the working directory:
git reset --hard <commit-hash>
- Reset HEAD to a previous commit:
-
Reattaching HEAD:
- To reattach a detached HEAD to a branch:
git switch <branch-name>
- To reattach a detached HEAD to a branch:
-
Checking Out a Commit with Detached HEAD:
git checkout <commit-hash>
-
HEAD^ and HEAD~:
HEAD^
refers to the parent of the current commit.HEAD~<n>
refers to the commit n steps before the current HEAD. Example:This moves HEAD to two commits before the current commit.git checkout HEAD~2
Git Reflog
The Git reflog (reference log) is a mechanism that records updates to the HEAD and branch references in your repository. It helps you track changes to HEAD, even if those changes are not part of the branch history.
-
What Reflog Tracks:
- Every time you change HEAD, such as switching branches, resetting, rebasing, or merging, the reflog records the update.
- Reflog entries are local and not shared with remote repositories.
-
Reflog Retention:
- By default, Git retains reflog entries for 90 days.
-
Safety Net:
- Reflog is a powerful tool for recovering commits or branches that were accidentally deleted or reset.
Viewing the Reflog
-
Basic Command:
git reflog
This shows a list of recent changes to HEAD, including the commit hash, action performed, and a brief description.
-
Viewing Reflog for a Specific Branch:
git reflog show <branch-name>
Example:
git reflog show main
-
Reflog Entries Format:
- Example output:
d1e8c6b (HEAD -> main) HEAD@{0}: commit: Fix bug in feature
a7c9f3a HEAD@{1}: checkout: moving from feature to main
f2d4e5b HEAD@{2}: commit: Add new feature - The syntax includes:
- The commit hash.
- The reference (e.g.,
HEAD@{n}
). - The action performed (e.g.,
commit
,checkout
, etc.). - A description of the action.
- Example output:
Recovering Changes with Reflog
-
Resetting to a Specific Reflog Entry:
- Use the
HEAD@{n}
notation to reset to a previous state:git reset --hard HEAD@{2}
- Use the
-
Checking Out a Commit from Reflog:
git checkout HEAD@{n}
-
Creating a Branch from a Reflog Commit:
- If you find a commit in the reflog that you want to preserve, you can create a branch from it:
git branch <new-branch-name> HEAD@{n}
- If you find a commit in the reflog that you want to preserve, you can create a branch from it:
Cleaning Up the Reflog
-
Expire Old Entries:
- Remove entries older than a specific time:
git reflog expire --expire=30.days.ago --all
- Remove entries older than a specific time:
-
Garbage Collection:
- Prune unreachable objects from the reflog:
git gc --prune=now
- Prune unreachable objects from the reflog:
Best Practices
-
Use Reflog for Recovery:
- If you’ve accidentally deleted a branch or commit, reflog can help you recover it.
-
Check Reflog Before Force Push:
- If you’re unsure about the state of your repository after a reset or rebase, use
git reflog
to verify the history.
- If you’re unsure about the state of your repository after a reset or rebase, use
-
Avoid Overwriting Reflog Entries:
- Be cautious with commands like
git gc
andgit reflog expire
as they permanently delete reflog entries.
- Be cautious with commands like
Recovering a Deleted Branch Using Reflog
If you’ve accidentally deleted a branch, you can recover it using the reflog. Here are the steps:
-
Find the Commit Hash:
- Use the reflog to locate the commit where the branch was last present:
git reflog
- Look for entries associated with the deleted branch. For example:
Here,
a1b2c3d HEAD@{2}: checkout: moving from deleted-branch to main
f3e4d5c HEAD@{3}: commit: Work on featurea1b2c3d
is the commit hash of the deleted branch.
- Use the reflog to locate the commit where the branch was last present:
-
Create a New Branch:
- Use the commit hash to recreate the branch:
Example:
git branch <branch-name> <commit-hash>
git branch deleted-branch a1b2c3d
- Use the commit hash to recreate the branch:
-
Switch to the Recovered Branch:
- After recreating the branch, you can switch to it:
git switch deleted-branch
- After recreating the branch, you can switch to it: