Skip to content

Instantly share code, notes, and snippets.

@slmingol
Forked from RichardBronosky/0-TLDR.md
Created September 14, 2018 22:30
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save slmingol/f5a4616506cece772b8c2626e2e1809f to your computer and use it in GitHub Desktop.
Save slmingol/f5a4616506cece772b8c2626e2e1809f to your computer and use it in GitHub Desktop.
How to easily launch a temporary one-off git server from any local repository, to enable a peer-to-peer git workflow.

User 1

remote_server=172.31.0.1
git daemon --verbose --export-all --base-path=.git --reuseaddr --strict-paths .git/ > /tmp/git-serve.log 2>&1 &
ssh -R 9418:localhost:9418 ec2-user@$remote_server
git clone git://localhost/ local-repo-name

Repo from workstation is cloned onto server.

User 2

remote_server=172.31.0.1
ssh -L 9418:localhost:9418 ec2-user@$remote_server

In a new local terminal (because the other one is now SSH'ed to the server)

git clone git://localhost/ local-repo-name

Repo from User 1's workstation is cloned to this workstation. User 1 only needs to commit their changes for User 2 to be able to pull them.

No need to push to the remote clone. In fact, if the goal was to get the code to User 2, you didn't need to clone it onto the server. That was only in case that you needed to run a test suite or something.

Launch a one-off git server from any local repository.

I tweeted this already but I thought it could use some expansion:

Enable decentralized git workflow: git config alias.serve "daemon --verbose --export-all --base-path=.git --reuseaddr --strict-paths .git/"

Say you use a git workflow that involves working with a core "official" repository that you pull and push your changes from and into. I'm sure many companies do this, as do many users of git hosting services like Github.

Say that server, or Github, goes down for a bit.

No worries, after all, one of the reasons you use git is so you have a copy of the entire project history in your local clone.

You can keep right on coding and committing, while you wait for the operations team to bring the server back to life. Note to self: buy doughnuts for operations team.

But what if, during this downtime, you want to collaborate with another person, who may not be a git expert, on the same repository?

Or, instead of downtime, what if you and your collaborator are in the field, and for some reason you can't get your VPN to let you connect to your official repo?

Or, what if you and your collaborator are spiking out a bunch of experimental changes, and even though you have access, you don't want to push your unfinished mess into the official central repository? (Not even as feature branches.) Maybe you're in the middle of cleaning up a disastrous rebase or merge and the branches are all over the place.

Well, git, as you are probably aware, is a "distributed" version control system.

Even though you might use a central "official" git repository in your workflow, you still have the ability to use git in a peer-to-peer manner, where you and your collaborator simply build and share commits with each other, and the central server never even has to know.

So, how do you get your branches and commits over to them, or vice versa?

  • You could use git's facilities for e-mailing patches. But that's a bit inelegant and requires some knowledge on their end of how to apply e-mailed patches.
  • You could create an account on your own machine for your collaborator to ssh into. But maybe you don't have local root access, or maybe you don't trust them with SSH access to your box.
  • You could clone your repo onto a thumbdrive and pass it back and forth. But that's rather tedious, especially if you happen to be on the same local network, and requires a thumb drive.

You can probably think of other methods, too. But there's a super easy way: if you can see each other on the network, you can launch a one-off git server that they can use as their remote to clone, fetch, and pull your changes, and kill it when you're done with it.

The tool that enables this is git daemon, which has a lot of options and functionality, but for the purpose of enabling this easy one-off "just serve up the repo I'm in," the way to use it is to create an alias. I like to call it git serve. Run:

git config --global alias.serve "daemon --verbose --export-all --base-path=.git --reuseaddr --strict-paths .git/"

Using an alias is actually crucial, because git aliases are executed in the base directory of your working tree. So the path '.git' will always point to the right place, no matter where you are within the directory tree of your repository.

Use your new git serve like so:

  1. Run git serve. "Ready to rumble," it will report. Git is bad-ass.
  2. Find out your IP address. Say it's 192.168.1.123.
  3. Say "hey Jane, I'm not ready/able to push these commits up to origin, but you can fetch my commits into your clone by running git fetch git://192.168.1.123/"
  4. Press ctrl+c when you don't want to serve that repo any longer.

You could also tell Jane to git clone git://192.168.1.123/ local-repo-name if she does not yet have a clone of the repository. Or, use git pull git://192.168.1.123/ branchname to do a fetch and merge at once, useful if you are working together on a feature branch.

Note however that you shouldn't do this on hostile networks if you keep secrets in your repository, because there's no authentication. It doesn't advertise its existence, but anybody with a a port scanner can find it, connect to it, and clone your repo.

But it's not super dangerous because it is read-only by default. Read the git daemon man page carefully if you think that you want to enable write access. In the case where you want to obtain your collaborator's commits, it's much safer to leave it read-only, and ask your collaborator to also run this command, so you can pull from them.

Tangentially related: on the subject of one-off servers, if you want to temporarily share a bunch of static files over HTTP: python -m SimpleHTTPServer

This is awesome for local development and test servers

Note: The default git port is 9418.

Consider

  1. Once you have a git daemon running, you can git clone git://localhost/ ~/src/new_copy just like you would git clone ~/src/original_copy ~/src/new_copy.
    • (You do know you can clone from directory to directory in order to try out new ideas you get while your working tree is a WIP. Don't you?)
  2. If someone on the same network can reach your IP they can git clone git://192.168.1.123/ local-repo-name as Datagrok said.
    • I stress If because that's not so at Starbucks, etc.

What about a remote server that you have to SSH to? (maybe even using VPN or a bastion, etc.)

  1. When you ssh to that server, you add -R 9418:localhost:9418 to the command.
    • Examples:
      • ssh -R 9418:localhost:9418 ec2-user@172.31.0.1
      • ssh -o 'ProxyCommand ssh -W %h:%p bastion.int' -R 9418:localhost:9418 ec2-user@172.31.0.1
  2. Now you can clone via git clone git://localhost/ local-repo-name on the server, and it is talking to your local workstation via a Reverse Tunnel.
    • Remember -R as <Remote port>:<target_host>:<target_port>

Tunnels are amazing! Anything must be possible!

Surely your partner at Starbucks (from #2 above) ought to be able to clone from you if that was possible.

  1. Have you partner ssh to that server and add -L 9418:localhost:9418 to the command.
    • Examples:
      • ssh -L 9418:localhost:9418 ec2-user@172.31.0.1
  2. Now she can (in another local terminal) clone via git clone git://localhost/ local-repo-name on her workstation, and it is talking to your workstation via a Forward Tunnel… that's pointed at the Reverse Tunnel from #4
    • Remember -L as <Local port>:<target_host>:<target_port>
    • Don't get overwhelmed with trying to remember what side of the tunnel the <target_host> and <target_port> are on.
      • The target is always on the opposite side of the tunnel as the port that is "listening".
      • (Otherwise you'd just connect to the target without a tunnel. Right?)
      • The side of the tunnel that is listening is indicated by the letter you use. Either -R or -L.

Read those checkbox bullets over and over again out loud until it sticks. When you are able to conjure SSH Tunnels without Googling or searching man pages, you will never look at "connection issues" the same way again.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment