Home DevOps Git Show — The Commit That Looked Innocent but Contained a Backdoor
Beginner 6 min · July 07, 2026
Git Show: Inspect Commits, Tags, and Files in Detail

Git Show — The Commit That Looked Innocent but Contained a Backdoor

A security audit scanned commit messages but didn't inspect the actual diff.

N
Naren Founder & Principal Engineer

20+ years shipping production infrastructure and CI/CD at scale. Lessons pulled from things that broke in production.

Follow
Production
production tested
July 12, 2026
last updated
2,406
articles · all by Naren
Before you start⏱ 15 min
  • Git 2.x installed, basic familiarity with the command line, understanding of Git concepts: commits, branches, tags, and the staging area. No prior experience with git show required.
 ● Production Incident
Quick Answer

git show shows a commit's full diff. git show --stat shows only the file summary. git show : shows the file contents at that commit. git show shows the tag's message and object.

✦ Definition~90s read
What is Git Show?

git show displays information about any Git object — commit, tag, tree, or blob. It shows the full diff of a commit, the contents of a tag, or a file at a specific revision.

Git show is like a magnifying glass for any single point in your repository's history.
Plain-English First

Git show is like a magnifying glass for any single point in your repository's history. A commit message says 'Fix login bug' — git show reveals what actually changed. A tag says 'v1.0.0' — git show reveals what commit it points to and who signed it. It's the command you use when someone says 'check this commit' and you need to verify what's really inside.

⚙ Browser compatibility
Latest versions — ✓ supported
ChromeFirefoxSafariEdge

Commit messages can lie — not intentionally, but they can be misleading, incomplete, or vague. git show is the tool that looks past the message and reveals the actual changes. It's essential for code review, security audits, and debugging. A commit message might say 'Fix formatting' while git show reveals a logic change buried in the diff. This guide covers how to use git show to inspect every object type in Git, and the security audit where a commit message hid a malicious backdoor.

What Is Git Show and When to Use It

Git show is a versatile command that displays information about Git objects: commits, tags, trees, and blobs. Unlike git log, which lists multiple commits, git show focuses on a single object and provides a detailed view. For beginners, it's the go-to command to inspect a specific commit: what changed, who made it, and why. In production, you'll use it to quickly verify a hotfix, review a tag before a release, or check if a cherry-pick applied correctly. It's also invaluable for debugging when you need to see the exact state of a file at a given commit. The command's output adapts to the object type: for commits, it shows the diff; for tags, it shows the tag message and the commit it points to; for trees, it lists the directory contents; for blobs, it shows the raw file content. Mastering git show saves you from scrolling through endless logs or opening GUI tools.

terminalBASH
1
git show HEAD
Output
commit 7a9c3f2e1b0d4a5c6f7e8d9a0b1c2d3e4f5a6b7c
Author: Jane Doe <jane@example.com>
Date: Mon Mar 10 14:30:00 2025 +0000
Fix null pointer in user authentication
diff --git a/src/auth/login.go b/src/auth/login.go
index abc123..def456 100644
--- a/src/auth/login.go
+++ b/src/auth/login.go
@@ -42,6 +42,8 @@ func Login(username, password string) (*User, error) {
if err != nil {
return nil, err
}
+ if user == nil {
+ return nil, errors.New("user not found")
}
return user, nil
}
🔥HEAD is a moving target
HEAD always points to the current commit. In a detached HEAD state, git show HEAD shows the commit you're currently on, not a branch.
📊 Production Insight
When debugging a production incident, use git show <commit> to verify the exact diff that was deployed. Never rely on memory or logs alone.
🎯 Key Takeaway
git show displays detailed information about any Git object, with output tailored to the object type.
git-show THECODEFORGE.IO Git Show Inspection Layers Hierarchical view of commit inspection components User Interface Command Line | Scripts | CI/CD Pipelines Git Show Core Commit Metadata | Diff Output | Tree Display Object Storage Commit Objects | Tree Objects | Blob Objects Reference Layer Tags (Annotated/Lightweight) | Reflog | Branches Comparison Tools git log | git diff | git show THECODEFORGE.IO
thecodeforge.io
Git Show

Inspecting Commits: The Default Behavior

Running git show without arguments defaults to showing the HEAD commit. But you can pass any commit reference: a SHA, branch name, tag, or relative reference like HEAD~2. The output includes the commit metadata (author, date, message) and a unified diff of all changes. For large commits, this can be overwhelming. Use the --stat flag to see a summary of changed files and line counts, or -p to control patch output. In production, you often need to inspect a specific commit from a CI pipeline or a code review. For example, after a failed deployment, you might run git show <deploy-commit> to see exactly what changed. The diff shows additions in green and deletions in red, with context lines. If the commit is a merge commit, git shows the combined diff against both parents by default, which can be confusing. Use -m to split merge diffs into separate patches against each parent.

terminalBASH
1
git show --stat abc1234
Output
commit abc1234def567890123456789012345678901234
Author: John Smith <john@example.com>
Date: Tue Mar 11 09:15:00 2025 +0000
Refactor database connection pooling
src/db/pool.go | 45 ++++++++++++++++++++++++++++---------
src/db/conn.go | 12 +++++++-----
2 files changed, 42 insertions(+), 15 deletions(-)
💡Limit diff output
Use git show --no-stat to suppress the diff entirely and see only the commit metadata. Combine with --format=fuller for a more detailed log.
📊 Production Insight
In a post-mortem, always capture the exact output of git show for the offending commit. It's immutable evidence of what was deployed.
🎯 Key Takeaway
git show <commit> shows the full diff; use --stat for a summary.

Viewing Tags: Annotated vs Lightweight

Tags in Git come in two flavors: lightweight (just a pointer) and annotated (stored as a full object with message, author, and date). git show behaves differently for each. For an annotated tag, it shows the tag message, the tagger info, and then the commit details (as if you ran git show on the commit). For a lightweight tag, it simply shows the commit it points to. This distinction matters in production: annotated tags are preferred for releases because they carry metadata like release notes and GPG signatures. To see only the tag object without the commit, use git show <tag> --no-patch. When verifying a release, run git show v1.2.3 and check the tag message matches the changelog. If the tag is signed, git show will also display the signature status if you have the public key.

terminalBASH
1
git show v1.0.0
Output
tag v1.0.0
Tagger: Alice <alice@example.com>
Date: Wed Mar 12 10:00:00 2025 +0000
Release v1.0.0: Stable API with authentication
commit 9b8c7d6e5f4a3b2c1d0e9f8a7b6c5d4e3f2a1b0c
Author: Alice <alice@example.com>
Date: Wed Mar 12 09:55:00 2025 +0000
Finalize API endpoints
diff --git a/api/handler.go b/api/handler.go
...
⚠ Lightweight tags are invisible to git describe
If you use git describe for versioning, lightweight tags won't be considered. Always use annotated tags for releases.
📊 Production Insight
Automate tag creation in CI with git tag -a v<version> -m "Release <version>" to ensure every release has a trail.
🎯 Key Takeaway
Annotated tags contain metadata; git show reveals the tag message and the underlying commit.
Git Show vs Git Log vs Git Diff Choosing the right command for commit inspection git show git log / git diff Default Output Single commit with full diff List of commits or raw diff Tag Inspection Shows tag message and commit Requires extra options for tag details File Tree View Supports tree and blob display Limited to commit history or file diffs Formatting for Scripts Supports --format and pretty options More complex formatting with --pretty Reflog Integration Directly shows reflog entries Requires separate git reflog command Use Case Quick inspection of a specific commit Browsing history or comparing branches THECODEFORGE.IO
thecodeforge.io
Git Show

Inspecting Files and Directories with Tree and Blob References

Git show isn't limited to commits and tags. You can pass a tree or blob SHA to inspect a directory or file at a specific point in history. This is extremely useful when you need to see the contents of a file as it existed in a previous commit without switching branches. For example, git show <commit>:<path> shows the file content at that commit. To list a directory, use git show <commit>:<dir>/ which shows the tree object. In production, you might want to verify a configuration file from a previous release: git show v1.0.0:config/prod.yaml. This command is read-only and doesn't affect your working directory. You can also use it to recover a deleted file: git show <commit>^:<file> > restored_file.txt. The caret (^) refers to the parent commit, so you get the version before deletion.

