I have a network on computers all of which have access to the same git repository. This network will not have access to the internet and I'm trying to find a way to be able to update the git repositories on all computers. I can upload files to the computers and run shell commands on them, but I cannot simply run git pull origin master
. So I've set up one of the computers as a "central" computer, and other computers to do a git pull central master
to update themselves with the central computer. However, I'm trying to figure out what's the best way to update the central computer. I'm trying git patches, so I run a command to get the current commit ID on the central computer, and do a git diff <commitIDCentralComp> <commitIDGitHub> > patch_file.patch
then upload that patch file and run a git apply patch_file.patch
, and then run git pull central master
on the other computers, but the problem with that is that even though it updates the code, the commit ID on the central computer does not change. So if I update the code on GitHub, and now have a different commit ID, I'll just be making a patch file with the original commit ID on the central computer, not the new one. Is there a way to ensure the commit ID changes as well and is in sync with the latest on GitHub?
git bundle
is the command you want to use for this task. It is precisely designed for the "offline" transfer of Git objects (to quote the manual), just like you want to do.
git bundle
creates a file that contains pretty much the same stuff a git fetch
would download, that you can then copy over through whatever means you need to use.
User manual: https://git-scm.com/docs/git-bundle
git bundle
use caseFor a few years I had a situation where I had two distinct "central" repositories on two networks that didn't talk to each other. I would create a bundle on one, carry it over to the other (through some maddeningly inefficient means, though that's besides the point), and incorporate the bundle there.
In my workflow, the most common case was that one server was ahead of the other and I had to copy a few commits over.
To illustrate, assume I had 3 commits to take from Host1 to Host2:
On Host1, in a sandbox cloned from the Host1 central server:
git bundle create mybundle main~4..main
Copy mybundle
to Host2.
On Host2, in a sandbox cloned from Host'2 central server:
git fetch <path to>/mybundle main:bundle-main
Now when you look at the branches in your sandbox on Host2, you'll see bundle-main
which points to the same commit main
pointed to on Host1. It actually took me a while to wrap my brain around that git fetch
command: you're just treating the bundle as if it was a remote. And it sort-of it: it contains the stuff you would need to fetch from Host1's remote, but in a file instead of on an actual remote server.
Once you've confirmed that bundle-main
is the same commit as main
on Host1, merge bundle-main
into main
and push it to your Host2 central server:
git checkout main # make sure it's up to date with origin/main
git merge bundle-main
git push origin main
And now, Host1's main
and Host2's main
should be identical.
Now, with this workflow, I often found that someone had made changes on Host1 and someone else different changes on Host2, requiring a merge.
The workflow for this case is basically the same, with a small twist: when you do git merge bundle-main
, instead of a fast-forward merge like I assumed above, you'll create an actual merge commit. You can then take the merge commit created on Host2 back over to Host1 with exactly the same process, in the reversed direction.
To be sure the bundle has everything needed on the other side, when you do git bundle create mybundle <commit1>..<commit2>
, you need to make sure <commit1>
is a commit that actually exists on the destination server, and <commit2>
is the new HEAD commit you want to send there. Out of paranoia, I typically went one or two commits further back than necessary because the file transfer between my two networks was painful and I didn't want to have to redo it, but you probably don't have to do that.
Thankfully, I now have a Git server I can see from both networks, so I haven't actually used this workflow in a while. I hope I didn't get any details wrong, but if anything doesn't work let me know and I'll adjust my answer. I've tested my commands here just now, though, so they should work for you. Hopefully I didn't miss any important corner cases or details.