subscribe tag tags calendar spinner search cloud star-empty star-full twitter github givey

Although what I'm about to talk about is well documented[1], I've never come across it in my 10 year career using Git. I stumbled across it out of sheer curiosity to see what would happen if I used a repository instead of a remote name. In theory Git would treat them the same, since everything is technically a ref, and it did. The idea is simply to be able to push your code anywhere, without having to first add the remote to your local repository. You're probably asking why you would want to do this, or why anyone would even care that this is possible. I have a few use cases below which are now way easier day to day.

Lots of remotes

Git, by design, is decentralised. However, nearly all use cases I've come across have used git in a centralised way. Teams or groups all put their code onto a hub, such as Github or Bitbucket, and each member pulls down the latest code from a single place. When one of these hubs go down, software engineers pretty much declare themselves a free bank holiday.

The irony is that Git is designed in a way where these hubs are completely none-essential in order to actually be used a version control system. With the correct network setup and workflow in place, any user can push and pull code directly between themselves and any other user, without a hub at all. You could push your latest change directly to someone for code review, who could then push it directly to a CI server. That CI server could then push directly to a build system or deployment server. Obviously complex workflows would have to be in place to ensure all team members get all revisions, which isn't trivial, via some sort of eventually consistent mesh topology.

In reality it's rare to use Git like this, but it's entirely possible. if anyone were to use Git is such a way, they would need a remote setup for each team member in order to push and pull code. git remote add john-smith [email protected]/secretapp1.git etc. While this could be automated quite easily, it'd still be a pain to keep all of these named origins locally. Likely, you're only going to want to push/pull code to a certain team member once or twice, but they're origin is always around. What if you have a team of 10,000 potential team members? Multiple people with similar names? You see my point. Un-named origins solve this:

git push [email protected]/secretapp1.git backdoor-branch

A great use case for this in the real world would be to push/pull large changes over a local network in an office environment. For example if there isn't an internal hub, teammates could achieve much higher transfer speeds by direct communication rather than first pushing then pulling from a hub. In my case I push directly to my Macbook from my iMac over SSH before I leave the office. This was mostly useful when I had a 3G internet connection at home and Git would sometimes drop connections or take a long while to pull changes.

Multi-stage Heroku apps

A more common and realistic problem that I've come across many times myself is multi stage Heroku apps. This can also apply to apps where you run a mini version on your own account rather than the real one for a client. The way heroku-cli works by default is it assumes you have a single remote called heroku. You can actually call it whatever you want as internally it checks the remote for heroku style syntax such as As long as you have this single endpoint, you can use all commands without having to specify an application or remote everything using -a secretapp2 or -r herokuremote.

Likely, you're going to have secretapp2-staging and secretapp2-production. As soon as you add that second remote, every single command now needs the -a or -r suffix which is a pain to type out. 95% of the time, you are going to be running commands on the staging app; Checking logs, shell-ing in to the rails console, testing buildpack configurations. The production remote is really just there for deployments and/or shell-ing in to rails to change a piece of customer data you forgot to make available through the admin panel but customer support team need it right now at 4am or the client will cry themselves to sleep.

Realistically what you want is the single remote to make development commands easier to type. But now do you need to add the production remote, deploy, then remove it again for local CLI zen? No! You can use direct push like above; Since Heroku is just another decentralised node you can push directly to it without a name.

git push master

The advantage to this is you can't accidentally deploy to the wrong app when you forget which terminal tab you're in (we've all been there). If you had a named remote then git push heroku-production master would deploy master to production, but for the wrong app; Disaster. In an ideal world you could never deploy to production from your local machine. That would all be handled via nicely configured CI that never goes wrong. In the real world we prototype and we work on hobby apps. Many hobby apps; So things like this are bound to happen eventually. Luckily, git has built in protection for this if you use the remote explicitly as above. You will actually get a rejection message because you are pushing content that doesn't match the remote's hash signature.

Side note: Never use -f (force push flag) as it will bypass said protection. That should be also be general rule for good practice. Although it doesn't help in the Heroku case, I recommend always enabling branch protection on your remote. [2]


So there you have it. A quick and dirty way to push and pull your way around any remote without all the commitment issues of their named origins taking up precious bytes on your machine.


Posted 13 Sep 2017 by Marc Qualie