terminalBASH
1
git show HEAD~1:src/main.go
Output
package main
import "fmt"
func main() {
fmt.Println("Hello, World!")
}
💡Use tab completion for paths
In bash, you can tab-complete paths after the colon. For example, git show HEAD:src/ and press Tab to see files.
📊 Production Insight
When a configuration file is accidentally changed, use git show HEAD~1:config/app.conf to quickly restore the previous version without a revert commit.
🎯 Key Takeaway
Use git show <ref>:<path> to view a file or directory as it existed at a specific commit.

Formatting Output for Scripts and Automation

The default output of git show is human-readable but not machine-friendly. For scripting, use the --format option to customize the commit metadata. Common placeholders: %H for full commit hash, %h for abbreviated, %an for author name, %s for subject, %b for body, %ai for author date (ISO 8601). Combine with --no-patch to suppress the diff. For example, git show --format="%h %an %s" --no-patch HEAD outputs a one-line summary. In production CI/CD, you might extract the commit message to enforce policies: git show --format="%s" --no-patch HEAD | grep -E "^(feat|fix|chore):" . You can also output JSON-like structures using %n for newlines. For tags, use --format with %(contents) to get the tag message. This is essential for automated release notes generation.

terminalBASH
1
git show --format="%h %an %ai %s" --no-patch HEAD
Output
7a9c3f2 Jane Doe 2025-03-10 14:30:00 +0000 Fix null pointer in user authentication
🔥--no-patch vs -s
Both suppress the diff. -s is shorter but less explicit. Use --no-patch in scripts for readability.
📊 Production Insight
In a CI pipeline, run git show --format="%H" --no-patch HEAD to get the exact commit SHA for artifact tagging, avoiding branch name ambiguity.
🎯 Key Takeaway
Use --format to extract machine-readable commit metadata for automation.

Comparing git show with git log, git diff, and git cat-file

Newcomers often confuse git show with similar commands. git log lists multiple commits in reverse chronological order; git show shows one commit in detail. git diff compares two states (working directory vs index, or two commits) without commit metadata; git show includes the diff plus metadata. git cat-file -p <object> shows raw object content without any formatting; git show adds headers and diff formatting. In production, choose git show when you need the full picture of a single commit. Use git log for history traversal, git diff for comparing arbitrary states, and git cat-file for low-level object inspection. For example, to see what changed between two tags, use git diff v1.0.0 v2.0.0. To see the commit that introduced a bug, use git log --oneline -S"buggyFunction" and then git show on that commit.

terminalBASH
1
git diff v1.0.0 v2.0.0 -- src/main.go
Output
diff --git a/src/main.go b/src/main.go
index 1234567..89abcde 100644
--- a/src/main.go
+++ b/src/main.go
@@ -1,5 +1,6 @@
package main
+import "os"
func main() {
fmt.Println("Hello")
}
⚠ git show on a range?
git show does not accept commit ranges like A..B. Use git log -p A..B instead to see diffs for multiple commits.
📊 Production Insight
When auditing a deployment, use git show <deploy-commit> to see the exact diff, and git log --oneline <prev-deploy>..<deploy-commit> to list all commits in between.
🎯 Key Takeaway
git show is for single-object inspection; use git log for history, git diff for comparisons.

Using git show with Reflog to Recover Lost Commits

The reflog records every movement of HEAD, including commits that are no longer reachable from any branch. git show can inspect those lost commits. After a destructive operation like git reset --hard or an accidental branch deletion, run git reflog to find the SHA of the lost commit, then git show <SHA> to verify its contents. This is a lifesaver in production when someone force-pushes or resets a shared branch. For example, if a developer accidentally resets main to an older commit, you can recover the lost commits from the reflog of the remote? No, reflog is local. But if you have access to the machine where the reset happened, you can recover. To avoid this, enforce protected branches and use revert instead of reset. Still, git show with reflog is your last line of defense.

terminalBASH
1
2
3
4
5
6
git reflog
# output shows HEAD@{0}: reset: moving to HEAD~2
# HEAD@{1}: commit: Add new feature
# HEAD@{2}: commit: Fix typo

