Q: When git pushes refs that have no common history over the Smart Protocol, can it consider root or sub-trees already in-common between local and origin
when building the thin-pack to send?
tl;dr
Consider this (uncommon) situation when working-with and pushing to a remote Git repository.
- I have a local repository where the local
master
points to a tree with 1110 descendant sub-trees a[0-9]/b[0-9]/c[0-9]
.
- Remote
origin/master
is current with the local master
commit i.e. identical histories. It uses ssh
protocol.
- For whatever reason, I create a local branch
squashed
. I set that branch to a new, single root-commit, but with the same content/tree as master
. This can be done with git commit-tree
. So this branch has a single commit with no commits in-common with master
, but the root tree-hash is identical, it points to the same tree object in master
and origin/master
. It is not important that this is a single/squashed commit in order to discuss this - any history rewritten back to the root commit, with no common history will do.
git push origin HEAD # push squashed
From observations of the performance of this with a large repository, and the number of objects sent, I suspect that push
, send-pack
and receive-pack
and associated thin-pack negotiation over the Smart Protocol does something like:
- Confirms that the commit being pushed
squashed
has no common-history with any commit origin
currently has.
- Is oblivious to the fact that
squashed
points to a tree that is not only in origin
, but is the tree for a current HEAD
ref.
- Packs and sends everything.
In this case the trees are identical. If a subsequent change is made in squashed
... either an additional commit, or a new squash that changes a file in a0
, 2 trees (/
and a0
) would have changed, and the other 1109 would be unchanged. The root tree has changed, which means a next-level search would be required to see whether it is worth searching for further common sub-trees. This might require a heuristic, as without comparing all sub-trees down-to the leaves, it is not possible to infer the number of descendant trees in-common from the trees at any particular depth.
Of course if there are multiple commits in the nothing-in-common history being pushed, this negotiation would need to be repeated for each commit.
Does it sound reasonable that the Smart API could consider already-held common sub-trees, or at the very least, the root-tree, as it considers each commit? Or should Git already be doing this and there is something wrong with my client or server?
git version 2.8.2
See Question&Answers more detail:
os 与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…