Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

git push is very slow for a branch

Tags:

We have a git repo that is quite large (ios app resources). I appreciate that git is going to be slow when working with it, but if I create a new branch and edit a couple of files (not binary ones) and push, it takes forever.

It feels like the entire repo is being pushed. I was under the impression that git would only send the diff, is that wrong? (I know git stores compressed versions of the whole file, I mean the diff between my branch and where I branched from).

If I run git diff --stat --cached origin/foo then I see a short list of files that looks like what I would expect, e.g. 34 files changed, 1117 insertions(+), 72 deletions(-). But when I push it gets to Writing objects: 21% (2317/10804) and grinds to a halt, as if it's pushing all 2.4GB of binary data.

Am I missing something (I've googled it pretty hard)? Is this the expected behaviour? I'm using git 2.2.2 on OS X (Mavericks), and ssh ([email protected]).

I found a similar question here: Git - pushing a remote branch for a large project is really slow but no real answers.

like image 717
grahamrhay Avatar asked Mar 18 '15 09:03

grahamrhay


People also ask

Why is git push taking so long?

If you are starting a new project from a clone, (from the CLI without a fork) when you push to a blank remote you are pushing the entire history of the project you just cloned. This is going to take some time. If you just need the clone as it stands and you don't want the history, delete the .

How long does a github push take?

Expected behavior: Pushing with git push from the terminal takes less than 5 seconds. Actual behavior: Pushing in Atom takes several minutes.

What is the problem with git force -- push?

The Risks of Git Push ForceBecause you have failed to pull those changes, they are not reflected in your local repository. In this case, if you perform a Git push force, you will replace the remote repository with a copy of your local repo, effectively deleting your team member's work.

Does git push affect all branches?

No, git push only pushes commits from current local branch to remote branch that you specified in command.


1 Answers

You're using a "smart" transport (this is a good thing), so you do get deltas, or more specifically, "delta compression". But that's not to say that git pushes diffs.

Both push and fetch work the same way here: on a smart transport, your git calls up the remote and both ends have a mini conversation to figure out who has which repository objects, identified by SHA-1 and attached to specific labels (typically branch and tag names although other labels are allowed as well).

For instance, in this case, your git calls up theirs and says: "I propose to have you set your branch master to SHA-1 1234567.... I see that your master is currently 333333..., here's what I think you need to get from there to 7777777...." Theirs should reply with "ok, I need some of those but I already have ...". Once your git has figured out what needs to be sent, and what is already present, your git builds a "thin pack"1 containing all the to-be-sent objects. (This is the "delta compressing using up to %d threads" phase.)

The resulting thin pack is then sent over the smart transport; this is where you see the "writing objects" messages. (The entire thin pack must be sent successfully, after which the receiver "fattens it up" again using git index-pack --fix-thin and drops it into the repository.)

Exactly what data is sent, depends on the objects in the thin pack. That should be just the set of commits between "what they have" and "what you're sending", plus any objects (trees and blobs) needed for those commits, plus any annotated tags you're sending and any objects needed for those, that they don't already have.

You can find the commits in question by using git fetch to pick up their latest information, then using git rev-list to see what commits you'd send them. For instance, if you're just going to push things on master:

$ git fetch origin   # assuming the remote name is origin [wait for it to finish] $ git rev-list origin/master..master 

Examining these commits may show a very large binary file that is contained in one of the middle ones, then removed again in a later commit:

$ git log --name-status origin/master..master 

If one commit has A giantfile.bin and then a subsequent (probably listed first in git log output) commit has D giantfile.bin, you're probably getting hung up sending the blob for giantfile.bin.

If that's the case, you can use git rebase -i to eliminate the commit that adds the giant binary file, so that git push won't have to send that commit.

(If your history is linear—has no merges to push—then you can also, or instead, use git format-patch to create a series of email messages that contain patches. These are suitable for emailing to someone at the other site—not that there's someone at github waiting to receive them, but you can easily examine the patch files to see if any of them are enormous.)


1The pack is "thin" in that it violates a normal pack-file rule that requires any delta-compression "downstream" object to be in the pack itself. Instead, the "downstream" objects can (in fact, must) be in the repository receiving the thin pack.

like image 62
torek Avatar answered Oct 15 '22 14:10

torek