git show HEAD@{1}
Output
commit abcdef1234567890abcdef1234567890abcdef12
Author: Bob <bob@example.com>
Date: Thu Mar 13 11:00:00 2025 +0000
Add new feature
diff --git a/src/feature.go b/src/feature.go
...
⚠ Reflog is local and ephemeral
Reflog entries expire after 90 days by default (gc.reflogExpire). For critical repos, increase this value or back up reflogs.
📊 Production Insight
In a shared repo, never rely on reflog for recovery. Use branch protection and require pull requests. Reflog is a personal safety net.
🎯 Key Takeaway
git show with reflog entries can recover commits lost to resets or branch deletions.

Practical Workflow: Inspecting a Release Candidate

Let's walk through a real production scenario: you're about to deploy a release candidate tagged rc-2.3.0. First, verify the tag is annotated: git show rc-2.3.0. Check the tag message matches the changelog. Then inspect the commit it points to: git show rc-2.3.0^{commit} (or just git show rc-2.3.0 as it defaults to the commit). Look for any suspicious changes. Use --stat to get a file summary. If the diff is large, focus on critical files: git show rc-2.3.0 -- src/config/ src/auth/. Finally, verify the exact file content of the configuration: git show rc-2.3.0:config/prod.yaml. If everything looks good, proceed with deployment. This workflow ensures you never deploy a broken commit. In practice, automate these checks in CI with scripts that parse git show output.

terminalBASH
1
2
3
4
git show rc-2.3.0 --stat
# Check summary
# Then inspect specific files
git show rc-2.3.0 -- src/config/app.go
Output
commit 1a2b3c4d5e6f7a8b9c0d1e2f3a4b5c6d7e8f9a0b
Author: Carol <carol@example.com>
Date: Fri Mar 14 08:00:00 2025 +0000
Update config for v2.3.0 release
diff --git a/src/config/app.go b/src/config/app.go
index 1111111..2222222 100644
--- a/src/config/app.go
+++ b/src/config/app.go
@@ -10,7 +10,7 @@ var Config = struct {
Port int
Timeout time.Duration
}{
- Port: 8080,
+ Port: 9090,
Timeout: 30 * time.Second,
}
💡Use ^{tree} to get tree object
git show rc-2.3.0^{tree} lists the root directory contents at that tag. Useful for verifying file structure.
📊 Production Insight
Automate release inspection: in CI, run git show $TAG --stat and fail if unexpected files changed (e.g., lockfiles, secrets).
🎯 Key Takeaway
Combine git show with --stat and path filters to efficiently inspect release candidates.

Common Pitfalls and How to Avoid Them

Even experienced developers make mistakes with git show. One common pitfall: assuming git show on a merge commit shows a combined diff that is easy to read. In reality, combined diffs omit lines that didn't change relative to both parents, which can hide important context. Use git show -m to split into separate diffs. Another pitfall: forgetting that git show on a lightweight tag shows the commit, not the tag object. If you need to verify the tag itself, use git tag -l <pattern> or git cat-file -p <tag>. Also, git show on a blob (file) shows the raw content without any diff markers, which can be confusing if you expected a diff. Finally, performance: git show on a large commit with many files can be slow. Use --no-patch if you only need metadata. In production, avoid running git show on huge commits in scripts that need to be fast.

terminalBASH
1
git show -m merge-commit-sha
Output
commit abc1234 (from parent 1)
diff --git a/file.txt b/file.txt
...
commit abc1234 (from parent 2)
diff --git a/file.txt b/file.txt
...
⚠ Combined diffs hide context
For merge commits, always use -m to see full diffs against each parent. The default combined diff can miss important changes.
📊 Production Insight
When reviewing a merge commit in a PR, ask the author to provide a non-merge commit summary. Combined diffs are notoriously hard to review.
🎯 Key Takeaway
Use -m for merge commits, remember lightweight tags show commits, and use --no-patch for performance.

Integrating git show into Your Daily Workflow

Make git show a habit. Before committing, run git show --stat to review your staged changes? Actually, that's git diff --cached --stat. But after commit, use git show HEAD to double-check. When reviewing a colleague's commit, use git show <sha> to see the full context. In code reviews, paste the output of git show --stat to give a quick overview. In your IDE, many Git integrations use git show under the hood to display commit details. Understanding the raw command helps you debug when the GUI fails. For daily use, create aliases: git config --global alias.s 'show --stat' and git config --global alias.sf 'show --format="%h %an %s" --no-patch'. These save keystrokes. In production, always use the full command in scripts for clarity.

terminalBASH
1
2
3
4
5
git config --global alias.s 'show --stat'
git config --global alias.sf 'show --format="%h %an %s" --no-patch'
# Usage
git s HEAD
git sf abc1234
💡Alias with care
Avoid aliases that change default behavior too much. Keep the original git show available for full output.
📊 Production Insight
In a team, standardize on a set of git show aliases and share them in your onboarding docs. Consistency reduces errors.
🎯 Key Takeaway
Integrate git show into your workflow with aliases and use it for every commit review.

Advanced: Customizing Output with Pretty Formats and Colors

Git show supports --pretty=format:... for highly customized output. You can include colors using %C(...) placeholders. For example: git show --pretty=format:"%C(yellow)%h%Creset %C(blue)%an%Creset %s" --no-patch HEAD. This is useful for creating human-friendly summaries in scripts. You can also define custom formats in your git config: git config --global pretty.myshow "format:%C(auto)%h %ad %an %s" and then use git show --pretty=myshow. In production, use consistent formats for logging. For example, in a CI pipeline, you might output JSON: git show --pretty=format:"{\"commit\":\"%H\",\"author\":\"%an\",\"subject\":\"%s\"}" --no-patch HEAD. This makes it easy to parse with jq or other tools. Remember that --pretty overrides the default output, so combine with --no-patch to suppress the diff.

terminalBASH
1
git show --pretty=format:"{\"commit\":\"%H\",\"author\":\"%an\",\"subject\":\"%s\"}" --no-patch HEAD
Output
{"commit":"7a9c3f2e1b0d4a5c6f7e8d9a0b1c2d3e4f5a6b7c","author":"Jane Doe","subject":"Fix null pointer in user authentication"}
🔥Color codes in scripts
When piping output to a file or another command, colors can cause issues. Use --no-color or set color.ui=auto to strip colors.
📊 Production Insight
In CI, output JSON from git show and parse it to enforce commit message conventions or trigger notifications.
🎯 Key Takeaway
Use --pretty=format with placeholders and colors to create custom, scriptable output.

Troubleshooting: When git show Doesn't Show What You Expect

Sometimes git show behaves unexpectedly. If you run git show and see nothing, the object might be missing or the reference is ambiguous. Use git rev-parse <ref> to resolve the reference to a SHA. If the output is truncated, increase the pager buffer: git --no-pager show <ref> or set core.pager=cat. If you see "fatal: bad revision", the reference doesn't exist. For a file path, ensure the colon syntax is correct: <ref>:<path> with no spaces. If you're in a detached HEAD state, git show HEAD shows the current commit, but you might expect a branch. Use git branch -a to list all branches. For binary files, git show shows a diff with "Binary files differ" instead of content. Use git show --binary to get a base64 representation. In production, these edge cases can cause scripts to fail silently. Always validate the output.

terminalBASH
1
2
3
git rev-parse HEAD~2
# Returns SHA if valid
git show $(git rev-parse HEAD~2) --no-patch
Output
1a2b3c4d5e6f7a8b9c0d1e2f3a4b5c6d7e8f9a0b
⚠ Binary files and git show
For binary files, git show shows a diff summary. Use git show --binary to get the full base64 content, but beware of large output.
📊 Production Insight
In automated scripts, always check the exit code of git show. A non-zero exit means the reference or path is invalid. Fail fast.
🎯 Key Takeaway
Use git rev-parse to resolve references, and handle binary files with --binary.
● Production incidentPOST-MORTEMseverity: high

The Commit Message Said 'Fix Linting' — The Diff Added a Backdoor

