I have all of my data on my home PC in a git repo.
This home PC (and therefore the git repo) is only accessible from the local LAN that the home PC is on. Putting the git repo on an internet-accessible cloud server, or making my home PC accessible on the internet, is not an option. This limitation is important to mention for the below question, because otherwise the obvious solution is "just put your git repo on a cloud server".
I have a laptop I travel with called Laptop-A. Before I leave on my travels, I check out the repo on Laptop-A from my home PC by using: git clone ssh://main-PC/... During my travels, I make local changes on Laptop-A, and I commit them locally, but I can't push them since the main repo on my home PC is not accessible via the internet. My changes can only be pushed when return home and am on the same LAN as my home PC.
This all works, but now I'm adding Laptop-B while traveling. This laptop also has the main repo cloned, just like Laptop-A does. In fact, the two laptops are basically identical but they are two separate machines. I'm doing this in case one of the laptops has a hardware malfunction. In that case, I still have the other laptop.
However, now I run into the problem that for the two laptops to truly be redundant, when I make a local change to a git repo on one laptop, that change is not reflected in the git repo on the other laptop, since they are obviously two separately checked out copies of the repo. I could commit each change manually and separately on each laptop, but that is awkward and I could make a mistake leading to inconsistencies. Even if I do it correctly, it's annoying and will lead to merge conflicts once I want to push from both laptops when I return home.
What I want to do is commit a change on Laptop-A and then have this synced to Laptop-B, so that I can push (to the main repo) from either laptop once I return home.
How can I accomplish this?
No Git repository is "special" or "more important" than any other Git repository, unless you deem it so yourself.
When you
git clone ssh://main-PC/...on Laptop A, the Git you run on Laptop A creates a Git repository that is a peer of the Git onmain-PC. You only think of the main PC version as "more master-y" because that's how you use it, and in fact, while traveling, the laptop version is "more master-y" because it gets new commits.Your laptop-A repository uses the name
originto remember the URLssh://main-PC/.... The nameoriginis a remote. Your laptop-A Git uses remote-tracking names of the formorigin/*to remember branch names in that other Git.On your laptop-B, you can either clone your laptop-A clone, or your main-PC clone. Your laptop-B will remember whatever URL you use here under its name
origin, and use remote-tracking namesorigin/*to remember branch names copied during the clone process.You can add more remote names to either laptop. For instance, assuming laptops A and B both ran
git clone ssh://main-PC/..., so that on both,originmeansssh://main-PC/..., you might want to do this on laptop A:for instance (of course the IP address may change over time, so you'll need to remove and re-add, or use
git remote set-url, to fix it sometimes). Now laptop-A has a name for laptop-B, and you cangit fetchorgit pushfrom A to B to obtain (fetch) or send (push) any commits that are on B but not A (fetch) or A but not B (push). Similarly, on laptop B:will create the remote name
laptop-aon laptop B, and now you cangit fetchorgit pushusing this name.Commits that are on one laptop are now easily transferred to the other. Note that the remote-tracking name,
laptop-b/masteron laptop A for instance, is how the one laptop will remember that the other laptop has some commit—so now you'll want to have whichever laptop is "behind" update its local branch name(s) to remember the new commit(s).The key notion is that all three repositories are peers. None has any special status, except insofar as you personally decide that one has some special status. Instead of making a static decision, you can decide based on commit hash IDs as recorded under remote-tracking names like
origin/master,laptop-a/master, andlaptop-b/master.The branch names in each of these peer repositories are different. The commit hash IDs are the same, as long as they all have the same commits. When one repository lacks some commit(s),
git fetchwill yank them in (from the repository that needs the commits, to the one that has them), and/orgit pushwill send them (from the repository that has the commits, to the one that needs them).These two operations—fetch and push—are almost symmetric, except for one other key difference. The fetch operation takes the source repository's branch names and renames them, so that they come in under remote-tracking names like
origin/master. The push operation sends the commits, then either:Because the target of a push is setting its branch names, several special conditions hold:
--bareas it never has any branch checked out into a work-tree.For these reasons, it's sometimes nicer to use an all-fetch work-flow; but then you have to use a second Git command to combine the new commits into the local repository. Many people like to use the
git pullcommand for this, as it actually runsgit fetchfirst, then runs a second Git command to incorporate the fetched commits.