GitButler ⧓

GuidesCLI Tutorial

Inspecting and Diffing

Looking at commits, branches and work in progress with GitButler

When you're working with projects, sometimes you'll need to inspect things to see what the differences are or summarize work.

The first thing to remember is that GitButler is basically an advanced Git client, which means that you can use any Git inspection command without problems when you're using GitButler.

This includes things like git show, git diff, git log, git blame, git bisect, etc. So we have not tried to recreate the functionality of these, but instead focused on some of the common needs in a modern workflow that these tools may not do well.

Let's look at a simple scenario.

$ but status --files
╭┄zz [unstaged changes] 
┊   g0 M Gemfileh0 M README.md 
┊
┊╭┄us [user-bookmarks]  
┊●   fde72a6 add user changes  
┊│     fd:0 M app/models/user.rb
┊●   85efe19 create bookmarks  
┊│     85:0 A app/controllers/bookmarks_controller.rb
┊│     85:1 A app/views/bookmarks/index.html.erb
├╯
┊
┴ 32a2175 (common base) [origin/main] 2025-11-03 Merge pull request #65 from schacon/feature-bookma(checked 15 seconds ago)

Hint: run `but diff` to see uncommitted changes and `but stage <file>` to stage them to a branch

Here we have an unstaged file (Gemfile), a file staged to the user-bookmarks branch (README.md), and two commits on our branch.

Diffing things

For most of this, you could use git diff. For example, to see everything that is uncommitted, you can just run git diff.

$ git diff HEAD
diff --git c/Gemfile w/Gemfile
index 5cd27fa8..5c76922c 100644
--- c/Gemfile
+++ w/Gemfile
@@ -21,7 +21,7 @@ gem "jbuilder"
 # gem "bcrypt", "~> 3.1.7"
 
 # Windows does not include zoneinfo files, so bundle the tzinfo-data gem
-gem "tzinfo-data", platforms: %i[ windows jruby ]
+gem "tzinfo-data", platforms: %i[ mingw mswin x64_mingw jruby ]
 
 # Use the database-backed adapters for Rails.cache, Active Job, and Action Cable
 gem "solid_cache"
@@ -42,7 +42,7 @@ gem "thruster", require: false
 
 group :development, :test do
   # See https://guides.rubyonrails.org/debugging_rails_applications.html#debugging-with-the-debug-gem
-  gem "debug", platforms: %i[ mri windows ], require: "debug/prelude"
+  gem "debug", platforms: %i[ mri mingw mswin x64_mingw ], require: "debug/prelude"
 
   # Static analysis for security vulnerabilities [https://brakemanscanner.org/]
   gem "brakeman", require: false
diff --git c/README.md w/README.md
index 32fb79f3..57d59121 100644
--- c/README.md
+++ w/README.md
@@ -76,6 +76,6 @@ bundle exec rubocop
 
 This project is open source and available under the [MIT License](LICENSE).
 
-## New Stuff
+## Even More New Stuff
 
-New stuff is always coming
+New stuff is always coming, and more is on the way!

However, I don't find that a super readable format, even if it's useful in applying with the Unix patch command. Since most people tend not to be emailing patches around, we tried to optimize for a much more human readable format:

$ but diff
──────────i0 Gemfile──────────21 21│ # gem "bcrypt", "~> 3.1.7"
   22 2223 23│ # Windows does not include zoneinfo files, so bundle the tzinfo-data gem
   24   │-gem "tzinfo-data", platforms: %i[ windows jruby ]
      24│+gem "tzinfo-data", platforms: %i[ mingw mswin x64_mingw jruby ]
   25 2526 26│ # Use the database-backed adapters for Rails.cache, Active Job, and Action Cable
   27 27│ gem "solid_cache"
──────────j0 Gemfile──────────42 4243 43│ group :development, :test do
   44 44│   # See https://guides.rubyonrails.org/debugging_rails_applications.html#debugging-with-the-debug-gem
   45   │-  gem "debug", platforms: %i[ mri windows ], require: "debug/prelude"
      45│+  gem "debug", platforms: %i[ mri mingw mswin x64_mingw ], require: "debug/prelude"
   46 4647 47│   # Static analysis for security vulnerabilities [https://brakemanscanner.org/]
   48 48│   gem "brakeman", require: false
