Reference log recovery (git reflog)
Reference Log Recovery (git reflog)
Git's reference log (reflog) records the change history of all references (such as branches and HEAD) in the local repository. It acts like a "black box" for Git operations, allowing you to recover lost commits even if branches are accidentally deleted or incorrect resets are performed.
How reflog Works
Every time a HEAD or branch reference changes, Git records the following in the reference log:
- The SHA-1 value before the change
- The SHA-1 value after the change
- The type of operation (commit, checkout, reset, etc.)
- The operation timestamp
- The operator information
These records are stored in the .git/logs/
directory:
- HEAD changes are recorded in
.git/logs/HEAD
- Branch changes are recorded in
.git/logs/refs/heads/<branch-name>
Basic Usage
View the complete reference log:
git reflog
# Example output:
# 7a3b2c1 HEAD@{0}: commit: Update README
# 91d4f5a HEAD@{1}: checkout: moving from main to feature/login
View the reference log for a specific branch:
git reflog show feature/login
View with a time format:
git reflog --date=iso
Recovering from Mistakes
Scenario 1: Recovering a Deleted Branch
# 1. View records before deletion
git reflog
# Output includes:
# 91d4f5a HEAD@{3}: checkout: moving from deleted-branch to main
# 2. Recreate the branch based on the old reference
git branch recovered-branch 91d4f5a
Scenario 2: Undoing an Incorrect Reset
# Accidentally performed a hard reset
git reset --hard HEAD~3
# View the state before the reset
git reflog
# Example output:
# a1b2c3d HEAD@{1}: reset: moving to HEAD~3
# e4f5g6h HEAD@{2}: commit: Add user authentication
# Restore to the commit before the reset
git reset --hard e4f5g6h
Advanced Applications
Finding the Repository State at a Specific Time
# Find the HEAD state at 3 PM yesterday
git reflog --date=local | grep "May 10 15:"
Combining with git log
# View detailed information for a commit in the reference log
git show HEAD@{2}
Cleaning Up Expired Records
By default, reflog records are retained for 90 days. You can manually clean them up:
# Clean records older than 30 days
git reflog expire --expire=30.days.ago
Practical Example
Assume we encounter the following situation while developing a frontend project:
- Create a new feature branch:
git checkout -b feature/modal
- Make several commits:
// modal.js
export function showModal() {
console.log('Modal opened');
}
git add modal.js
git commit -m "Add modal base function"
- Accidentally merge into the main branch:
git checkout main
git merge feature/modal
- Undo the merge:
git reflog
# Example output:
# 123abcd HEAD@{0}: merge feature/modal: Fast-forward
# 456efgh HEAD@{1}: checkout: moving from feature/modal to main
git reset --hard 456efgh
Differences Between Reference Log and Regular Log
Feature | git reflog | git log |
---|---|---|
Scope | All reference changes in local repo | Commit history |
Storage | .git/logs/ directory | Object database |
Retention | Default 90 days | Permanent |
Order | Reverse chronological by operation time | Reverse chronological by commit time |
Includes | All reference changes | Only commit operations |
Reference Log Entry Breakdown
A typical reflog entry:
a1b2c3d HEAD@{5}: commit: Update package.json
a1b2c3d
: New SHA-1 value after the operationHEAD@{5}
: Reference and relative positioncommit
: Operation typeUpdate package.json
: Operation description
Reference Expression Syntax
Git supports various reference expressions:
HEAD@{n}
: The nth previous state of HEADbranch@{n}
: The nth previous state of a branchHEAD@{2.days.ago}
: The state of HEAD two days agomain@{yesterday}
: The state of the main branch yesterday
Example:
# View code differences from this time yesterday
git diff HEAD@{1.day.ago}
Limitations of Reference Logs
- Local only: Reflog is not pushed to remote repositories
- Time-bound: Automatically cleaned up after 90 days by default
- Does not record workspace changes: Uncommitted modifications cannot be recovered via reflog
- Does not record stash operations: git stash operations have their own stash log
Integration with Other Commands
Using reflog to Check Merge Conflicts
git reflog show -p HEAD
Finding Lost Commits
# Search for commits containing specific information
git reflog | grep "fix login bug"
Restoring Historical Versions of Specific Files
# View file change history
git reflog -- path/to/file.js
# Restore a file to a specific version
git checkout HEAD@{5} -- path/to/file.js
Underlying Implementation of Reference Logs
Git automatically logs updates when references are changed via the git-update-ref
command. The underlying data structure is a plain text file with the format:
<old-sha> <new-sha> <committer> <timestamp> <timezone> <operation> <message>
Example log entry:
0000000000000000000000000000000000000000 a1b2c3d4e5f6g7h8i9j0k1l2m3n4o5p6 John Doe <john@example.com> 1625097600 +0800 commit (initial): Initial commit
Best Practices for Reference Logs
- Regular checks: Review reflog after important operations to confirm records
- Prompt recovery: Use reflog to recover from mistakes as soon as possible
- Backup important states: For critical points, creating tags is more reliable than relying on reflog
- Team collaboration note: Do not depend on others' reflogs, as they are local records
Alternatives to Reference Logs
When reflog is unavailable, consider:
git fsck --lost-found
: Find dangling objects- Remote repository backup: Reclone from the remote repository
- File recovery tools: For uncommitted changes
Configuration Options for Reference Logs
You can adjust reflog behavior via Git configuration:
# Modify the default expiration time (days)
git config gc.reflogExpire 180
# Set to never delete reference logs
git config gc.reflogExpire never
Graphical View of Reference Logs
Many Git GUI tools support visualizing reflog:
# View with gitk
gitk --reflog
# View with tig
tig reflog
Scripting with Reference Logs
You can automate reflog processing with scripts:
// Example: Node.js script to parse git reflog output
const { execSync } = require('child_process');
function parseReflog() {
const output = execSync('git reflog --date=iso').toString();
return output.split('\n')
.filter(line => line.trim())
.map(line => {
const [hash, ref, action, ...message] = line.split(/\s+/);
return {
hash,
ref,
action: action.replace(':', ''),
message: message.join(' ')
};
});
}
console.log(parseReflog());
本站部分内容来自互联网,一切版权均归源网站或源作者所有。
如果侵犯了你的权益请来信告知我们删除。邮箱:cc@cccx.cn
下一篇:高级合并策略