git log
TL;DR: git log is Git’s primary tool for auditing project history. It traverses the Directed Acyclic Graph (DAG) of commits by starting at the current checkout point (HEAD), reading its parent hashes, and recursively walking backward in time to the initial root commit. It is a powerful search and analysis tool rather than a simple text-based list.
What Does git log Actually Do?
To understand how git log generates your history, you must look at how Git organizes commits. Git does not store your commits in a flat list or array. Instead, it structures them as a Directed Acyclic Graph (DAG).
In this graph:
- Nodes: These are your commit objects.
- Edges: These are pointers from a child commit to its parent commit(s). They are directed (they point backward in time) and acyclic (history cannot loop back on itself).
graph RL
C3[Commit 3<br>HEAD / main] -->|parent| C2[Commit 2]
C2 -->|parent| C1[Commit 1<br>Root Commit]
When you invoke git log, Git does not scan your entire disk. Instead, it performs a graph traversal starting from a given entry point—by default, the commit pointed to by HEAD (your current location, link git-checkout).
The Traversal Algorithm
- Git reads the file
.git/HEADto determine your active branch (e.g.,ref: refs/heads/main). - It resolves the active branch reference to its 40-character commit hash by reading
.git/refs/heads/main(e.g.,8a4c10...). - It loads the commit object
8a4c10...from the object database (.git/objects/) and extracts the metadata: Author, Committer, Timestamp, Message, and theparenthash. - Git outputs this commit’s details to your console.
- Git pushes the parent hash (e.g.,
55a420...) to a traversal queue. - The loop repeats: Git pops the next commit hash from the queue, reads it, displays it, and queues its parents.
- The traversal halts when a commit has no
parentfield, which signifies the very first commit of the repository (the root commit).
In the case of a merge commit, the commit object lists multiple parent lines. Git handles this by adding all parent hashes to the queue. Depending on the sorting settings (e.g., chronological, topological, or date-ordered), Git will interleave the commits from the merged branches to reconstruct a unified timeline.
What Happens Inside .git/ (Hands-on exploration)
Let’s build a repository containing multiple commits and branches, then trace exactly how Git parses its files to generate the git log output.
Step 1: Set Up a Multi-Commit Repository
Let’s initialize a repository and make two quick commits on the main branch.
$ mkdir git-log-demo && cd git-log-demo
$ git init
Initialized empty Git repository in /git-log-demo/.git/
$ echo "v1" > file.txt
$ git add file.txt
$ git commit -m "First commit"
[main (root-commit) 5be36ab] First commit
$ echo "v2" > file.txt
$ git add file.txt
$ git commit -m "Second commit"
[main ae39f81] Second commit
Step 2: Create a Branch and a Merge Commit
Now, let’s create a branch named feature (link git-branch), make a commit, switch back, and merge it.
$ git checkout -b feature
Switched to a new branch 'feature'
$ echo "feature-work" > feature.txt
$ git add feature.txt
$ git commit -m "Feature commit"
[feature c4f8101] Feature commit
$ git checkout main
Switched to branch 'main'
$ git merge feature -m "Merge feature branch"
Merge made by the 'ort' strategy.
feature.txt | 1 +
1 file changed, 1 insertion(+)
create mode 100644 feature.txt
Step 3: Resolving refs and cata-logging the commits
Let’s see where HEAD points right now:
$ cat .git/HEAD
ref: refs/heads/main
Now let’s see which commit hash main points to:
$ cat .git/refs/heads/main
6df8d0354178de3d038fa61dfb63e8a157580b33
This is our merge commit. Let’s look at this commit object using the plumbing command git cat-file:
$ git cat-file -p 6df8d0354178de3d038fa61dfb63e8a157580b33
tree e7c3909ea1dc725f187e1451f2ad490e5b0213ef
parent ae39f81ca99d45e5b619d854cf78d1f2a36b1d2e
parent c4f810129a8a72cf5a1db5b2f270a2936274b1e2
author Purna Pattela <purna@example.com> 1772960500 +0000
committer Purna Pattela <purna@example.com> 1772960500 +0000
Merge feature branch
Notice that because this is a merge commit, it has two parents:
parent ae39f81...(the last commit onmainbefore the merge).parent c4f8101...(the commit from thefeaturebranch).
If we run git log, Git will output the merge commit (6df8d03), then read its parents. It traverses down the parent ae39f81 and c4f8101 in chronological order. Let’s inspect ae39f81:
$ git cat-file -p ae39f81ca99d45e5b619d854cf78d1f2a36b1d2e
tree b4f93dc52c0dfa6c7f8a9a2a6dfba1d2a36b567d
parent 5be36abc0e9df7f2a7db2e9b0cf2a3d2427a1d1e
author Purna Pattela <purna@example.com> 1772960400 +0000
committer Purna Pattela <purna@example.com> 1772960400 +0000
Second commit
This commit points to the initial parent 5be36ab.... Let’s inspect 5be36ab:
$ git cat-file -p 5be36abc0e9df7f2a7db2e9b0cf2a3d2427a1d1e
tree f3b3a3c9e6db5832a875a6c11d2b270a2936274b
author Purna Pattela <purna@example.com> 1772960300 +0000
committer Purna Pattela <purna@example.com> 1772960300 +0000
First commit
Since 5be36ab... has no parent line, Git knows this is the root of our tree and stops the traversal. The resulting log output lists all four commits in reverse chronological order.
Detailed Command Options & Advanced Usage
The default output of git log is verbose and sequential. You can format, filter, and trace history using flags.
1. Advanced Formatting Options
--oneline
Condenses each commit to a single line containing the abbreviated commit hash and the subject line. This is ideal for scanning commit histories.
$ git log --oneline
6df8d03 Merge feature branch
c4f8101 Feature commit
ae39f81 Second commit
5be36ab First commit
--graph --decorate
Plots an ASCII-art representation of the branch execution paths alongside branch labels (HEAD, branch names, tags).
$ git log --graph --oneline --decorate --all
* 6df8d03 (HEAD -> main) Merge feature branch
|\
| * c4f8101 (feature) Feature commit
* | ae39f81 Second commit
|/
* 5be36ab First commit
Custom Formats (--pretty=format:)
You can design your own output templates using placeholders. For example, to print only the hash, author name, date, and commit message:
$ git log --pretty=format:"%h - %an (%ar): %s"
6df8d03 - Purna Pattela (2 minutes ago): Merge feature branch
c4f8101 - Purna Pattela (5 minutes ago): Feature commit
Key placeholders include:
%h: Abbreviated commit hash.%an: Author name.%ar: Author date (relative, e.g. “3 days ago”).%ad: Author date (absolute format).%s: Subject line (commit message first line).%d: Ref decorations (e.g.(HEAD -> main)).
2. Forensic History Filtering
Searching by code changes (The Pickaxe -S)
If you want to find out which commit introduced or removed a specific text string (like a function name or API endpoint) from your codebase, use the -S flag:
$ git log -S "payment_processor_v2" --oneline
This is called the Pickaxe. It searches the contents of the files at each commit state, rather than just searching commit message text.
Searching by commit message (--grep)
To search only the commit messages for a keyword:
$ git log --grep="bugfix"
Filtering by path
To see only commits that modified a specific file or folder, append a double-dash followed by the file path:
$ git log --oneline -- src/utils/helper.js
Real-World Scenario: Debugging a Regression
Imagine your team deploys a new version of an application, and users report that the application is crashing when they click the “Submit” button. You know the button worked fine a week ago.
To find the culprit, you can combine history filters:
# Step 1: List all commits from the last week that modified the checkout button component
$ git log --since="1 week ago" --oneline -- src/components/SubmitButton.js
a3d5f9c refactor: rewrite submit click handler
54f8b9e chore: update button styling
# Step 2: Show the actual code modifications in the suspicious commit (a3d5f9c)
$ git log -p -1 a3d5f9c
Using the patch flag -p, you review the exact changes in the handler function, spot the missing event parameter, and write a hotfix.
Common Pitfalls and Mistakes
1. Getting Trapped in the Pager
By default, if the log output is longer than your screen height, Git pipes the output to a pager utility (typically less). Beginners often don’t know how to return to their normal terminal.
- The Fix: Press
qto quit the pager. - Tip: If you want Git to print the output directly to the terminal without opening a pager, set the pager config to
cat:
$ git --no-pager log -n 5
2. Missing Commits from Other Branches
Running git log only shows commits that are reachable from your current branch’s history. If you are on main and someone else pushed changes to feature-b, you will not see their commits.
- The Fix: Use the
--allflag to show all commits on all branches:
$ git log --oneline --all --graph
3. Confusing git log with git reflog
If you rebase (link git-rebase) or reset commits, those commits are removed from the branch history and will no longer show up in git log.
- Why:
git logonly traverses active pointers. - The Fix: Use
git reflog. The reference log tracks every single change made to the HEAD pointer on your local machine (including checkout switches, amends, resets, and rebases). It is your ultimate safety net for recovering “deleted” commits.
Command Quick Reference
| Command | Action |
|---|---|
git log | Shows full commit history (hashes, author, date, message). |
git log --oneline | Shows a compact, single-line summary per commit. |
git log --graph --oneline --all | Displays a visual tree of all branches and merges. |
git log -p | Shows the patch (code diff) introduced by each commit. |
git log -n <limit> | Limits the output to the specified number of commits (e.g. -n 5). |
git log --author="Name" | Filters history by author name. |
git log --grep="pattern" | Filters commits by keywords in the message. |
git log -S "code" | Finds commits adding or removing a specific line/word of code. |
git log --no-merges | Excludes merge commits from the history log. |
FAQ (People Also Ask)
Why are my commits not showing up in git log?
If you just ran git commit but it doesn’t appear in the log, check the following:
- Staging check: Did you run
git addbefore committing? If not, the commit may have been rejected because nothing was staged. - Detached HEAD: If you are in a detached HEAD state, your commits aren’t associated with a branch. If you checkout
main, they will seem to disappear from your log. Rungit reflogto find the missing hashes.
What is the difference between Author Date and Committer Date?
- Author Date: The timestamp of when the commit was originally created (e.g., using
git commit). - Committer Date: The timestamp of when the commit was last written to the repository (e.g., when it was cherry-picked, rebased, or amended).
- By default,
git logdisplays the Author Date. To see the Committer Date, use:git log --pretty=fuller.
How do I see who changed a specific line in a file?
While git log -S can find the commit that introduced a string, git blame <file> is the fastest way to view line-by-line authorship. It displays the commit hash, author name, and timestamp for every single line of a file.
How can I search the commit history for a specific date range?
You can combine --since (or --after) and --until (or --before) flags:
$ git log --since="2026-06-01" --until="2026-07-01" --oneline
Git also parses relative human dates, such as --since="3 weeks ago" or --until="yesterday".
Test Your Knowledge
Loading quiz…