35

I have two git repositories on different PCs. I have some local branches on every one of them. I don`t want to send this branches to remote server, just keep them local. How can I synchronize then without using a web? Can I just zip repository on one PC and move to another? Is that safe? Maybe I can export somehow newest changes from every branch?

Wolf
  • 8,482
  • 7
  • 48
  • 92
szaman
  • 6,388
  • 13
  • 47
  • 79
  • 1
    The only difference between the git repository on "the server" (if there is a difference) is that the repo on the server is probably bare. Think of the other PC exactly the same way you think of the server. – William Pursell Feb 01 '11 at 11:59

4 Answers4

26

Rather than making a bare clone, I prefer making a bundle (see "How can I email someone a git repository?"), which generates one file, easier to copy around (on an USB stick for instance)

The bonus is that is does have some of the characteristics of a bare repo: you can pull from it or clone it.
But only have to worry about one file.

machineB$ git clone /home/me/tmp/file.bundle R2

This will define a remote called "origin" in the resulting repository that lets you fetch and pull from the bundle. The $GIT_DIR/config file in R2 will have an entry like this:

[remote "origin"]
    url = /home/me/tmp/file.bundle
    fetch = refs/heads/*:refs/remotes/origin/*

To update the resulting mine.git repository, you can fetch or pull after replacing the bundle stored at /home/me/tmp/file.bundle with incremental updates.

After working some more in the original repository, you can create an incremental bundle to update the other repository:

machineA$ cd R1
machineA$ git bundle create file.bundle lastR2bundle..master
machineA$ git tag -f lastR2bundle master

You then transfer the bundle to the other machine to replace /home/me/tmp/file.bundle, and pull from it.

machineB$ cd R2
machineB$ git pull
Community
  • 1
  • 1
VonC
  • 1,042,979
  • 435
  • 3,649
  • 4,283
23

See this blog post "Synchronizing Git repositories without a server " (by Victor Costan).

This post describes a method for pushing changes between two repositories without using a server with network connections to both hosts having repositories

Start up by creating a repository on the USB stick.

mkdir /path/to/usb/stick/repository.git
git clone --local --bare . /path/to/usb/stick/repository.git

Then register the repository on the USB stick as a remote repository, and push the desired branch to it (if you don't want to push master, substitute your desired branch).

git remote add usb file:///path/to/usb/stick/repository.git
git push usb master

In the future, you can treat the USB repository as any other remote repository. Just make sure it's mounted :) For instance, the following pushes new changes to the USB repository.

git push usb

On the receiving end, mount the USB stick, and use a file URL for the repository

file:///path/to/usb/stick/repository.git

A few handy commands:

# cloning the repository on the USB stick
git clone file:///path/to/usb/stick/repository.git
# updating a repository cloned from the USB stick using the above command
git pull origin
# adding the USB stick repository as a remote for an existing repository
git remote add usb file:///path/to/usb/stick/repository.git
# updating from a remote repository configured using the above command
git pull usb master
mpenkov
  • 20,356
  • 7
  • 75
  • 121
  • 1
    Never rely *completely* on an external link: you don't know how long it will last. With http://blog.stackoverflow.com/2009/06/stack-overflow-creative-commons-data-dump/ , that information will be available forever. – VonC Feb 01 '11 at 08:36
  • would that first "git clone --local" be better as "git clone --no-hardlinks" to make it explicitly clear that it needs to be a deep copy? – Dave Amphlett Aug 02 '11 at 10:40
  • I believe it would. On OSX, I got unix link-failure errors until I switched that. I also switched to --no-local in the same vein, although I'm not certain it's necessary. Command that worked for me: `git clone --no-local --no-hardlinks --bare . /path/to/repository.git/ `. After that, two of us were able to push and pull like with any other remote. – XML Aug 27 '14 at 04:12
  • @VonC at least we hope it will last forever - there's no guarantee that SO will be about in 10 years time. – Snowcrash Sep 25 '14 at 15:12
  • I get `fatal: repository '.' does not exist` at this stage: git clone --local --bare . /path/to/usb/stick/repository.git – Snowcrash Sep 25 '14 at 15:18
5

Direct copy of a repository to the other file system is an alternative to bare clone or to bundle. After copying you can set the copied repo up directly as a local remote - unintuitive as local remote may seem - to fetch and merge into the first repository.

I.e. to merge repo2 from a second computer into ~/repo1, first copy repo2 to the repo1 file system at ~/repo2 (memory stick, network copy, etc.) and then you can use the answer to Git pulling changes between two local repositories:

~/repo1 $ git remote add repo2 ~/repo2
~/repo1 $ git fetch repo2
~/repo1 $ git merge repo2/foo

This works because as the wikipedia article on git says: "A Git repository — data and metadata — is completely contained within its directory, so a normal system-level copy (or rename, or delete) of an entire Git repository is a safe operation. The resulting copy is both independent of and unaware of the original."

Community
  • 1
  • 1
sage
  • 4,100
  • 1
  • 36
  • 46
  • can anyone with more knowledge than me confirm this? @sage if I just want to backup my directory (which contains my .git) by copy-pasting to a USB-stick, would that not be enough? – nutty about natty Mar 31 '13 at 17:05
  • 2
    @nutty - Direct copying does work fine for transferring the repo in its exact state and I often do that. However, for some use cases I find it preferable to be able to pull/merge from one disk location to another (e.g., when I have edited both repo locations and I want to sync them up). Git is delightfully accommodating in this regard. :-) – sage Apr 01 '13 at 17:13
0

I'd just like to add a little twist to things. The information in other posts seems right, but I'd like to mention a few extra things I do in practice.

If I do

git remote -v

I get information like this

USB_F   file:///f/Git_repositories/projectname.git (fetch)
USB_F   file:///f/Git_repositories/projectname.git (push)
USB_G   file:///g/Git_repositories/projectname.git (fetch)
USB_G   file:///g/Git_repositories/projectname.git (push)

Basically I have defined several remotes with USB names rather than just one as suggested since the drive letter allocated to my USB device changes depending on the port I insert it into.

I then run a script with contents like this

cd /path/to/projectname

if [ -d /f/Git_repositories/projectname.git ] 
then
    git push USB_F --all
    git push USB_F --tags
fi
if [ -d /g/Git_repositories/projectname.git ] 
then
    git push USB_G --all
    git push USB_G --tags
fi

The intention is to push all branches and all tags to the USB repository if it exists and where ever it is. (The -d flag is checking for existence of the git repository directory and conditional code only executes if the directory exists.)

The original question said: I have some local branches on every one of them. I don`t want to send this branches to remote server, just keep them local. How can I synchronize ...

The push -all and push --tags command do this synchronizing, making sure that all the branches and tags are pushed to the USB repository, even new ones that the USB repository was unaware of. There is no defaulting to master or needing to know the names of branches and handling them one by one.

I run this for backup purposes so I've only shown the push side of things, and reduced the number of projects and repositories. In reality I backup multiple projects to multiple locations, but it's only the repeated USB items that are relevant here.

Another thing that is rather obvious but that I have not seen mentioned, is that in order to sync PC A and PC B, you'd need to

1. sync PC A and the USB device
2. sync PC B and the USB device
3. sync PC A and the USB device again!

Or viewed differently, go

PC A -> USB -> PC B
PC B -> USB -> PC A

so that ultimately the branches and tags are the same on the two machines.

Ivan
  • 3,463
  • 28
  • 26