More on git Published the 2020-09-21 A while ago, I wrote [an article about barebones git hosting](barebones-git) in which I showcased the built-in git templating feature as a side note. The most common feedback I received from it was to try to introduce some more "less-known" git features, and this led me to write this article. # Commands Here, I will outline a few nifty commands and modules that are, in my humble opinion, pretty worth checking out, even if you won't end up using them. ## `git-annex`: Track files without versioning their content For non-LFS git projects, there is a way to manage heavy files without pulling them into the git tree. Instead, [the `git-annex` command](https://www.mankier.com/1/git-annex) will keep track of files based on checksums, and allow most standard git operations without having to set up a LFS server, or to destroy your git tree. It allows tracking, moving, locking, synchronizing, files, but can do much more! For example, the `git annex addurl https://pypi.artemix.org/mailhook/mailhook-0.0.2-py3-none-any.whl` command will download the `mailhook-0.0.2-py3-none-any.whl` file into the local tree. A different example is the `git annex importfeed https://www.artemix.org/blog/feeds/all.xml`, documented as "Imports the contents of podcast feeds into the annex.". This effectively allows you to download a RSS feed into your tree. Note that [`git-annex-importfeed`](https://www.mankier.com/1/git-annex-importfeed) is made for podcasts, and has a wrapper around the `youtube-dl` tool if you wish to download youtube playlists too. Yes, this command is pretty sidetracked. ## `git-bundle`: Package a git repository, or part of it So let's say you're in an internet outage, but you *really* need to give your changes and part of your repository to a friend of yours. You cannot use usual means because of the internet outage, so you cannot use HTTP, SSH, or anything else like that. Thankfully, [the `git-bundle` command](https://www.mankier.com/1/git-bundle) is made to automatically create an archive of a branch or more, basically put part of a repository. To extract the branches from the archive, you simply use [the standard `clone` command](https://www.mankier.com/1/git-clone), using a local path instead of an URL. ``` $ git clone -b main ~/Downloads/mymain.bundle ./git/repository ``` This will grab the `main` branch from the bundle stored in the downloads folder, and insert it into the git repository at `./git/repository`. Note that it also allows you to verify said archives. ## `git-am`: E-mail based git contribution workflow Let's say you like to use e-mails to manage your git contributions, sharing patchsets and such through it. You could do so by hand, downloading the patchsets and applying them with [the `git apply` command](https://www.mankier.com/1/git-apply), but git provides a few cool utilities to manage your e-mail based workflow. One of said commands is [`git-am`](https://www.mankier.com/1/git-am), tasked with pulling git contributions from your mailbox, and parse / apply them right away. Additionally, it also allows to apply a patch / patchset file, using the simple command `git am ~/Downloads/contributions.patch`. ## `git-archive`: Archiving the tree at a given commit into a bundle If you want to grab the tree at a given commit, or head, but don't want to clone, duplicate, or checkout your currently used repository, you can easily extract everything you'd get if you checked out a reference, but instead of modifying your work tree, [the `git-archive` command](https://www.mankier.com/1/git-archive) will put everything in a tarball archive for you to move around or unpack. For example, let's say I wanna get the working tree from the first release of my project, so I can publish it. ``` $ git archive --format=tar.gz --prefix project v1.0.0 > project-1.0.0.tar.gz ``` Boom, now the unpacking will put everything from the version tagged by `v1.0.0` in a folder named `project`. But what if you just wanna check out the main branch from your project, to compare it with your currently checked out feature branch? You don't have to manually pack / unpack, thanks to the unix command chaining magic. ``` $ git archive --format=tar --prefix main project-main | (cd .. && tar xf -) ``` Now the project's main branch will be available in the `project-main` folder, alongside your project's feature folder. # Concepts Here, I will outline some concepts and features provided by git. The only difference between this section and the previous one is the fact that concepts here are mostly configuration-bound or environment-bound, and not based on git commands. ## Git namespaces What if you want to avoid replicating the same codebase 10 times, but submodules and libraries are too bothersome for your context? Well, git provides a way to group and separate your references by namespaces. The concept of [git namespacing](https://www.mankier.com/7/gitnamespaces) is to have a common repository (on which you will have everything, and on which you can run a single common `git gc` command, besides other maintenance operations), but which you can split into different names. A name is a group of branches, tags, and other kinds of references, which you can check out and consider as different repositories, as git has the ability to see them as different remotes. The biggest advantage is that it avoids duplication. ## Git hooks Automation is kewl. When you're working on projects, it's pretty cool to automate all kinds of tasks during your git workflow. For example, before allowing a commit to be done, you may wanna run your linter to make sure you're not committing non-style-compliant code. You could also want to run your unit tests before pushing your changes to your remote repository, to make sure you're not pushing broken content. Manually doing so is annoying, slow, and prone to error. Thankfully, git provides [the concept of hooks](https://www.mankier.com/5/githooks), which is basically a set of executables you can define to be automatically run on different git actions. Note that git will always ignore non-executable programs, so you can simply disable one by removing the `x` flag from it. There are lots of events you can use, around commits, remote interactions, e-mail interactions, and much more. # Setting up a simple web UI over a bare git repository As shown [in my previous article](https://www.artemix.org/blog/barebones-git), setting up a bare git repository is dead-easy and much faster and lighter than setting up an entire git-oriented web daemon (such as gitea or gitlab). Still, it can be nice to be able to browse your git repository through your browser, it's a very convenient feature. Thankfully, you can easily put and swap web UIs that sit on top of git repositories without having to deploy and setup 28 databases and daemons! There are a few pretty well-known interfaces: - The standard [`git-instaweb` interface](https://www.mankier.com/1/git-instaweb), which is usually natively bundled into git but requires a HTTP daemon to be installed, such as `lighttpd` - The well-known [C CGI `gitc` software](https://git.zx2c4.com/cgit/), which should already be packaged for your distribution of choice. You just need to have a server capable of handling CGI executables (most should) - The less-known, Apache-oriented, [perl gitweb CGI software](https://git.wiki.kernel.org/index.php/Gitweb), pretty much the same as `gitc` - The PHP/Bootstrap-based [`gitlist` project](https://github.com/klaussilveira/gitlist), which needs an entire web server on top, but can easily be hosted on cheap PHP managed hosting for this reason # As a wrap-up Now, I only showcased uncommon features I personally use a lot, but there is *much more* to cover; however, this won't be the topic of a third article. I still strongly invite you to at least check out the list of git manuals, [a quick search on mankier](https://www.mankier.com/?q=git-) will already help you discover a few ones, and I'm sure some will nicely integrate into your workflow.