Darek Kay's picture Darek Kay

Git explained: Commit ranges

Git's log and diff commands are useful for inspecting your repository changes. Both commands accept ranges of commits in different formats, which can be confusing. In this post, I will shed some light on the differences between a b, a..b and a...b commit ranges. Check out the repository that I will be using as an example.

This is part 2 of my Git explained series.

git log

The git log command lists all commits that are reachable from a certain commit.

git log feature

Git graph. Branch main points to F→E→D→C→B→A. Branch feature points to H→G→C→B→A. Highlighted commits: H,G,C,B,A.

You can also specify multiple commits separated by a space, which will list all commits that are reachable from any of them:

git log main feature

Git graph. Branch main points to F→E→D→C→B→A. Branch feature points to H→G→C→B→A. All commits are highlighted.

You might want to exclude certain commits from git log. The following commands are equivalent and will list all commits that are reachable from feature but not from main:

git log main..feature
git log ^main feature
git log feature --not main

Git graph. Branch main points to F→E→D→C→B→A. Branch feature points to H→G→C→B→A. Highlighted commits: H,G.

Another special notation is the triple dot, which excludes the common ancestor of two commits. The following example lists all commits that are reachable from either feature or main, but not both of them:

git log main...feature

Git graph. Branch main points to F→E→D→C→B→A. Branch feature points to H→G→C→B→A. Highlighted commits: F,E,D,H,G.

git diff

The git diff command displays the differences (changes) between commits.

Separating two commits by either a space or a double dot will show the full difference between those commits:

git diff main feature
git diff main..feature
-D
-E
-F
+G
+H

Git graph. Branch main points to F→E→D→C→B→A. Branch feature points to H→G→C→B→A. Red commits: F,E,D. Green commits: H,G.

Another way to think about this: what changes have to be applied to move from main to feature? In the previous example, we need to first "revert" commits F, E, D and then apply commits G, H.

The triple dot notation is useful for displaying only the changes from a certain branch:

git diff main...feature
+G
+H

Git graph. Branch main points to F→E→D→C→B→A. Branch feature points to H→G→C→B→A. Green commits: H,G.

This example displays only the differences in feature compared to main.

Examples

Here are some common use cases for log and diff commands.

Pull request preview

GitHub's pull request view uses git log and git diff under the hood. For example, the "Commits" tab displays all commits from feature that will be merged into main:

GitHub screenshot with two commits G and H.

If you want to preview the commits before creating your pull request, here's the command:

git log main..feature --reverse
* 11dcc47 - G
* b8434e1 - H

The "Files changed" tab displays the actual changes to be applied:

GitHub screenshot with two changed files.

Here's how to reproduce this locally:

git diff main...feature
+ G
+ H

Amend

If you are used to rewriting history, amend is one of your best friends. In the following example, commit 5c7a82 is missing some changes. To keep the Git history clean, we've amended those changes (2b049ea):

* 2b049ea - (HEAD -> feature) Fix defect 47
| * 5c7a782 - (origin/feature) Fix defect 47
|/
* fb2546f - Add checkout page

We might want to verify what we've amended before pushing our changes:

git diff origin/feature feature
- Hello
+ Hello world

The change looks good, so we'd like to push it. The original commit 5c7a782 is public, but it's on our own branch, so we decide to "force push" with git push --force-with-lease.

But what if someone else works on the same branch? After fetching feature, they will see the inverted graph:

* 2b049ea - (origin/feature) Fix defect 47
| * 5c7a782 - (HEAD -> feature) Fix defect 47
|/
* fb2546f - Add checkout page

Now they will be interested in the changes on origin/feature compared to their local commit (i.e., the one before our amend). In other words, what change needs to be applied to get from feature to origin/feature:

git diff feature origin/feature
- Hello
+ Hello world

Notice how the diff is the same as before, but the command looks different this time because of the commit order.

Cheat sheets

If you're using this post as a reference, here's all the information in one place:

Git log cheatsheet


Git diff cheatsheet


Related posts

Want to leave a comment?

Join the discussion at Twitter or Mastodon. Feel free to drop me an email. 💌

Git explained: Commit ranges