The grafts approach mentioned by Chris Johnsen for joining two repositories is no longer fully valid (with grafts alone).
With Git 2.18 (Q2 2018), the functionality of "$GIT_DIR/info/grafts
" has been superseded by the "refs/replace/
" mechanism (for some time now).
The internal code had support for it in many places, which has been cleaned up
in order to drop support of the "grafts" mechanism.
See commit a3694d9, commit f42fa47, commit 8d0d81a, commit e2d65c1, commit f9f99b3, commit 0115e03, commit fb40429, commit 041c98e, commit e24e871 (28 Apr 2018), and commit d398f2e, commit fef461e, commit c5aa6db (25 Apr 2018) by Johannes Schindelin (dscho
).
(Merged by Junio C Hamano -- gitster
-- in commit 352cf6c, 23 May 2018)
So instead of
echo "$commit-id $graft-id" >> .git/info/grafts
You now do:
git replace --graft $commit-id $graft-id
git filter-branch $graft-id..HEAD
Deprecate support for .git/info/grafts
The grafts feature was a convenient way to "stitch together" ancient
history to the fresh start of linux.git
.
Its implementation is, however, not up to Git's standards, as there are
too many ways where it can lead to surprising and unwelcome behavior.
For example, when pushing from a repository with active grafts, it is
possible to miss commits that have been "grafted out", resulting in a
broken state on the other side.
Also, the grafts feature is limited to "rewriting" commits' list of
parents, it cannot replace anything else.
The much younger feature implemented as git replace
set out to remedy
those limitations and dangerous bugs.
Seeing as git replace
is pretty mature by now (since 4228e8b
(replace: add --graft
option, 2014-07-19, Git 2.1.0) it can perform the graft
file's duties), it is time to deprecate support for the graft file, and
to retire it eventually.
Now (again, Git 2.18, Q2 2018), you have:
replace
: add --graft
option
The usage string for this option is:
git replace [-f] --graft <commit> [<parent>...]
First we create a new commit that is the same as <commit>
except that its parents are [<parents>...]
Then we create a replace ref that replace with
the commit we just created.
With this new option, it should be straightforward to
convert grafts to replace refs.
And before Git 2.20 (Q4 2018), the recently introduced commit-graph auxiliary data is incompatible with mechanisms such as replace & grafts that "breaks" immutable nature of the object reference relationship.
Disable optimizations based on its use (and updating existing commit-graph) when these incompatible features are in use in the repository.
See commit 829a321, commit 5cef295, commit 20fd6d5, commit d653824, commit b775896, commit 950c62b (20 Aug 2018) by Derrick Stolee (derrickstolee
).
See commit 212e0f7, commit 4a6067c (20 Aug 2018) by Stefan Beller (stefanbeller
).
(Merged by Junio C Hamano -- gitster
-- in commit 6d8f8eb, 16 Oct 2018)
With Git 2.24 (Q4 2019), the "upload-pack
" (the counterpart of "git fetch
"), which needs to disable commit-graph when responding to a shallow clone/fetch request, does not panic anymore.
See commit 6abada1, commit fbab552 (12 Sep 2019) by Jeff King (peff
).
(Merged by Junio C Hamano -- gitster
-- in commit 098e8c6, 07 Oct 2019)
## upload-pack
: disable commit graph more gently for shallow traversal
When the client has asked for certain shallow options like "deepen-since", we do a custom rev-list walk that pretends to be shallow.
Before doing so, we have to disable the commit-graph, since it is not compatible with the shallow view of the repository. That's handled by 829a321 (commit-graph
: close_commit_graph before shallow walk, 2018-08-20, Git v2.19.2).
That commit literally closes and frees our repo->objects->commit_graph struct
.
That creates an interesting problem for commits that have already been
parsed using the commit graph.
Their commit->object.parsed
flag is set, their commit->graph_pos
is set, but their commit->maybe_tree
may still be NULL
.
When somebody later calls repo_get_commit_tree()
, we see that we haven't loaded the tree oid yet and try to get it from the commit graph.
But since it has been freed, we segfault!
So the root of the issue is a data dependency between the commit's
lazy-load of the tree oid and the fact that the commit graph can go
away mid-process.