How to dig around our internal data to find (nearly) anything
GitButler saves data in a few different ways. As we're still in beta, sometimes things might break and it may look like you've lost work, but you almost certainly haven't. We're pretty good about saving stuff a lot. Here's how to recover almost anything you had in your working directory or virtual branches.
If everything crashes or the UI isn't working at all, you may be surprised to know that even though your virtual branches don't show up in a normal git branch output, we do actually constantly write them out as Git references (just not in refs/heads).
These references are just like git branches - they point to a commit that has the latest version of your branch. You can create other git branches off of them, you can push them to GitHub, etc.
You will have one for each virtual branch (applied or unapplied) that you've created (that you haven't deleted).
If you've committed everything on a virtual branch, the reference will just point to the latest commit. If you have work in progress on the branch, it will point to a WIP commit that includes those changes.
So for example, if I have the following two virtual branches, one fully committed and one with work pending:
I can view the git branches like this:
Terminal
❯ git show gitbutler/Convert-tables-to-utf8mb4commit 841e4db701ca41206c03f1f4fe345f7e27d05eabAuthor: Scott Chacon <schacon@gmail.com>Date: Fri Feb 23 10:30:17 2024 +0100 my latest commit❯ git show gitbutler/Add-database-schema-conversion-scriptcommit d95e7f4da1611ea6bb8a80da06e66ca923fbff55Author: GitButler <gitbutler@gitbutler.com>Date: Fri Feb 23 10:30:18 2024 +0100 GitButler WIP Commit This is a WIP commit for the virtual branch 'Add database schema conversion script' This commit is used to store the state of the virtual branch while you are working on it. It is not meant to be used for anything else.
See how the Add-database-schema-conversion-script reference points to a "WIP commit"? The tree of that commit has all those changed files in it as though we had committed them.
If you don't want to search through all your refs with for-each-refs, you can also just run a normal git log command and we'll show you what references we've written and which modified files are in each one:
Terminal
❯ git logcommit 2d8afe0ea811b5f24b9a6f84f6d024bb323a2db5 (HEAD -> gitbutler/integration)Author: GitButler <gitbutler@gitbutler.com>Date: Fri Feb 23 10:30:18 2024 +0100 GitButler Integration Commit This is an integration commit for the virtual branches that GitButler is tracking. Due to GitButler managing multiple virtual branches, you cannot switch back and forth between git branches and virtual branches easily. If you switch to another branch, GitButler will need to be reinitialized. If you commit on this branch, GitButler will throw it away. Here are the branches that are currently applied: - Add database schema conversion script (refs/gitbutler/Add-database-schema-conversion-script) - butler/Gemfile - butler/README.md - butler/db/schema.rb - butler/db/migrate/20240209144600_change_mysql_charset.rb - .pscale.yml - Convert tables to utf8mb4 (refs/gitbutler/Convert-tables-to-utf8mb4) branch head: 841e4db701ca41206c03f1f4fe345f7e27d05eab - butler/create_column_conversions.rb Your previous branch was: refs/heads/sc-branch-comments The sha for that commit was: 5e16e99667db9d26f78110df807853a896120ff3 For more information about what we're doing here, check out our docs: https://docs.gitbutler.com/features/virtual-branches/integration-branch
You can see the two gitbutler refs under the "Here are the branches that are currently applied" section.
Again, these are real git refs, just not under refs/heads so that we don't pollute your git branch output. But if GitButler crashes at some point, you can still push them to GitHub or whatever you want. Here is an example pushing my virtual branch to a GitHub branch called convert-tables:
Terminal
❯ git push origin refs/gitbutler/Convert-tables-to-utf8mb4:refs/heads/convert-tablesEnumerating objects: 6, done.Counting objects: 100% (6/6), done.Delta compression using up to 10 threadsCompressing objects: 100% (4/4), done.Writing objects: 100% (4/4), 474 bytes | 474.00 KiB/s, done.Total 4 (delta 2), reused 1 (delta 0), pack-reused 0remote: Resolving deltas: 100% (2/2), completed with 2 local objects.remote:remote: Create a pull request for 'convert-tables' on GitHub by visiting:remote: https://github.com/gitbutlerapp/web/pull/new/convert-tablesremote:To github.com:gitbutlerapp/web.git * [new branch] refs/gitbutler/Convert-tables-to-utf8mb4 -> convert-tables
Ok, let's say that your work was not in one of those refs for some reason. Maybe you hit some weird bug and it completely changed everything in a way where now you're sitting on the couch in the dark with a glass of whisky, slowly mumbling the word "GitButler..." and plotting your revenge.
Most of the time, we'll have whatever you're looking for in our operations log.
The easiest way to access this is to use the built in Project History UI: Project History
However, let's dig into how this works, just in case you want to check it out yourself.
Every time that GitButler does some possibly data-changing operation, we store a snapshot of your project state in our operations log before the operation happens so you can undo it if you want to. This is stored as a Git commit history that is parallel to your projects (ie, no common parents).
You can inspect this by looking at the .git/gitbutler/operations-log.toml file.
You can see that before creating a branch or updating our workspace with upstream work, we're recording the state of our project so we have an undo point. So what data are we keeping here in addition to this trailer information?
Let's look at the tree of one of these commits:
Terminal
❯ git cat-file -p 16e47cb1d091ca9dd44327fef2f5305b09403a95^{tree}040000 tree 4b825dc642cb6eb9a060e54bf8d69288fbee4904 conflicts040000 tree b283f22f5abf4ed9c612c1b5b3b9a98ec25474b0 index040000 tree b283f22f5abf4ed9c612c1b5b3b9a98ec25474b0 target_tree100644 blob d839dca7e14f5833ad737b4adbf337bd20489927 virtual_branches.toml040000 tree a0821552c0e7d5defe369d577af5e3a87b442469 virtual_branches040000 tree b283f22f5abf4ed9c612c1b5b3b9a98ec25474b0 workdir
So, it's not a snapshot of your working directory alone, but it includes a bunch of other meta information.
The state of your working directory is indeed stored in the workdir tree:
Beyond that, we also store the state of your index in index as a tree, the state of what your target (trunk) tree looked like in target_tree, conflicts if you were in a conflicted state in conflicts and the state of your virtual branches.