90

I want to use version control but, due to security reasons, the server I'm working on has no internet access: I can only move files on a USB flash drive. Can I still use Git with this setup? Can I create small patches that I can apply on a Git repository?

9
  • 65
    Your title says no network access, your question says no internet access; a huge difference.
    – tkausl
    Oct 18, 2018 at 4:18
  • 7
    @TutuKaeen You can have a local network that's not connected to the internet. So instead of github.com you set up git server at eg. 192.168.1.100 and everything else works same.
    – Agent_L
    Oct 18, 2018 at 9:03
  • 12
    @TutuKaeen: The critical question is whether direct (or indirect) network communication is possible between the two machines. So in your case, both machines are networked, but the networks are separated? In that case, please edit that information into your question.
    – sleske
    Oct 18, 2018 at 12:14
  • 15
    @TutuKaeen Your question remains unclear. You say you want to use version control, but in your comments you require that it help you deploy to production. These issues don't always overlap. I think you have good answers below now, but in the future it would be helpful if your question were more comprehensive about your requirements, which seem to be: "I want to use version control, my development machine doesn't have internet access, it does have network access but not to the production machine, and I want to know how to get code out of version control onto the production machine."
    – DavidS
    Oct 18, 2018 at 16:46
  • 4
    It just seems weird to use the term server for a machine not connected to any network. It could just be a local network even without internet access but it's still a network nonetheless.
    – dokgu
    Oct 18, 2018 at 20:00

5 Answers 5

160

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.

10
  • 50
    To add to this exceptional answer - It may also be worthwhile to investigate using a 'bare' respository on the flash drive. 'bare' repositories don't have a working tree, and so cut out a category of potential issues when used as a shared 'point of authority', which sounds like the OP's use-case. Oct 17, 2018 at 15:36
  • 5
    The file:// is also a bit more flexible. It allows you to use some features (like shallow clones) that you can't with a local path. Oct 17, 2018 at 15:53
  • 1
    @IronGremlin Could you expand on this "shared point of authority" notion? I'm not a Git expert and I'm curious what you mean by it. Oct 18, 2018 at 17:39
  • 2
    @LightnessRacesinOrbit - This is a pretty dense topic, but, basically, git is distributed, so everyone gets their own history. A can ask B for their version of history, but C doesn't know about it unless someone tells them. Having a single repository to store the 'authoritative' history means D acts as a clearing house for histories. So, A tells D about changes, and B and C know to talk to D to stay up to date, rather than doing side-channel stuff amongst themselves. Case in point, if OP's server is C, and the flash drive is D, it makes sure the server doesn't get left out of A/B interactions. Oct 18, 2018 at 17:58
  • 6
    @LightnessRacesinOrbit Important to note here that bare doesn't have to mean authoritative, it's just useful in that context. For example, it's also useful because, lacking a working tree, it's a smaller diskspace (or bandwidth) footprint. This used to be a hell of a lot more important than it is now, but still comes up. Oct 18, 2018 at 18:12
47

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.

5
  • actually it would not be bad for my purposes, also in git nothing is "primary" as every repository has the whole history, so you can recreate it every time something goes bad Oct 17, 2018 at 14:02
  • manual tagging or note-keeping is needed, one option unless the repo is very big is: git bundle create my.bundle --all, it should contain everything
    – birdspider
    Oct 17, 2018 at 17:10
  • I like this answer more as it's more illustrative even though the accepted answer and this says the same thing.
    – Rystraum
    Oct 18, 2018 at 13:38
  • What's the significance of the "bare" option? Oct 18, 2018 at 17:40
  • 1
    It creates a repository that is just the database (what you'd normally find in the .git/ hidden folder), without a 'working tree' (the editable files). It is the preferred form for repositories that you git push to. Oct 18, 2018 at 17:54
21

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.

1
  • Don't forget to mention the --all flag to get everything. If the repo is small enough this is the simplest process as you simply transfer everything every time! Just don't loose the memory stick - probably the biggest security issue! Oct 19, 2018 at 11:08
7

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:


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.

4

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.

7
  • 3
    that I know, but I want to work on another computer and apply it to files on server with no internet access Oct 17, 2018 at 11:46
  • 2
    @TutuKaeen I see nothing wrong with having the repository on a flash drive and just cloning/syncing it to hard drives of different computers. However, "server without internet access" sounds strange, the goal of a server is to provide a service, most often the service is related to networking (but not always, indeed). Oct 17, 2018 at 13:11
  • 2
    @dhae - Please take a moment to provide more details on how to use Git locally. Only indicating it can be done isn't that helpful of an answer.
    – Ramhound
    Oct 17, 2018 at 13:32
  • 2
    @anonymousLurker the serving is serving data to closed network in very important institution. It just doesn't serve anything to the broad internet, as the data is very delicate and for the employees only. Oct 17, 2018 at 14:05
  • 1
    @TutuKaeen: If it has any network access, you could always run your own Git server via SSH. There's more to Git than just GitHub. Oct 17, 2018 at 15:17

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .