Somebody changed that config file last month and nobody remembers who. Or a bug showed up in the latest release and you need the commit that started it.
git log is where both searches begin. It lists the commits reachable from a revision, newest first, and it never alters the repository.
Each entry shows a commit hash, an author, a date, and a commit message. That is enough to audit changes, trace a regression, or compare a branch against main.
The manual on git-scm.com describes the output as a set operation. You get the commits reachable from the revisions you name, minus any reachable from a revision prefixed with ^.
Range notation, path limits, and filters all work by narrowing that one set.
What Is git log?

With no arguments, git log starts at HEAD, follows the parent links of each commit through a Git repository, and prints what it finds through a pager until it reaches the first commit. Nothing in the repository changes.
The syntax is git log [<options>] [<revision-range>] [[--] <path>…].
None of it is required. Options change what gets shown. The revision range decides where the walk starts and stops. A path (or several) limits the output to commits that touch it.
The git-log manual last changed in Git 2.56.0, dated 2026-09-28 (git-scm.com). Run git --version to see which release you have.
How git log differs from similar commands

git show prints a single commit together with its patch. git reflog records where HEAD and branch tips used to point, which is a different thing from commit ancestry. And git shortlog groups log output by author, so it suits release announcements better than daily digging.
By default, git log prints no diff at all, according to the git-log manual. Add -p or --stat when you want to see what each commit changed.
How Do You Read the Default git log Output?

The default medium format prints the newest commit first, and every entry holds a commit hash, an author, a date, and a message.
Anatomy of one entry
- The commit line holds the full hash, plus ref names such as (HEAD -> main, origin/main) when output goes to a terminal.
- The author line gives the name and email of whoever wrote the change.
- The date is the author date, shown in the original time zone.
- Last comes the message, subject line first and then the body, indented by 4 spaces.
The full hash is a 40-byte hexadecimal object name (git-log manual, Git 2.56.0). You rarely type all of it, since any unique leading part works as a commit hash in later commands.
The names in parentheses are labels pointing at that commit. HEAD -> main tells you which branch is checked out.
Merge commits get one extra line, Merge:, placed before the Author line. It lists the abbreviated hashes of the parents.
Navigating the pager
Long output goes through a pager, usually less, so the log stops after the first screen.
- Space moves to the next page and b goes back one
- j and k move a single line down or up
- q quits
Use git --no-pager log to print everything in one go. That suits scripts and piping.
How to Format git log Output

Most days --oneline is enough. It prints one abbreviated hash and subject per commit. When you need other fields, --pretty or --format take over.
Compact views
--oneline is shorthand for --pretty=oneline --abbrev-commit.
--graph draws branch and merge lines down the left side. It implies --topo-order, so commit order can differ from a plain log.
--decorate prints ref names next to commits. It is already on when output goes to a terminal, so you will rarely type it.
Abbreviated hashes default to 7 hexadecimal digits and grow as the repository gets larger (git-scm.com, pretty-formats manual).
Built-in pretty formats
| Format | Fields shown | Best for |
|---|---|---|
| oneline | Hash and subject | Scanning long history |
| short | Hash, author, subject | Quick author check |
| medium (default) | Hash, author, date, full message | Everyday review |
| fuller | Author and committer, both dates | Rebased or cherry-picked work |
Custom format strings
The --format option takes placeholders. %h is the abbreviated hash, %an the author name, %ar the relative date, %s the subject, and %d the ref names.
A working example is git log --format="%h %an %ar %s".
Dates follow --date, which accepts relative, short, iso, human, and format: with a strftime string. The log.date config variable sets the default.
One quirk. format: separates entries, so the last line has no trailing newline. tformat: terminates every entry, and any string containing a % placeholder is treated as tformat: automatically.
How to Filter Commits by Author, Date, Message and Count

The options that do most of the work are --author, --since with --until, --grep, --no-merges, and -n. They stack, so combining them narrows the result further.
By author and date
--author takes a regular expression matched against the author header, so it catches names and emails. Pass it several times and a commit matching any of the patterns is shown.
--committer does the same on the committer header. After a rebase or cherry-pick, that header differs from the author.
--since and --until accept dates such as “2 weeks ago”, and “today” means the last midnight.
--since stops walking at the first commit older than the date. --since-as-filter visits every commit in the range instead, so a commit with an out-of-order timestamp further back still gets checked.
By message
--grep matches a regular expression against the commit message.
- Several
--grepflags match any pattern, unless--all-matchrequires every one. --invert-grepkeeps commits that do not match.- Add
-ito ignore case. -Eand-Fswitch to extended regex or fixed strings.
By type and count
Merge commits have more than one parent, and Git creates them when you run git merge. --no-merges hides them, and --merges shows only them.
-3 shows the 3 newest commits that pass every other filter.
--skip=10 drops the first 10.
Filters that hide merges also hide the story of how a branch landed. Keep merges visible when you audit what reached the main branch.
How Do Revision Ranges and Paths Change What git log Shows?

A revision range sets which commits git log walks, and a path restricts the output to commits that modify it. With no range given, git log defaults to HEAD (git-scm.com, git-log manual).
Two-dot and three-dot ranges
| Notation | Selects | Example |
|---|---|---|
| A..B | Reachable from B, not from A | git log main..feature |
| A…B | Reachable from either side, not both | git log main...feature |
| B –not A | Same as A..B, written out | git log feature --not main |
You can omit one end and it defaults to HEAD. origin.. answers what you committed since your branch forked from origin.
Writing git log A..B C..D does not produce two ranges. It names a single set of commits reachable from B or D but from neither A nor C, per gitrevisions.
Ends can be any ref. Tags work as range endpoints, so git log v2.5.. lists everything since that release.
--allstarts from every ref plus HEAD, and--branches,--tagsand--remotesnarrow that to one ref type.--first-parentfollows only the first parent at each merge, which gives an overview of a topic branch.
Limiting by file or directory
Put a path after -- to keep only commits that touch it, as in git log -- src/. The separator is required when a path could be mistaken for a branch name.
Combine a path with a date filter for a fast review. git log --since="2 weeks ago" -- gitk is the manual’s own example.
Paths work with ranges too. git log main..feature -- README.md shows only the commits on feature that changed that file.
How to See What Changed in Each Commit and Search Code History

Add -p to print each commit’s patch, or --stat for a per-file summary. To find the commit that introduced a change, reach for -S, -G, or -L.
Showing diffs and file lists
Patch output comes from the same machinery as git diff, so its display options carry over to the log.
-pgives the full patch for every commit.--statlists changed files with insertion and deletion counts.--name-onlyprints file names and nothing else.--name-statusadds a status letter to each name (A added, M modified, D deleted, R renamed).
Status letters also drive --diff-filter. git log --diff-filter=A --name-status lists only the files each commit added.
With a path, -p shows the diff for that path only. Add --full-diff to see the whole commit diff for commits that touch it.
Finding when code appeared or changed
-S "string" matches commits that change how many times the string occurs in a file.
-G "regex" matches commits whose patch has an added or removed line matching the expression.
The git-diff manual gives the sharpest example. A call to frotz is rewritten in place, so -G finds the commit while -S misses it, because the number of occurrences stayed the same.
-L traces a line range or a function through history, as in git log -L :main:main.c. It implies -p.
git log --follow -p -- path/to/file keeps listing a file’s history across renames.
Which git log Command Answers Which Question?

