{
  pkgs,
  lib,
  config,
  ...
}:
let
  cfg = config.programs.git;
in
{
  config = lib.mkIf cfg.enable {
    home.packages = [
      pkgs.jjui
      pkgs.lazyjj
      (pkgs.writeShellApplication {
        name = "git-sync";
        text = (
          lib.strings.concatLines (
            map (r: ''
              echo "===== ${r.path}"
              if [ ! -d "${r.path}" ]
              then
                ${pkgs.git}/bin/git clone "${r.uri}" "${r.path}"
              else
                (
                  cd "${r.path}"
                  if [ -d .jj ]
                  then
                    ${lib.getExe config.programs.jujutsu.package} git fetch
                    ${lib.getExe config.programs.jujutsu.package} rebase -d main@origin
                    ${lib.getExe config.programs.jujutsu.package} bookmark set main -r @-
                    ${lib.getExe config.programs.jujutsu.package} git push
                  else
                    ${pkgs.git}/bin/git --no-optional-locks diff --quiet || echo "Repository is dirty!"
                    ${pkgs.git}/bin/git pull || true
                    # Only push if there's something to push. Also prevents from trying to push on repos where we don't have rights.
                    (${pkgs.git}/bin/git --no-optional-locks status --porcelain -b --ignore-submodules | grep ' \[ahead [0-9]\+\]' && ${pkgs.git}/bin/git push) || true
                  fi
                )
              fi
            '') (lib.attrsets.attrValues config.services.git-sync.repositories)
          )
        );
      })
    ];
    programs = {
      git = {
        package = pkgs.gitFull;
        aliases = {
          "git" = "!exec git"; # In case I write one too many git
        };
        ignores = [
          "*.swp"
          "*.swo"
          "*.ycm_extra_conf.py"
          "tags"
          ".mypy_cache"
        ];
        delta = {
          enable = true;
          options = {
            line-numbers = true;
            syntax-theme = "base16";
          };
        };
        # Also tried difftastic, and while I like the default theme it's a bit
        # less configurable
        lfs.enable = true;
        userEmail = lib.mkDefault "geoffrey@frogeye.fr";
        userName = lib.mkDefault "Geoffrey Frogeye";
        extraConfig =
          {
            core = {
              editor = "nvim";
            };
            push = {
              default = "matching";
            };
            pull = {
              ff = "only";
            };
          }
          // lib.optionalAttrs config.frogeye.desktop.xorg {
            diff.tool = "meld";
            difftool.prompt = false;
            "difftool \"meld\"".cmd = "${pkgs.meld}/bin/meld \"$LOCAL\" \"$REMOTE\"";
            # This escapes quotes, which isn't the case in the original, hoping this isn't an issue.
          };
      };
      jujutsu = {
        enable = true;
        # Current version doesn't have the "none" signing backend
        settings = {
          git = {
            auto-local-bookmark = true;
            auto-local-branch = true;
          };
          user = {
            email = cfg.userEmail;
            name = cfg.userName;
          };
          ui = {
            pager = "delta";
            diff.format = "git";
            diff-editor = "meld-3";
            merge-editor = "meld";
          };
          signing = lib.mkIf (!builtins.isNull cfg.signing) {
            sign-all = true;
            backend = "gpg";
            inherit (cfg.signing) key;
            backends.gpg.allow-expired-keys = false;
          };
        };
      };
    };
    services = {
      git-sync = {
        enable = false; # The real thing syncs too quickly and asks for passphrase, which is annoying
        # So for now it's just a way to park config which will be reused by git-sync-* commands
        repositories = {
          dotfiles = {
            path = "${config.xdg.configHome}/dotfiles";
            uri = lib.mkDefault "https://git.frogeye.fr/geoffrey/dotfiles.git";
          };
        };
      };
    };
  };
}