────────────k0 README.md────────────76 7677 77│ This project is open source and available under the [MIT License](LICENSE).
   78 7879   │-## New Stuff
      79│+## Even More New Stuff
   80 8081   │-New stuff is always coming
      81│+New stuff is always coming, and more is on the way!

You can see that this is the same information, but a bit more easily understandable.

You can also focus the diff output to any of the short codes in that status output. For example, to just see what is staged to user-bookmarks you can run but diff l0. To only see the changes committed to the bookmarks controller file in the "create bookmarks" commit you can run but diff n0, to only see what modifications have not been staged you can run but diff zz, and so on.

Listing Branches

When GitButler creates and modifies branches, it is manipulating real Git branches, so you can see them and inspect them with normal Git commands as well. While you can use the git branch command to see all your branches, the but branch command is a bit nicer.

Here is what git branch might output (this example repo has over 100 branches, so let's just truncate it):

$ git branch | head -10
  update-homepage2
  gitbutler/edit
  update-homepage
  sc-switch-wording-to-x
  sc-lefty-branch
* gitbutler/workspace
  user-bookmarks
  move-second-commit
  squash-example
  sc-tests-controllers

This output is actually better than the default Git output for this, because I have a config setting of branch.sort -comitterdate, so at least it's showing me the branches by last commit rather than the default of alphabetically.

The but branch command, however, is built specifically to help you identify the branches you're looking for and give you some useful information about them. Let's give it a try:

$ but branch
Applied Branches
00   active  ✓ *user-bookmark…        1w ago     Scott Chacon      

Unapplied Branches
01   local   update-homepage2             ↑2     today      Scott Chacon      
02   local   update-homepage              ↑3     1w ago     Scott Chacon      
03   local   sc-switch-wording-to-x       ↑2     1w ago     Scott Chacon      
04   local   sc-lefty-branch              ↑1     1w ago     Scott Chacon      
05   local   move-second-commit           ↑1     1w ago     Scott Chacon      
06   local   squash-example               ↑1     1w ago     Scott Chacon      
07   local   sc-tests-controllers         ↑1     2w ago     Scott Chacon      
08   local   sc-likes                     ↑1     3w ago     Scott Chacon      
09   local   sc-bookmarks-comments2       ↑2     3w ago     Scott Chacon      
0a   local   docs-tests-likes-bookmarks   ↑1     2mo ago    Scott Chacon      
0b   local   sc-branch-30                 ↑3     2mo ago    Scott Chacon      
0c   local   sc-branch-29                 ↑1     2mo ago    Scott Chacon      
0d   local   gitbutler/worktree/2c7f3480… ↑1     2mo ago    Scott Chacon      
0e   remote  test                         ↑1     2mo ago    Scott Chacon      
0f   local   new-branch                   ↑0     3mo ago    Scott Chacon      
0g   local   new-branch2                  ↑0     3mo ago    Scott Chacon      
0h   local   new-branch3                  ↑0     3mo ago    Scott Chacon      
0i   local   test-branch-delete-me        ↑4     3mo ago    GitButler         
0j   local   feature-a-frontend           ↑3     3mo ago    Scott Chacon      
0k   local   feature-a-backend            ↑1     3mo ago    Scott Chacon      

... and 121 more branches (use --all to show all)

You can immediately notice that this is a very different type of listing. We're not just showing the names of the branches, but also some very useful information about all of the branches that are available to us.

First, we show any applied branches - these are the branches that are currently applied into your workspace. Next, all the unapplied branches - that is, the other branches that you don't currently have active in your working directory.

For each branch, you'll see how many commits "ahead" it is, that is, how many commits are on that branch that are not on the target branch (eg origin/main). In other words, if this branch were merged to production, what would come in with it?

There is also a "✓" or "✗" that indicates if this branch is cleanly mergeable with your target branch.

It also shows the last author of a commit on that branch and orders everything by how long ago the last commit was.

The point of this listing is to help you easily see what work you have available, not merged into your target, that you might want to work on.

Filtering your Branches

Running but branch defaults to running but branch list, which has a bunch of other options (filtering to only local or remote branches, not calculating mergability for speed, etc). The most useful option might be the filtering, for example, you can type a partial match string and it will filter the output:

$ but branch list book
Applied Branches
00   active  ✓ *user-bookmark…        1w ago     Scott Chacon      

Unapplied Branches
01   local   sc-bookmarks-comments2     ↑2     3w ago     Scott Chacon      
02   local   docs-tests-likes-bookmark… ↑1     2mo ago    Scott Chacon      
03   local   feature-bookmarks          ↑0     4mo ago    Scott Chacon      

Looking at a Branches

If you want to see what is on a branch, you can inspect a specific branch by running but branch show <branch>. This will show the commits on this branch ahead of your target.

Essentially, it runs the equivalent of git log origin/main..<branch> with some more introspection.

$ git log origin/main..feature-awesome-thing
commit 464aae4d905fc53df7a1a5d02f86ae8117b3a92b
Author: Scott Chacon <schacon@gmail.com>
Date:   Thu Oct 9 11:39:50 2025 +0200

    add user changes

commit ca81308347d2fbaba043227f8de79aa34fc6132a
Author: Scott Chacon <schacon@gmail.com>
Date:   Thu Oct 9 11:39:41 2025 +0200

    create bookmarks

Now let's look at but branch show

$ but branch show feature-awesome-thing
Branch: feature-awesome-thing (2 commits ahead)

464aae4 add user changes
    2025-10-09 11:39:50 by Scott Chacon
    2 files changed, 27 insertions, 0 deletions

ca81308 create bookmarks
    2025-10-09 11:39:41 by Scott Chacon
    4 files changed, 131 insertions, 2 deletions

Pretty much a short log of the branch difference from our target branch. However, there are a bunch of options if you want to dig in further.

The -r option will show you PR information if one is opened on this branch. The -f option will show you the files modified in each commit.

The real fun one is adding --ai, which will take a look at the changes and summarize what the changes actually do.

Let's run all of them at the same time:

$ but branch show sc-branch-28 --ai -r -f
Branch: sc-branch-28 (#59) (2 commits ahead)

0294f53 rest
    2025-10-23 12:05:58 by Scott Chacon
    2 files changed, 90 insertions, 2 deletions

    Gemfile (+2, -2)
    app/views/bookmarks/index.html.erb (new file, +88)

85d5e67 routes
    2025-10-23 12:05:58 by Scott Chacon
    1 file changed, 5 insertions, 0 deletions

    config/routes.rb (+5, -0)


Reviews:

  PR/MR: #59
  Title: The Best Pull Request Probably Ever Made
  URL: https://github.com/schacon/why/pull/59
  Description:
    This is one of the greatest Pull Requests that has ever been made. You will cower in fear of it's awesomeness.


AI Summary:
Add basic bookmarks UI and route configuration. This branch updates the Gemfile and introduces a new bookmarks index view to display bookmarks, and modifies routes to wire up the bookmarks resource. Overall it lays groundwork for a bookmarks feature by adding the front-end listing and necessary routing.


Showing a Commit

If you want to look at a specific commit in any of these circumstances, you can use the but show command with the commit hash.

$ but show a42580b96ed7b432
Commit:    a42580b96ed7b432ac9906f3685e99014bb12c0e
Change-ID: yltmulxpvktwwmkzrmtmztwtkwskvzzu
Author:    Scott Chacon <schacon@gmail.com>
Date:      2026-01-24 16:24:29 +0100 (1w ago)

add user changes

Files changed:
  M app/models/user.rb

Deleting Branches

As long as we're talking about branches, let's show how to get rid of them. If you've merged one, it will by default not be shown anymore with but branch anyhow, but if you have one with some work on it that you want to abandon, you can also easily delete it with but branch delete (or -d).

Last updated on

On this page

Edit on GitHubGive us feedback