This project is a fork of git, where customizations used at Mergesium are maintained. You may or may not find them useful. They are improvements I cannot live without.
The usual git documentation mostly applies, and is found in the usual places. The description below highlights only the Mergesium improvements.
Maintains git-replace
refs to an upstream repo at merge
and rebase
time.
When adding a dependency on another project into your own, in order to preserve
the ability to pull future updates, you would typically git merge --allow-unrelated-histories
.
However, this brings the entire unrelated project's history into yours, balooning
your own commit history.
Instead, this feature implements the new mode git merge --linked
, which creates
a placeholder empty commit as a stand-in for the unrelated history, and merges
that into your branch. It also creates replace
refs linking the stand-in
commit to the unrelated commit you merged.
The result is that your own repository does not grow by copying the unrelated history.
At clone time, only the objects in your history are fetched.
Typically these are the only objects a cloner cares about. If you want to
examine the history of the unrelated project, git show --link
, git blame --link
,
and git log --link
will automatically fetch the linked history from the remote repo and create
the replace
refs, showing the expanded history, including commits from the
unrelated history. The fetch
is filtered to download only the needed objects.
This project (Mergesium Git) uses this feature to link the upstream git.
Maintained in the linked-history
branch.
When examining a merge commit with show <commit>
, this feature adds
a terse graph of the commits involved in the merge. This graph is only
expanded to the common ancestor or merge base, omitting uninteresting
commits, and labelling the merge pivots.
The merge graph can answer questions like "What was the purpose of this merge?", or "How is this feature evolving?" (see merge-graph docs)
Several graph modes are provided, which ommit or expand various sections,
which will be useful from different perspectives. A project maintainer
will be most interested in the --merge-graph=summary
and
--merge-graph=diagnosis
, while an individual developer or
team leader will be interested in the --merge-graph=effect
and
--merge-graph=purpose
formats.
Maintained in the merge-graph
branch.
Stashing incomplete merges (with unresolved conflicts) is possible, and, if given a refererence, the stash can be pushed to a remote repo just as any regular commit.
Popping an incomplete merge puts the index and worktree in the same state as when they were stashed.
Other than the obvious benefit that big, hairy merges can be stashed and continued later, the other benefit is that a conflicting state can be shared with team members, and their assistance requested. Often the expert who understands the conflict best is not the person attempting the merge. The ability to request the expert's help can be priceless in such cases.
This feature requires index-v5
Maintained in the stash-v5
branch.
In graphs displayed in the terminal, commits id's are colored more sensibly:
- merge commits are blue
- ammended commits bold (commit-time != author-time)
- rebased/cherry-picked commits yellow (committer != author)
Pretty-print formats:
- new placeholder %A shows attribution (author / committer if different)
This feature requires merge-graph
Maintained in the commit-styling
branch.
A new index format is designed which is able to store conflicting merges as tree objects. This is useful for stashing incomplete merges.
This format stores up to 64 slots (compared with 3 slots for head, ours, theirs in other index formats). Slot 63 is the conflicted state, whereas previous index versions did not store a conflicted state in the index, but on the filesystem. Slots 3-62 are used for "theirs" in octopus merges with up to 59 inputs.
The index objects are encoded into the tree object using the field usually used to encode object type (regular file, executable, symlink, tree or submodule). The object type now also encodes an index slot number for index object, allowing a v5 index to be restored exactly from a tree object, whether it contains conflicts or not.
Maintained in the index-v5
branch.
Wherever abbreviated commit SHA's are displayed, eg, in graphs, a more
descriptive identifier is shown (eg. v2.34.0-15-g9c4d58ff2c
). This is
not different than the usual ID calculated by the upstream git describe
(see git-describe).
What makes the ID "topical" is the origin of the tag used in the ID.
The upstream git simply selects the nearest tag and calls it a day.
To make it topical, a tag is selected only from the first parent of the HEAD commit. Where this makes a difference is in branches fetched from remotes which happen to contain tags. At Mergesium we consider all those remote tags irrelevant for describing a commit, and instead look for a tag that we created (ie, first parent of HEAD).
Eg. Suppose a collaborator branches your project from our tag "rel-v4" and
creates a commit and tags it "colab-tag". When you fetch and consider
merging his branch, the "colab-tag" tag is completely disregarded. His commit
is described as rel-v4-1-g<sha>
and not colab-tag
The point is that the descriptions you want to see as a maintainer should
inform you of how far a remote commit is from your own tree, and what release
the remote commit is based on. In the example above, the description
rel-v4-1-g<sha>
says the remote branch was based on my rel-v4
release, and it
directly (at depth 1
) applies patches to it.
Using remote tags to calculate remote commit-ids is the naive approach, but
makes those commit-ids ironically not descriptive. In the example above I used
a deliberately generic remote tag colab-tag
, but the problem is even worse
when remote tags resemble your own (imagine the collaborator used rel-v5
or v2
as a tag that makes sense to him).
While not technically a feature, the merge command has been refactored to allow additional merge strategies to be implemented.
Previously, the ort and recursive merge strategies shared much of the logic, eg, the merge-base finding algorithm. Much merge strategy logic was implemented in builtin/merge.c rather than merge-recursive.c or merge-ort.c - this assumed that all strategies would be closely coupled derivatives of these two identical-twin strategies.
The refactored merge.c sources allow new merge strategies that don't share logic with either ort or recursive, like some experimental strategies we're working with at Mergesium.
Additionally, the "Linked History" and "Merge graph" features introduced above can be implemented generically without being tied to any particular strategy.
Maintained in the refactor-merge
branch.