Using Git across multiple systems without network access

Solution 1:

Sure, there's nothing about Git that requires a particular protocol. Just out of the box the standard client supports HTTP(S), SSH, the custom Git protocol and, importantly, the local protocol. That just takes a path to a local .git directory, which can be within working directory (/path/to/project/.git) or just a bare directory (/path/to/project.git), though the naming is just a convention.

This means you can, of course, add a flash drive as a remote:

git remote add origin /mnt/flashdrive/foo.git

or, on Windows:

git remote add origin F:\foo.git

Or even add it as an additional remote with a different name (if you prefer origin to point towards an Internet server somewhere):

git remote add flashdrive /mnt/flashdrive/foo.git

Then you can just push/pull to/from this remote just like any other.

If you read the documentation, you'll notice there's also a file:// protocol that behaves slightly differently. It is recommended to use a local path as that will make use of some additional optimisations - if you use the file:// protocol then git will use some standard network components (to talk to the local disk), which is slower.

Solution 2:

On a single computer, nothing special is needed. Run git init in your desired directory and work with Git as you normally would.

For synchronizing a repository across multiple computers, there are several methods.

Method 1a (no network at all): You can create a 'bare repository' on the USB stick, then push to it and pull from it as you would with any other remote repository. In other words, repository operations via local paths aren't any different from operations via SSH or HTTPS URLs.

  1. Create a 'remote' repository:

    $ git init --bare /mnt/Stick/Repositories/Large_Project.git
    
  2. In computer 1, push everything to it:

    $ cd ~/Large_Project
    $ git remote add usb /mnt/Stick/Repositories/Large_Project.git
    $ git push usb master
    
  3. In computer 2, well, same as always.

    $ git remote add usb /mnt/Stick/Repositories/Large_Project.git
    $ git pull usb
    

(You can push/fetch/pull from a URL or path directly, too.)

Method 1b (internal network): If you have an internal server with SSH available, and if it has Git installed, you can do the same as above, just specify an SSH address using the [user@]host:path or ssh://[user@]host/path syntax.

  1. Create a 'remote' repository by running git init --bare <somepath.git> on the designated server (via SSH).

  2. In computer 1, the same way as demonstrated earlier.

    $ git remote add origin myserver.example.com:Gits/Large_Project.git
    

    Or if you prefer:

    $ git remote add origin ssh://myserver.example.com/~/Gits/Large_Project.git
    
  3. In computer 2, again the same as method 1a.


Method 2: You can create 'transfer bundles' which archive a given list of commits into a single file.

Unfortunately the bundle commands don't automatically remember what was already bundled the last time, so manual tagging or note-keeping is needed. I'll just take the examples from the git-bundle manual.

  1. In computer 1, create a bundle of the entire branch:

    $ cd ~/Large_Project
    $ git bundle create /mnt/Stick/Project.bundle master
    $ git tag -f last-bundled master
    
  2. In computer 2, pull from the bundle as if it were a repository:

    $ cd ~/Large_Project
    $ git pull /mnt/Stick/Project.bundle
    

Subsequent bundles don't need to pack the whole master – they can pack just the newly added commits from last-bundled..master instead.

  1. In computer 1, create a bundle of the newly added commits:

    $ cd ~/Large_Project
    $ git bundle create /mnt/Stick/Project.bundle last-bundled..master
    $ git tag -f last-bundled master
    
  2. Same as above.

Solution 3:

git bundle create

One of the methods is to use external storage to exchange data between repositories is git bundle. This way you only have single files for each transfer, not intermediate Git repositories.

Each "git push" turns into creation of a file, "git fetch" fetches things from that file.

Demo session

Creating the first repository and doing the first "push"

gitbundletest$ mkdir repo1

gitbundletest$ cd repo1

repo1$ git init
Initialized empty Git repository in /tmp/gitbundletest/repo1/.git/
repo1$ echo 1 > 1 && git add 1 && git commit -m 1
[master (root-commit) c8b9ff9] 1
 1 file changed, 1 insertion(+)
 create mode 100644 1

repo1$ git bundle create /tmp/1.bundle master HEAD
Enumerating objects: 3, done.
Counting objects: 100% (3/3), done.
Writing objects: 100% (3/3), 384 bytes | 384.00 KiB/s, done.
Total 3 (delta 0), reused 0 (delta 0)

"cloning" to the second repository (i.e. the second computer):

gitbundletest$ git clone /tmp/1.bundle repo2
Cloning into 'repo2'...
Receiving objects: 100% (3/3), done.

gitbundletest$ cd repo2/

repo2$ cat 1
1

Doing some changes and "pushing" them to another bundle file:

repo2$ echo 2 > 1 && git add 1 && git commit -m 2
[master 250d387] 2
 1 file changed, 1 insertion(+), 1 deletion(-)

repo2$ git bundle create /tmp/2.bundle origin/master..master origin/HEAD..HEAD
Enumerating objects: 5, done.
Counting objects: 100% (5/5), done.
Writing objects: 100% (3/3), 415 bytes | 415.00 KiB/s, done.
Total 3 (delta 0), reused 0 (delta 0)

"pulling" changes to the first repository:

repo2$ cd ../repo1

repo1$ git pull /tmp/2.bundle 
Receiving objects: 100% (3/3), done.
From /tmp/2.bundle
 * branch            HEAD       -> FETCH_HEAD
Updating c8b9ff9..250d387
Fast-forward
 1 | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

repo1$ cat 1
2

Unlike the first bundle, second one contains only partial Git history and is not directly clonable:

repo1$ cd ..

gitbundletest$ git clone /tmp/2.bundle repo3
Cloning into 'repo3'...
error: Repository lacks these prerequisite commits:
error: c8b9ff94942039469fa1937f6d38d85e0e39893a 
fatal: bad object 250d38747656401e15eca289a27024c61e63ed68
fatal: remote did not send all necessary objects

There is disadvantage in using bundles that you need to manually specify what range of commits each bundle should contain. Unlike git push, git bundle does not keep track what was in previous bundle, you need to manually adjust refs/remotes/origin/master or bundles would be bigger than it could be.

Solution 4:

You need to first install Git. Then to create a new repository, run within the folder that you've copied:

git init

Then you can add files you want to version control by git add (add -a for all files) and start committing the changes (git commit).

You don't have to push to any remote, as you can work on your local history (git log).

For more information, check:

  • Git tutorial.
  • git - the simple guide

Pushing/pulling without internet

Using git push command, it's possible to push over SSH (using local connection, intranet):

git remote add server ssh://[user@]host.xz[:port]/path/to/dev/repo.git/
git push server

or pushing into the folder:

git push /mnt/usb/my_repo

This assumes you've two copies of your repository.

The same with pulling, e.g.

git pull /mnt/usb/my_repo

Patching

To apply patches, you can use patch command or git apply.

See: Create patch or diff file from git repository and apply it to another different git repository.

Solution 5:

You can use Git locally too. Then your commits are only stored locally, and you still have version control with it (and can diff/merge etc.), but you just can't access the repository from any other computer.

You can start a local Git repository by running git init in your local folder. As described here.