Git is an amazing piece of software, and almost all developers will know how to use, are using, or at least, have heard about it. It's a version control system that is essential for coding projects, as it helps us to track and manage the changes we do to our code. It also provides some functionalities to assist us in collaborating with other developers, as it makes sharing code and merging changes really easy for most of the cases. Sometimes we also joke that Git is the "blockchain" before blockchains are a thing, since a branch is essentially just a "chain" of commits, and you can "fork" out to create a new branch based on the current one... you see where this is going? :) Sadly, Git repositories don't exhibit the immutability characteristics of blockchains. They do have some traceability characteristics and you can argue that Git repositories are decentralised in some way, though.
Anyway, the relationship between Git and blockchains aren't the topic today.
Although Git reduces the barrier for us to collaborate with other developers by providing the necessary functions to facilitate code sharing and change merging, a lot of modern code collaborating relies on something that is beyond what Git provides. Namely, the use of online services such as GitHub and their features. In its heart, Git is a version control system, and it never strayed away from that. It helps you with tracking, pulling, pushing and merging code changes, and that is basically what it does, nothing more. It does not care what a GitHub is, or if your Git remote server even has a proper web interface for users to use. This means that although it can fetch from and push changes to the remote repository on GitHub, it doesn't know what a pull request is, or if there is a URL that can show the repository in a web browser. That is part of the beauty of Git - it does what it should and it keeps itself lean. It's not like your everyday app that tries to add a story feature just because everyone else is doing it.
Although it's cool, but this will mean that in general, our generic workflow in the office will be like this:
- Commit our code changes in a separate branch that is based off the branch that we want to merge in.
- Push the branch to remote.
- Open the web browser, open the repository's page (hopefully bookmarked), navigate to the pull requests page, select our newly pushed source branch, select our target branch, type a title and some description in the pull requests fields, and finally create the pull request so that someone can review it and get it merged.
The last step is just painfully long.
Even when we're not doing a pull request, sometimes we just have tasks to perform that will be easier to do if we are on the web interface. For example, checking some changes on another branch while we are working on our own branch (and we do not want to switch away from it). Wouldn't it be great if we can make life slightly easier and make ourselves a shortcut to simplify all that? Perhaps, in the terminal, because we do live in the terminal for a lot of our coding sessions?
Fortunately, it isn't too difficult to do that :)
When you pull a repository from a Git remote, the repository will have its remote origin URL configured in your local repo folder. You can see it in the config
file in the .git
folder of the repo, under the [remote "origin"]
section.
...or, as a simple one-liner:
git config --get remote.origin.url
This is what you get if you cloned the repository using SSH. If you cloned the repo with HTTPS, it'll give you a something that your browser can open directly. Although, whether if the remote server has something to show on this address, it's a different story. But hey, it's a HTTPS link!
Now, what do we do here?
If it is a GitHub repository and you got a HTTPS link, you basically have the link to the repo itself! GitHub will redirect links like https://github.com/user/repo.git
to https://github.com/user/repo
automatically. But, what if you cloned the repo using SSH instead? It's still quite simple, we're just going to modify it a little. After all, the remote URL we got there still contains everything that we need: the user and the repo.
Since we know that GitHub SSH remote URLs look like this:
git@github.com:user/repo.git
We will just have to replace the [email protected]:
at the front with https://github.com/
, and optionally, trim away the .git
at the end. sed
is our friend on this. If you're using Linux or Git Bash, it should be familiar...
git config --get remote.origin.url | sed 's;^git@github.com:;https://github.com/;'
Here, I'm using ;
as a separator for sed
. It's probably also my favourite separator character for sed
, as in experience it's not very common for us to stumble upon cases where we need to pass a string involving ;
to sed
. Besides that, ;
is also the statement separator character for a lot of programming languages, including my favourite C#. It's just intuitive to me :)
Through the help of sed
, we will get a proper link that we can use to visit our repo on GitHub now. That's not very hard, eh?
If all you want to do is to click on it, we can stop here now, but we love to be lazy so let's make the computer do more work for us... like, opening it directly after you run it in your terminal. For some reason, some programmers really hate the idea of needing to click things. I'm not one of those, but one less action needed is one more slacking point earned. Sounds good to me!
On Linux, it is very trivial: xdg-open
. We just need to pass the URL we got from just now into it, and it'll figure out the rest for us. Well, that's assuming that it is available on your install. It is a utility that is available on most Linux distributions out there, so there's a very high chance that you already have it, or can install it from your distro's repositories.
xdg-open $(git config --get remote.origin.url | sed 's;^git@github.com:;https://github.com/;')
On my Fedora Linux install, it automatically opens Firefox after executing this command, shooting me directly to the repo on GitHub. Now that's comfy. But, what if you're on Windows?
To give a summary before everything else: start
. Here's what I do in Git Bash.
start $(git config --get remote.origin.url | sed 's;^git@github.com:;https://github.com/;')
start
on Windows is like xdg-open
on Linux, it handles the link or the file that you pass to it with an appropriate application set as the default on your computer. So in this case, if my default web browser is Firefox, it'll let Firefox handle the link for me. If you for some reason has Internet Explorer as the default, it'll use that instead. I find it a better option than hard-coding the web browser's executable path or trying to call for a specific browser in the command, as it fits better with the computer's configuration and you don't need to deal with paths yourself. It's really quite a neat command.
The catch? It seems like not all shells on Windows can find this command. You can use it on PowerShell, Git Bash, or good ol' Command Prompt, but Elvish can't find it at all. It is a Windows specific command, and hence is naturally not something that can be found in the PATH like a normal executable could be. However, Git Bash seems to have some special handling to allow it to recognize this command. If you are using another shell, you might need to find your own workaround for this problem.
Anyway, here it is. You teleported to your repo on GitHub from the terminal! But, how could this be enough?
To just be a little bit more lazy, we modify the command above to open the issues page of the repo. For GitHub, it is very easy, because the URL for it is simply https://github.com/user/repo/issues
. We already have most of the work done above, the only thing left is to chop away the trailing .git
, and append /issues
to it.
Once again, we can use sed
to directly replace the .git
with /issues
...
git config --get remote.origin.url | sed 's;^[email protected]:;https://github.com/;' | sed 's;.git$;/issues;'
...and it'll give us exactly what we needed.
But, this isn't very reusable. Consider the case of GitHub, there are many pages of a repo that shares the parent URL of https://github.com/user/repo
! So, if we have a way to get the base repo URL, we would be free to append anything to it.
printf "%s/issues" $(git config --get remote.origin.url | sed 's;^[email protected]:;https://github.com/;' | sed 's;.git$;;')
Well, it looks quite messy as a one-liner. But if you are separating the second part into an individual function, you will be free to reuse it freely and just append anything to it with printf
. But, why did it cause my prompt to print directly after the URL instead of a new line? Turns out that printf
does not append a new line after the result :) It is not a problem if you directly pass it to start
or xdg-open
, though.
Now that's a lot of commands. What can we do with it? To use them easily and lazily, we can add them as an alias in Bash. Aliases are like alternate names to other commands, so it could do something like this:
(You can read more about adding permanent Bash aliases from here!)
Personally, I did more than that. As I made more and more of these shortcuts not only for GitHub but also Azure Devops (we use it at work), I ended up building a program in Bash to handle it. You can find it here, and so far I'm liking how it is working out. My favourite shortcut is the one I made to create a pull request, as it is a very frequently performed action in the workplace. I use it almost every working day, and I even made a few parameters for it to directly specify the source and target branches in the URL :) It probably is the comfiest command I built into it.
What are your favourite tricks with Git to save time and energy? I'm still constantly discovering new ways to work around Git repo problems in the workplace. Such as, it came to me that you can easily remove all tracked changes by committing all of them then hard-resetting to the previous commit. At the same time, you get a commit that you can reset back to if you regret later. A little bonus security that I can't complain.
That's all for now, see you next time!
Edit history:
2023-04-22 22:47 - Fix my missing description and header image (I forgot hotlinks do not make a thumbnail)