Version Control Systems

1. VCS   vc

ID: 36ccc6c1-1b2d-4a48-8c1c-714a43873407
CREATED: <2025-02-06 Thu 18:40>

[2025-02-06 Thu 18:40] Version control - Wikipedia

1.1. Git   git

ID: 442c8fbb-b09d-4f85-a068-2a0f6a2de430
CREATED: <2025-02-09 Sun 13:32>

[2025-02-14 Fri 21:20] Git [2025-02-14 Fri 21:20] Git Submodules

1.2. Mercurial   hg

ID: be8e9117-4d72-40ea-a062-8029a3342248
CREATED: <2025-02-09 Sun 13:32>

[2025-02-14 Fri 21:21] Mercurial SCM

Mercurial is a free, distributed source control management tool. It efficiently handles projects of any size and offers an easy and intuitive interface.

  • guide
  • mozilla tools
  • dealing with corruption
  • Why Mercurial? Git and Mercurial are two different tools with the same job, it has just been my experience that Mercurial does them a little bit better for my workflow, and I am able to build things faster using it.
    • Mercurial is designed to provide tools for building a DVCS, and encourages you to expand your knowledge about the system to reap the benefits it provides. With Git I found myself often avoiding the implementation details in favor of quick-fixes and ugly scripts. On the other hand, I feel much more comfortable designing a solution with the tools Mercurial provides.
    • the Mercurial system has features such as immutable commits and branches, which can be quite dangerous. There are ways to 'fix' changes made by these commands, but they go against the grain of the rest of the system. Git on the other hand lets you seamlessly edit commits and close branches, which can be life-savers when Billy the Intern commits to master.
    • Mercurial also has superior features for exporting native repository to different DVCS (Git, Darcs, SVN), making it more useful in scenarios where a repo needs to be shared with users or tools that are unfamiliar with the 'hg' command.
    • Overall, the choice is a personal one. Over time I have felt less constrained, as if there were less rules to follow with Mercurial. This is a far-cry from my first experience with it, where I felt the complete opposite.

1.2.1. Git Interop

ID: 879abc56-8968-43cc-8bee-76118b398eaf
CREATED: <2025-02-16 Sun 20:24>

It is quite easy to integrate this process with CI:

# >> make mirror
# root path
ROOT=$(dir $(abspath $(firstword $(MAKEFILE_LIST))))
# this is wherever you pulled hg-fast-export to
STASH=~/stash
# path to hg-fast-export binary
FE=$(STASH)/fast-export/hg-fast-export.sh
mirror:$(FE) $(ROOT) out
mkdir -p out/$@;
git init out/$@;
cd out/$@ && \
git config core.ignoreCase false && git config push.followTags true && \
# run with '-M default' for default branch
$(FE) -r $(ROOT) -M default && git checkout HEAD && \
git remote add gh git@github.com:richardwesthaver/mpk.git && \
git push gh --all;
@rm -rf out/$@;
  • Two different plugins - git and hggit, different features
    • 'git' usage will treat a cloned repo as a git repo and just pull branch heads into mercurial (.git directory and .hg directory present at root)
    • 'hggit' will convert all changesets, branches, etc (.hg directory only)
      • pulling changesets can be incredibly slow at times
      • unlike vanilla hg, pulling from a git repo with hggit does NOT support revision CLI flag ('-r 100' will not work), so the standard method of doing an incremental pull is not possible
      • expect unexpected behaviors. always have backups.
    • hggit will often pull the 'github-pages' branch from repos using GitHub Sites and treat it as the default branch in the resulting clone. To make the repo usable you need to update to the 'master' bookmark, and use that as default

1.2.2. Bundles

ID: 11bb8531-a936-4b77-a29e-1e2d35436836
CREATED: <2025-02-16 Sun 20:26>

Hg Bundles are a more powerful version of git bundles and come in two flavors: Clonebundles and Pullbundles. They share a common format, support the bundle and unbundle commands, but are also used to provision their own commands: hg clone and hg pull respectively. Bundles are advertised via manifest files located in the .hg directory of a repo, and support a variety of compression backends via the BUNDLESPEC value specified in manifest.

  • Bundlespec
    • none-v2
    • gzip-v2
    • zstd-v2
    • stream-v2
  • Manifests
    • clonebundles.manifest
    • pullbundles.manifest
    • manifest.json

1.2.3. Web Hosting

ID: b750a5f3-f12c-439a-a730-1dcea8951d43
CREATED: <2025-02-16 Sun 20:27>

Hosting with vanilla Mercurial is quite similar to vanilla Git. hg serve is basically the equivalent to git instaweb. Where they differ is in the out-of-box solutions - Git has cgit, GitLab, Gitolite, git.sr.ht, etc. Mercurial has hg.sr.ht, and just recently Heptapod, which is not production-ready.

My experience with self-hosting the sr.ht eco-system was far from a good one due to conflicting dependencies, package manager incompatibility, and some classic PHP craziness. The Heptapod docker container took eons just to build tests, so I just gave up on that for now but will be on the look out for new developments with that project. So what we're really left with is the built-in tools. Lucky for us, we have the hgweb scripts at our disposal.

Here's the relevant docs covering all topics in this section. They are all must-reads if you plan on exposing a Mercurial server to the public.

  • PublishingRepositories - Mercurial
  • SecuringRepositories - Mercurial
  • AuthorizingUsers - Mercurial
  • hgweb + wsgi + nginx
    The hgweb script is used for deployment of the server via CGI or WSGI. The WSGI setup is a bit more involved, but according to the docs:

    (!) Much better performance can be achieved by using WSGI instead of CGI.

    This section covers the WSGI (pronounced whis-gee) setup, specifically for Nginx. The docs have better examples for Apache servers, so you do need to go off the beaten path to find just the right values to set in Nginx. The following setup worked for https://hg.rwest.io running Arch Linux.

    • dependencies
      • uwsgi and uwsgi-plugin-python are required for the hgweb.wsgi script.
      • nginx is used here, but…
      • apache package is needed if you want to use htpasswd while setting up HTTP Authentication. SSH auth only or public hosts don't need this.
    • /etc/uwsgi/hgweb.ini
      This is a UWSGI service configuration file - the hgweb.wsgi script needs to be located in the directory specified by chdir. If you are using systemd, try enabling the service with systemctl enable uwsgi@hgweb.service, and check the logs for any errors. The service calls the hgweb.wsgi script, which serves all repos configured via hgweb.conf.

      [uwsgi]
      master = true
      ; max-requests = 1000
      ; logto = {log file path}/hgweb-uwsgi.log
      uid = hgweb ; set process owner
      gid = hgweb
      stats = /run/uwsgi/stats.sock
      chmod-socket = 666
      cap = setgid,setuid
      ; https://www.mercurial-scm.org/wiki/PublishRepositoriesOnNginx
      plugins = python
      socket = /run/uwsgi/hgweb.sock
      chdir = /home/hgweb/hg
      wsgi-file = hgweb.wsgi
      ; https://stackoverflow.com/questions/15878176/uwsgi-invalid-request-block-size
      ; http://uwsgi-docs.readthedocs.io/en/latest/ThingsToKnow.html
      ; buffer-size = 65535
      
    • hgweb.wsgi
      The config path must be a byte string, and an absolute path. This script needs to be in the same directory as hgweb.conf.

      #!/usr/bin/env python3
      config = b"/home/hgweb/hgweb.conf"
      # Uncomment to send python tracebacks to the browser if an error occurs:
      #import cgitb; cgitb.enable()
      # enable demandloading to reduce startup time
      from mercurial import demandimport; demandimport.enable()
      from mercurial.hgweb import hgweb
      application = hgweb(config)
      
    • hgweb.conf
      Mercurial web server configuration file. Setting staticurl to /static allows us to pass serving of static content to Nginx, which is faster and has better caching controls.

      [web]
      encoding = UTF-8
      baseurl = https://hg.rwest.io
      contact = some_dude
      templates = theme
      style = spartan
      logourl = https://rwest.io
      staticurl = /static
      descend = True
      collapse = True
      [paths]
      / = src/*
      
    • /etc/nginx/sites-enabled/hg.conf
      Note that none of the extra uwsgi params from mercurial docs are used here, only the default uwsgi_params files provided by Nginx.

        server {
          server_name hg.rwest.io;
          listen 443 ssl;
          ssl_certificate fullchain.pem;
          ssl_certificate_key privkey.pem;
          ssl_protocols TLSv1.1 TLSv1.2 TLSv1.3;
          ssl_ciphers HIGH:!aNULL:!MD5;
          root /home/hgweb/hg;
          location / {
            limit_except GET HEAD {
              auth_basic "Mercurial userspace";
              auth_basic_user_file /home/hgweb/hg/hg.htpasswd;
            }
          include uwsgi_params;
          uwsgi_pass unix:/run/uwsgi/hgweb.sock;    
        }
      
        location /static {
          alias /home/hgweb/hg/static;
          expires 30d;
        }
      }
      

1.2.4. Extensions

ID: a62a2e17-8167-4812-b5ec-f4f9ef698f56
CREATED: <2025-02-14 Fri 21:21>

[2025-02-14 Fri 21:21] Using Mercurial Extensions

  1. Evolve
    ID: f8829131-67eb-4d4d-a101-28f08eced9ae
    CREATED: <2025-02-14 Fri 21:21>
    

    [2025-02-14 Fri 21:22] Evolve Extension [2025-02-14 Fri 21:22] Changeset Evolution