Setting up `git maintenance register` on NixOS

Trying to set up an equivalent to git maintenance register on NixOS (since running that imperative command literally would generate a service file with hardcoded paths, thereby breaking on every time those paths are invalidated).

This is my attempt, adapted from the service file that git itself would generate:
(Ignore the details of mapListToAttrs, it should be unrelated to the issue at hand.)

  systemd.user = {
    services."git-maintenance@" = {
      description = "Optimize Git repositories data";
      serviceConfig = {
        ExecStart = ''"${getExe config.programs.git.package}" --exec-path="${getBin config.programs.git.package}/bin" for-each-repo --keep-going --config=maintenance.repo maintenance run --schedule=%i'';
      };
    };
    timers =
      mapListToAttrs (OnCalendar: "git-maintenance@${OnCalendar}")
        (OnCalendar: {
          description = "Optimize Git repositories data";
          timerConfig = {
            inherit OnCalendar;
            Persistent = true;
          };
        })
        [
          "hourly"
          "daily"
          "weekly"
        ];
  };

And I have, in my ~/.config/git/config:

[maintenance]
    repo = "/path/to/repo1"
    repo = "/path/to/repo2"
    strategy = "incremental"

However, when I attempt to run (or let the system automatically run) one of the services, e.g. git-maintenance@hourly:

$ systemctl --user status git-maintenance@hourly
× git-maintenance@hourly.service - Optimize Git repositories data
     Loaded: loaded (/etc/systemd/user/git-maintenance@.service; static)
     Active: failed (Result: exit-code) since TIMESTAMP; 1s ago
   Duration: 882ms
 Invocation: ff155269ee424b5a85c69490c8dea89e
TriggeredBy: ● git-maintenance@hourly.timer
    Process: 784921 ExecStart=/nix/store/pxpns5vm111i6j3r3wbygaj99wbrm6h1-git-2.47.0/bin/git for-each-repo --keep-going --config=maintenance.repo maintenance run --schedule=hourly (code=exited, status=1/FAILURE)
   Main PID: 784921 (code=exited, status=1/FAILURE)
   Mem peak: 7.2M
        CPU: 100ms

TIMESTAMP HOST systemd[1731]: Started Optimize Git repositories data.
TIMESTAMP HOST git[784929]: error: failed to prefetch remotes
TIMESTAMP HOST git[784929]: error: task 'prefetch' failed
TIMESTAMP HOST systemd[1731]: git-maintenance@hourly.service: Main process exited, code=exited, status=1/FAILURE
TIMESTAMP HOST systemd[1731]: git-maintenance@hourly.service: Failed with result 'exit-code'.

Meanwhile running the command manually works fine:

$ git for-each-repo --keep-going --config=maintenance.repo maintenance run --schedule=hourly

$ echo $?                                    
0

How do I get this command to work correctly in a systemd service?

You’ll have to figure out why it fails to prefetch.

My first guess given that operation failing would be networking but it should be in the root networking namespace and therefore function as well as when its ran outside of a systemd service.

I’d try to do basic debugging; whether you are able to curl some internet website, read the relevant git config sections and show the HEAD of some repo on disk from within your systemd service.

If all of that works, you’ll have to strace -f git in your systemd service to see what’s going wrong.

After throwing in

      environment = {
        GIT_TRACE = "2";
        GIT_CURL_VERBOSE = "2";
        GIT_TRACE_PERFORMANCE = "2";
        GIT_TRACE_PACK_ACCESS = "2";
        GIT_TRACE_PACKET = "2";
        GIT_TRACE_PACKFILE = "2";
        GIT_TRACE_SETUP = "2";
        GIT_TRACE_SHALLOW = "2";
      };

into the service config, still saw no new errors. But for some reason it’s trying to run git-upload-pack even though I’m just fetching.

TIMESTAMP HOST git[1098899]: 12:48:23.822746 git.c:479               trace: built-in: git fetch origin --prefetch --prune --no-tags --no-write-fetch-head --recurse-submodules=no --quiet
TIMESTAMP HOST git[1098899]: 12:48:23.823039 run-command.c:666       trace: run_command: unset GIT_PREFIX; GIT_PROTOCOL=version=2 ssh -o SendEnv=GIT_PROTOCOL git@github.com 'git-upload-pack '\''NixOS/nixpkgs.git'\'''
TIMESTAMP HOST git[1098899]: error: cannot run ssh: No such file or directory
TIMESTAMP HOST git[1098899]: fatal: unable to fork
TIMESTAMP HOST git[1098899]: 12:48:23.823166 trace.c:416             performance: 0.000590476 s: git command: /nix/store/1zgzrsbq3b0f06k76pha0r8hmfwvjvc0-git-2.47.0/libexec/git-core/git fetch origin --prefetch --prune --no-tags --no-write-fetch-head --recurse-submodules=no --quiet
TIMESTAMP HOST git[1098898]: error: failed to prefetch remotes
TIMESTAMP HOST git[1098898]: error: task 'prefetch' failed

but git is able to connect to the repos just fine later on.
No idea why it’s trying to run git-upload-pack on all SSH remotes, nor why it can’t find said command. I decided to just prefetch repos that use HTTPS and it appears to work now :person_shrugging: but that does mean I can’t prefetch the repo I actually cared about, since I couldn’t figure out how to get git to see itself (!)

NVM it was much simpler, just needed ssh on path for the service.

  systemd.user.services."git-maintenance@".path = [ config.programs.ssh.package ];

After further roadblocks involving permissions and whatnot, I’ve decided to abandon the idea that I can fetch from an ssh remote in a systemd service.