Home > OS >  git apply patch does not update commit id
git apply patch does not update commit id

Time:11-17

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?

CodePudding user response:

TL;DR

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

My git bundle use case

For 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.

Most common case: copy a few commits from one server to the other

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.

What if the repos diverged between Host1 and Host2?

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.

The general rule for creating the bundle

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.

Epilogue

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.

  • Related