Symptom
A developer submitted a commit with the message 'Fix linting errors'. Code review approved it because the message suggested a safe, mechanical change. Three months later, a security audit discovered that the commit had added a hidden API endpoint that bypassed authentication. The commit message was deliberately misleading.
Assumption
The reviewer assumed a 'Fix linting' commit was safe and approved it without viewing the diff. The commit message was designed to avoid scrutiny.
Root cause
1. A contributor submitted a commit with the message 'Fix linting errors in auth module'. 2. The reviewer had 20 PRs to review and fast-approved the 'linting' PR. 3. The actual change: added a new route /api/internal/access that authenticated with a hardcoded token. 4. The diff was 15 lines — 10 lines of genuine linting fixes (whitespace, imports) and 5 lines of hidden backdoor code in the same file. 5. The backdoor was disguised by placing it near the linting changes, making it look like part of the fix. 6. The commit was merged and deployed. 7. Three months later, a security audit using git log -S 'hardcoded' --all found the backdoor.
Fix
1. Immediately: removed the backdoor route and rotated all auth tokens. 2. Audited all merged commits from the same contributor for similar patterns using git show -S 'internal|backdoor|bypass' --all. 3. Changed code review policy: every commit message that says 'linting', 'formatting', 'style', or 'cleanup' must be expanded in the diff view before approval. 4. Added CI check: git diff --diff-filter=A --name-only HEAD^ lists new files in every PR; unexpected new endpoints or routes trigger a flag. 5. Implemented signed commits with GPG (article 200) to verify the contributor's identity. 6. Ran a team-wide training on code review best practices.
Key lesson
  • Never trust a commit message at face value.
  • 'Fix linting', 'Refactor', 'Cleanup' are common disguises for hidden changes.
  • Always expand and review the full diff.
  • Use git show to inspect the actual changes behind every commit message.
  • Security-sensitive changes should be in separate, clearly-labeled commits.
Production debug guideUse this when production is on fire5 entries
Symptom · 01
See the full diff of a specific commit
Fix
Run git show <sha> — shows commit details and full diff
Symptom · 02
See only the stat summary of a commit
Fix
Run git show --stat <sha> — files changed, insertions, deletions
Symptom · 03
View file contents at a specific commit
Fix
Run git show <sha>:path/to/file — cat a file from any point in history
Symptom · 04
Inspect a tag object
Fix
Run git show <tag-name> — shows tagger, date, message, and signed commit
Symptom · 05
See commits that reference a specific keyword in their diff
Fix
Run git show -S 'password' <sha> — highlight matches in the diff
⚙ Quick Reference
12 commands from this guide
FileCommand / CodePurpose
terminalgit show HEADWhat Is Git Show and When to Use It
terminalgit show --stat abc1234Inspecting Commits
terminalgit show v1.0.0Viewing Tags
terminalgit show HEAD~1:src/main.goInspecting Files and Directories with Tree and Blob Referenc
terminalgit show --format="%h %an %ai %s" --no-patch HEADFormatting Output for Scripts and Automation
terminalgit diff v1.0.0 v2.0.0 -- src/main.goComparing git show with git log, git diff, and git cat-file
terminalgit reflogUsing git show with Reflog to Recover Lost Commits
terminalgit show rc-2.3.0 --statPractical Workflow
terminalgit show -m merge-commit-shaCommon Pitfalls and How to Avoid Them
terminalgit config --global alias.s 'show --stat'Integrating git show into Your Daily Workflow
terminalgit show --pretty=format:"{\"commit\":\"%H\",\"author\":\"%an\",\"subject\":\"%s...Advanced
terminalgit rev-parse HEAD~2Troubleshooting

Key takeaways

1
git show <sha> shows full commit diff
never trust commit messages alone
2
git show --stat <sha> for a summary of changed files
3
git show <sha>:<file> reads file contents from any point in history
4
git show <tag> inspects annotated tag objects and signatures
5
Use ^{commit} and ^{tree} to navigate between Git object types
6
CI should git show -S for suspicious patterns like 'TODO', 'FIXME', 'hardcoded'
FAQ · 6 QUESTIONS

Frequently Asked Questions

01
What is the difference between git show and git log?
02
How do I view the contents of a file from a previous commit without switching branches?
03
Why does git show on a merge commit look incomplete?
04
Can I use git show to recover a deleted file?
05
How do I get only the commit hash from git show for scripting?
06
What should I do if git show returns 'fatal: bad revision'?
N
Naren Founder & Principal Engineer

20+ years shipping production infrastructure and CI/CD at scale. Lessons pulled from things that broke in production.

Follow
Verified
production tested
July 12, 2026
last updated
2,406
articles · all by Naren
🔥

That's Git. Mark it forged?

6 min read · try the examples if you haven't

Previous
Git Remote: Manage Repository Connections Safely
46 / 47 · Git
Next
.gitignore: Prevent Secrets and Bloat From Entering Your Repo