Skip to content
kain88-de edited this page May 4, 2024 · 115 revisions

Stock Git

In this documentation, "stock Git" refers to Git unaugmented by git-branchless or other tools, in the following sense (Merriam-Webster):

1a: commonly used or brought forward : STANDARD
the stock answer

This documentation sometimes contrasts "stock Git" with git-branchless to compare similar operations or specify capabilities which are not part of stock Git.

Working copy

The "working copy" refers to the set of checked out files on disk for the repository. It includes the files of the currently-checked-out commit, as well as any uncommitted changes.

In stock Git, this concept is called the "working copy" or "working tree".

Most stock Git operations operate on the working copy. For performance and ergonomic reasons, git-branchless offers implementations of operations that don't require changes to the working copy. For example, git move is used to carry out a rebase operation entirely in-memory.

Working copy snapshots

To improve the Git user experience, some git-branchless commands will take snapshots of the working copy. These are special ephemeral commits which also include unstaged changes and merge conflicts in the working copy. Unlike regular commits, you typically won't notice these snapshots in the smartlog or elsewhere. However, they can be used by git undo to undo changes to the working copy which were never committed, which typically results in a more intuitive user experience.

Working copy snapshotting never includes changes to untracked files, as they may be prohibitively large or contain secrets. Snapshots aren't committed to branches, so you won't accidentally push them to other repositories. Consequently, they will also automatically be garbage collected by Git after a certain period of time.

Working copy snapshotting will have a small performance impact, and might not work for repositories using certain Git features. You can disable working copy snapshotting if desired.

Main branch

The "main branch" is the single branch into which all commits are eventually merged/rebased. This is typically named something like master, main, mainline, trunk, etc. The alternative is to have multiple long-lived branches, which might be periodically merged together.

The branchless workflow assumes that all of your work is based off of a single main branch. It's not able to render multiple long-lived branches well.

To configure the name of main branch, see Configuration. When you run git-branchless init, git-branchless will try to guess the name of the main branch in your repository.

Anonymous branching

Normally, only commits which are reachable by a branch are visible in stock Git. git-branchless relaxes this restriction and makes all "active" commits visible in the smartlog, even if there is no branch pointing to them. This is convenient when you want to do experimental or speculative work and try out many approaches on top of a given commit without having to manage the overhead of branches. See Divergent development.

The specific rules for commit visibility can be found here, but usually you don't need to worry about them.

This feature was originally called "branchlessness", hence the name git-branchless. However, git-branchless is fully compatible with branches, so to reduce confusion, it's better to refer to this feature as "anonymous branching".

Commit graph

The "commit graph" is the directed acyclic graph structure containing all of the commits in the repository. Branches points to commit in the commit graph. Typical development happens by adding a new commit to the commit graph and then moving a branch to point to the new commit.

In stock Git, the term "commit history" is sometimes used to the commit graph or parts of it. We avoid using this terminology in git-branchless because it introduces multiple orthogonal timelines, and it may be ambiguous which timeline's "history" we're referring to. See Bitemporality.

Stock Git also has a feature enabled with core.commitGraph, which is used to optimize commit walks. This feature is unrelated to "commit graphs" as used in in documentation.

Commit stacks

Under a normal Git workflow, a series of commits is usually referred to as a "branch". In git-branchless, there may not be a branch associated with a series of commits. Instead, such a series is called a "commit stack".

In some stock Git workflows, this is called a "patch stack" or "patch series".

Actually, during development with git-branchless, a single commit may diverge into multiple speculative lines of development. This is a broader structure than a single series of commits. In proper computer science terms, a "commit stack" is a subtree of the Git commit graph. But for practical reasons, we don't use terminology like "tree", "branch", or "fork" to describe this structure, because these terms already have different established meanings in Git.

You can consider a commit stack to be like a set of plates resting on top of one another. In the below diagram, you can't pick up plate #2 without also picking up plates #4 and #5 which rest on top of it.

██#4████ ██#5████
██#2█████████████ ██#3██████
██#1████████████████████████   (bottom)

Stock Git does not have strong support for dealing with non-linear commit stacks. For example, in stock Git, you can typically only rebase a linear stack like #2 + #4 onto a new destination, which would "abandon" #5. In git-branchless, commands like git move allow you to move a sub-stack like #2 + #4 + #5 as a group.

Speculative merges

Usually, stock Git can't determine the result of merge or rebase operations without carrying them out on disk to some extent. This leads to an unfortunate user experience where the user may be afraid to merge/rebase on top of the main branch for fear of having to resolve merge conflicts.

git-branchless alleviates this by never starting merge conflict resolution unless specifically requested (typically with the -m/--merge flag). Unlike stock Git, git-branchless can "speculatively" apply the operations in-memory first, without touching the working copy, and quickly abort if it turns out that they would require merge conflict resolution. This makes it much less risky to try merge/rebase operations.

The git sync command rebases all commit stacks that wouldn't cause merge conflicts (unless -m/--merge is passed). This is possible because of speculative merging.

(Development is already underway for stock Git to get in-memory merges!)

Bitemporality

Bitemporality is the idea that data exists along two different timelines.

Stock Git has per-branch timelines, which indicates the order of commits which make up that branch. The git log command is used to show that timeline.

git-branchless adds support for per-commit timelines, which indicates how a commit was changed over time. This typically happens during local development, such as by running git commit --amend, which updates the current commit instead of making a new commit. This feature implements Mercurial's Changeset Evolution, and it powers novel features like git undo.

Stock Git has a limited version of per-commit timelines in the form of reflogs. However, these are inconvenient to use and insufficiently powerful for some use-cases. For technical details, see Comparison with the reflog.

Clone this wiki locally