Grafts exist inside the refs/replace/
hierarchy. (Or, it might be better to say, "owe their existence to" such references.) To transfer them from one repository to another, then, you must push or fetch such references.
For instance:
git push origin refs/replace/5c714d7798d1dc9c18d194fa6448680515c0ccdb
when commit 5c714d7798d1dc9c18d194fa6448680515c0ccdb
has a replacement (in my case the replacement was new commit object ceba978ce6dad3b52d12134f4ef2720c5f3a9002
, i.e., Git normally doesn't "see" 5c714d7
, looking to replacement object ceba978
instead).
To push all replacements:
git push origin 'refs/replace/*:refs/replace/*'
(the quotes are sometimes needed to keep the shell from mangling the asterisks; exactly when, and which kind of quotes to use, is somewhat shell-dependent, though both single and double quotes work on all Unix-y shells).
Notes on fetching replacements
If some remote R has replacements, and you want to bring all of theirs in to your repository, use git fetch R 'refs/replace/*:refs/replace/*'
(or the same with a prefix +
if you want their replacements to override any you have already). You can automate this for any given repository and remote. For instance, if you run git config --edit
, you will find that your existing origin
remote has several settings that look like this:
[remote "origin"]
url = ...
fetch = +refs/heads/*:refs/remotes/origin/*
Simply add the line:
fetch = refs/replace/*:refs/replace/*
or:
fetch = +refs/replace/*:refs/replace/*
to make your Git bring over their Git's refs/replace/*
. (Note: no quotes are needed here as the shell is not going to process this line.) The leading plus sign has the same meaning as usual:1 without it, if you already have some reference, you keep yours and ignore theirs. With the leading plus sign, you discard yours and use theirs instead. As with tags, if your reference and their reference already match, it does not matter whether you keep yours or replace yours with theirs; this only matters when you have different ideas about what object some reference should name.
1In fact, the "usual meaning" for leading plus sign depends on whether the reference is supposed to move, such a branch names, or not supposed to move, such as a tag name. The plus mark sets the force flag, i.e., "always take the proposed new setting", but for branch names—which are expected to "move forward"—an update is allowed without force if and only if it is a "forward" (or "fast forward") move. Git originally applied this rule to other references like tags as well, but the Git folks fixed it in Git 1.8.2. It's not clear to me which rules Git applies to refs/replace/
references, which are not supposed to move, but are not treated extra-specially the way tags are.
git pull origin 'refs/replace/*:refs/replace/*'
to retrieve the grafts. I have a strange situation where someone else has pushed some grafts as well and a pull from a clean repository is for some reason considered a merge. Is there another kind of graft/replacement which is pulled automatically that might cause this behaviour? – Slipstream