|
| 1 | +# PolyHack Toronto |
| 2 | + |
| 3 | +### Pain |
| 4 | + |
| 5 | +I had a problem. `https://` consistently broke for me when I tried to push. This is most likely because I had 2FA enabled, didn't have the key stored in my osx-credentials, and [wasn't using a token](http://olivierlacan.com/posts/why-is-git-https-not-working-on-github/), but I didn't know that yet. |
| 6 | + |
| 7 | +All of this could have been avoided if I had just figured this out earlier. |
| 8 | + |
| 9 | +### My solution |
| 10 | + |
| 11 | +Switching the git protocol to `ssh://` solved the problem for me, but I didn't want to do that manually, each time. I work with more git repositories than most people I know, as I do documentation work fairly often. At current count, I have 367 repositories in my `src` folder, and around a thousand repositories on GitHub. Not doing that manually. |
| 12 | + |
| 13 | +### Protocols out there |
| 14 | + |
| 15 | +What kind of protocols are there? https://gist.github.com/grawity/4392747 |
| 16 | + |
| 17 | +#### git |
| 18 | + |
| 19 | +- Does not add security beyond what Git itself provides. The server is not verified. |
| 20 | +- You cannot push over it. |
| 21 | + |
| 22 | +#### https |
| 23 | + |
| 24 | +- HTTPS will always verify the server automatically, using certificate authorities (generally secure). |
| 25 | +- Uses password authentication for pushing, and still allows anonymous pull. |
| 26 | +- Downside: You have to enter your GitHub password every time you push. Git can remember passwords for a few minutes, but you need to be careful when storing the password permanently – since it can be used to change anything in your GitHub account. |
| 27 | +- If you have two-factor authentication enabled, you will have to use a personal access token instead of your regular password. |
| 28 | +- HTTPS works practically everywhere, even in places which block SSH and plain-Git protocols. In some cases, it can even be a little faster than SSH, especially over high-latency connections. |
| 29 | + |
| 30 | +#### http |
| 31 | + |
| 32 | +- Doesn't work with GitHub anymore, but is offered by some other Git hosts. |
| 33 | +- Works practically everywhere, like HTTPS. |
| 34 | +- But does not provide any security – the connection is plain-text. |
| 35 | + |
| 36 | +#### ssh |
| 37 | + |
| 38 | +Uses public-key authentication. You have to generate a keypair (or "public key"), then add it to your GitHub account. |
| 39 | +Using keys is more secure than passwords, since you can add many to the same account (for example, a key for every computer you use GitHub from). The private keys on your computer can be protected with passphrases. |
| 40 | +On the other hand, since you do not use the password, GitHub does not require two-factor auth codes either – so whoever obtains your private key can push to your repositories without needing the code generator device. |
| 41 | +However, the keys only allow pushing/pulling, but not editing account details. If you lose the private key (or if it gets stolen), you can just remove it from your GitHub account. |
| 42 | +A minor downside is that authentication is needed for all connections, so you always need a GitHub account – even to pull or clone. |
| 43 | +You also need to carefully verify the server's fingerprint when connecting for the first time. Many people skip that and just type "yes", which is insecure. |
| 44 | +Uses port 9418 for it's daemon. Can be blocked for Corporate stuff. |
| 45 | + |
| 46 | +(Note: This description is about GitHub. On personal servers, SSH can use passwords, anonymous access, or various other mechanisms.) |
| 47 | + |
| 48 | +#### / |
| 49 | + |
| 50 | +- Clone from /srv/git/project.git |
| 51 | +- This is often used if everyone on your team has access to a shared filesystem such as an NFS mount, or in the less likely case that everyone logs in to the same computer. |
| 52 | +- Git tries to use hardlinks or directly copy the files it needs |
| 53 | +- Everyone who has access can manipulate date, uses same file access as server |
| 54 | +- Not necessarily faster |
| 55 | + |
| 56 | +#### file:// |
| 57 | + |
| 58 | +- Same as above, but git uses the same transfer processes it does for across a network |
| 59 | + |
| 60 | + |
| 61 | +### Setting these globally |
| 62 | + |
| 63 | +You can clone everything over git://, but tell Git to push over HTTPS. |
| 64 | + |
| 65 | +``` |
| 66 | +[url "https://github.com/"] |
| 67 | + pushInsteadOf = git://github.com/ |
| 68 | +``` |
| 69 | + |
| 70 | +Run this in `~/.config/git/config` or `.gitconfig`. |
| 71 | + |
| 72 | +### Setting locally |
| 73 | + |
| 74 | +``` |
| 75 | +[remote "origin"] |
| 76 | + url = git://RichardLitt/git-remote-to-ssh.git |
| 77 | + pushUrl = ssh://RichardLitt/git-remote-to-ssh.git |
| 78 | +``` |
| 79 | + |
| 80 | +### What does GitHub allow? |
| 81 | + |
| 82 | +From [`hosted-git-info`](https://www.npmjs.com/package/hosted-git-info): |
| 83 | + |
| 84 | +``` |
| 85 | +github: { |
| 86 | + // First two are insecure and generally shouldn't be used any more, but |
| 87 | + // they are still supported. |
| 88 | + 'protocols': [ 'git', 'http', 'git+ssh', 'git+https', 'ssh', 'https' ], |
| 89 | + 'domain': 'github.com', |
| 90 | + 'treepath': 'tree', |
| 91 | + 'filetemplate': 'https://{auth@}raw.githubusercontent.com/{user}/{project}/{committish}/{path}', |
| 92 | + 'bugstemplate': 'https://{domain}/{user}/{project}/issues', |
| 93 | + 'gittemplate': 'git://{auth@}{domain}/{user}/{project}.git{#committish}', |
| 94 | + 'tarballtemplate': 'https://{domain}/{user}/{project}/archive/{committish}.tar.gz' |
| 95 | +} |
| 96 | +``` |
| 97 | + |
| 98 | +### So, back to https |
| 99 | + |
| 100 | +I want to change all of my repository remotes from `https` to `ssh`. |
| 101 | + |
| 102 | +``` |
| 103 | +🐕 git remote -v |
| 104 | +origin https://github.com/RichardLitt/git-remote-to-ssh.git (fetch) |
| 105 | +origin https://github.com/RichardLitt/git-remote-to-ssh.git (push) |
| 106 | +``` |
| 107 | + |
| 108 | +To |
| 109 | + |
| 110 | +``` |
| 111 | +🐕 git remote -v |
| 112 | +origin [email protected]:RichardLitt/git-remote-to-ssh.git (fetch) |
| 113 | +origin [email protected]:RichardLitt/git-remote-to-ssh.git (push) |
| 114 | +``` |
| 115 | + |
| 116 | +### Shell script |
| 117 | + |
| 118 | +I found a handy shell script online. Let's look at it. |
| 119 | + |
| 120 | +```sh |
| 121 | +git checkout 79c4b111ad4d372f08a60e1fa97399e885753b95 |
| 122 | +``` |
| 123 | + |
| 124 | +### Atwood's Law |
| 125 | + |
| 126 | +> Any application that can be written in JavaScript, will eventually be written in JavaScript. |
| 127 | +
|
| 128 | +### Exec all the bash |
| 129 | + |
| 130 | +My first thought was using `exec()`, which can be pretty evil. I decided to use [`execa()`](https://github.com/sindresorhus/execa). So, let's do a simple port. |
| 131 | + |
| 132 | +```js |
| 133 | +execa(`git remote -v | grep -m1 '^${remote}' | sed -Ene's#.*(https://[^[:space:]]*).*#\1#p'`) |
| 134 | + .then((res) => console.log(res)) |
| 135 | + .catch((err) => console.log('Screw you everything is broken')) |
| 136 | +``` |
| 137 | + |
| 138 | +Of course, I got this: |
| 139 | + |
| 140 | +``` |
| 141 | +SyntaxError: Octal escape sequences are not allowed in strict mode. |
| 142 | +``` |
| 143 | + |
| 144 | +At this point, on my third refactor, I wondered - well, you know, there's probably a better parsing library out there for git, and I probably don't need to use `exec`, or `grep`. It's a silly thing to do. |
| 145 | + |
| 146 | +### Parsing gitconfig |
| 147 | + |
| 148 | +I spent a while doing fs.readFileSync, before I decided this was stupid. |
| 149 | + |
| 150 | +```js |
| 151 | +const parse = require('parse-git-config') |
| 152 | +var config = parse.sync(); |
| 153 | +``` |
| 154 | + |
| 155 | +Let's go and livecode. |
| 156 | + |
| 157 | +### Voila |
| 158 | + |
| 159 | +The thing is done! It works. It also: |
| 160 | + |
| 161 | +- Transforms any git url to ssh, not just https |
| 162 | +- Works for any valid git url |
| 163 | +- Is way easier for me to debug |
| 164 | + |
| 165 | +### Publish |
| 166 | + |
| 167 | +And that's it. I now have the thing I wanted, and I've learned a ton along the way. Hooray! |
| 168 | + |
| 169 | +### Irony |
| 170 | + |
| 171 | +I renamed the GitHub repo from `github-origin-https-to-ssh` to `git-remote-to-ssh`, and then manually edited my .gitconfig file to reflect the change. Did I accomplish anything? I've no idea. |
| 172 | + |
0 commit comments