Start from the question you have, not the flag you remember. Who, when, what, and where each lead to a different set of options.
| Question | Command | Returns |
|---|---|---|
| What did I commit today? | git log --author="Ana" --since=today --oneline | Your commits since midnight |
| What is on this branch but not on main? | git log main..HEAD --oneline | Commits unique to the branch |
| When was this string added or removed? | git log -S"timeout" --oneline | Commits that changed its count |
| How did this function evolve? | git log -L :parse_args:cli.py | Patches touching that function |
| Which commit added this file? | git log --diff-filter=A -- path/to/file | The commit that created it |
If you know the exact string, use -S. A pattern or an edited line fits -G better. And when the target is a function or a line range, go with -L.
Run the query with --oneline first. Once the candidate list is short, drop it and add -p to read the actual change.
When Does git log Not Show What You Need?
It misses commits that are unreachable from your starting point, and it hides some behind history simplification. File and line tracing also come with hard limits.
Commits that are not reachable
git log only lists commits reachable from the revisions you give it. A deleted branch, or a branch tip moved back with git reset, drops commits out of every normal range.
git reflog show is an alias for git log -g --abbrev-commit --pretty=oneline, so the same options work on it (git-reflog manual).
The recovery window is short. Reflog entries expire after 90 days by default, and after 30 days when the commit is unreachable from the branch tip (git-reflog manual).
History simplification hides commits
With a path, git log simplifies history. The default mode prunes side branches when a merge result is identical, so a commit you know touched the file can be missing.
--full-history follows every parent of a merge, and --simplify-merges then drops needless merges from that full view. --show-pulls adds the merge commits that first brought a change onto the branch.
The catch is that --simplify-merges walks the entire history before it returns a single result. On a very large repository that gets slow.
Merge commits and diffs
Merge commits print no diff unless you pass -m, -c, --cc, or another --diff-merges variant.
They also stay out of -S and -G results without one, so a change that exists only in a conflict resolution can hide from a search. The exception is --first-parent, which turns on first-parent diffs by default.
File and line limits
--followworks on one file, not on a directory.-Laccepts no path limiters, starts from a single revision, and does not support--statformats.
Rename detection also skips its exhaustive comparison above 1000 files by default (diff.renameLimit).
For the author of each current line, git blame answers directly. git log -L shows the full chain of changes behind those lines.
How to Set Defaults and Aliases for git log
Date style, short hashes, shortcuts, and saved formats cover most needs. They map to log.date, log.abbrevCommit, alias.<name>, and pretty.<name>.
Each one lives in a config file that git config reads and writes.
- Choose the scope.
--globalwrites to~/.gitconfig, and without a scope flag the value goes to the repository’s.git/config. - Set a date style with
git config set --global log.date short. - Turn on short hashes everywhere with
git config set --global log.abbrevCommit true. - Add a shortcut with
git config set --global alias.lg "log --oneline --graph --decorate". - Save a format with
git config set --global pretty.brief "format:%h %an %ar %s", then rungit log --pretty=brief. - Check the result with
git config list --show-origin, which prints each value next to the file it came from.
Git reads system, global, then local files, and the last value found wins. A repository setting beats your global one.
Per the 2.56.0 manual, the older git config <name> <value> form is deprecated in favor of get, set, and list. If git config set is rejected, your Git predates the subcommands and the old form still applies.
Two more defaults are worth knowing. log.decorate falls back to auto when unset, and --no-abbrev-commit on the command line overrides log.abbrevCommit.
Anything saved in .git/config stays on your machine. Teammates do not receive it through commits.
git log FAQ
How do I see commits on a remote branch?
Run git log origin/main, swapping in your remote and branch names. The output reflects your last fetch, so run git fetch first.
To list only what you have not merged yet, use git log main..origin/main.
How do I count commits per author?
Use git shortlog -sn. The -s flag prints only counts and -n sorts by them, which plain git log cannot do.
For release announcements, git shortlog v2.0..HEAD groups commit subjects under each author instead.
How can I check whether commits are signed?
Add --show-signature. Git passes each signature to gpg --verify and prints the result under the commit.
For a compact view, --format="%h %G? %s" prints one status letter per commit, such as G for good, B for bad, and N for unsigned. Set log.showSignature to make it the default.
How do I save git log output to a file?
Redirect it with git log --oneline > history.txt. Git only colors output going to a terminal under the default auto setting, so the file stays free of escape codes.
A changelog draft works the same way. Try git log --format="%s" v1.0..HEAD > notes.txt.
What to Do After git log Finds the Commit
Once git log surfaces the commit, inspect it first, then undo it with a new commit instead of rewriting history.
The order matters because each step lowers the risk of the next. Read the full patch with git show, trace the same lines with git log -L, and only then undo the change with git revert.
A later commit that touches those lines turns a clean revert into a conflict, so the trace comes before the undo.
Reverting a commit in Git adds an inverse commit, which leaves the history other developers already pulled intact. The price is a longer log, since the original commit and its inverse both stay visible.
This sequence fits a commit on a shared branch (position verified 1 October 2026). A commit that exists only on your local branch can be dropped with a reset instead.
- Notepad++ Android Options: Apps That Come Close - October 21, 2026
- MongoDB Cheat Sheet - October 20, 2026
- Adding AI Video Generation to a Software Product: Architecture, Cost Guardrails and QA - October 20, 2026




