0

I want to stop Git if it takes too long to run git status, but Git seems to be ignoring SIGTERMs: Why does timeout not interrupt `git status` when it takes too long?

So it seems that one way to get around this is to use SIGKILL, but that you may hit a bug and corrupt your repository if you send a SIGKILL: https://stackoverflow.com/a/63212737/11588505

git status is purely a query, though, so shouldn't it be perfectly safe to send a SIGKILL?

Camelid
  • 1,535
  • 8
  • 21
  • 2
    It should be. An `strace` on `git status` doesn't indicate any write operations to the filesystem. If all it does is read-only, then even an unhandled deadly signal won't corrupt anything. – Petr Skocik Aug 02 '20 at 18:32
  • 1
    @PSkocik: `git status` will *sometimes* write to the index file (to update it for certain cases to make *future* operations faster), but it should catch `SIGTERM` here. You can force `git status` *not* to update the index with `git --no-optional-locks status`. This is needed if you're running `git status` from a background process that might be running at the same time as some other Git operation. – torek Aug 02 '20 at 21:52
  • @torek Is there a general flag to force Git to be read-only? – Camelid Aug 02 '20 at 23:05
  • I just realized that I used the wrong word in my question. I meant SIGKILL, because for some reason `git status` seems to ignore SIGTERM: https://stackoverflow.com/a/63212737/11588505 – Camelid Aug 02 '20 at 23:07
  • @Camelid: The closest is `--no-optional-locks`, which avoids any locks not required to run. Note that if you use a command that has required locks, though, it still gets them (and then writes). And, it's not so much that Git *ignores* SIGTERM as that it *catches* it (and cleans up after itself, once it notices that it should stop, which takes a long time—probably `git status` should check more often than once-when-it's-done...). SIGKILL cannot be caught though. – torek Aug 02 '20 at 23:29

1 Answers1

1

Since SIGKILL cannot be caught and immediately terminates Git, this may leave behind various oddities or problems.

Git is designed to be reasonably resilient: for instance, instead of just writing out its index, it writes an updated index to a file named .git/index.lock, and then uses what's meant to be an atomic OS-level process to replace the old .git/index file with the new contents in .git/index.lock while calling the new file .git/index. This atomic operation is a rename system call: Git depends on the OS to implement it as an atomic operation, that either completely happens, or never starts.

Similar schemes are used to update references and other files, including loose objects and pack files. Not every file system on every OS obeys these rules, and if the OS itself crashes, you can get into various troublesome cases, but on the whole this works pretty well.

What happens if Git is killed, with the un-catch-able SIGKILL, during one of these critical sections is that the lock file remains left behind. A future Git invocation stops and tells you that there is a lock file and it cannot proceed. It then becomes your job to inspect the system as a whole, determine whether this is a stale lock, and hence whether it can be removed. If so, removing the stale lock and retrying the operation should recover.

When the OS itself crashes, Git may lose files that Git cannot operate without. Your best bet for this kind of problem is to have another repository somewhere else, preferably physically distant so that a common event (e.g., building catches fire and all the computers within it burn up or are ruined by fire suppression) does not damage the other Git repository. For less extreme cases, sometimes the repository is repairable in-place.

One of the most common failures is for the OS to completely delete the file named .git/HEAD, and with this file gone, Git no longer believes that the repository is a repository. Re-create the file (e.g., echo ref: refs/heads/master > .git/HEAD) and the repository is back. If your system obeys the POSIX file atomicity rules, this particular case cannot happen even for SIGKILL.

torek
  • 448,244
  • 59
  • 642
  • 775
  • So, if I use `git --no-optional-locks status`, then it should be fine? Or is there still a potential for corruption? – Camelid Aug 02 '20 at 23:53
  • Well, if another Git is running, the output from `git --no-optional-locks status` could be out of date by the time you get it—but it should be self-consistent. – torek Aug 02 '20 at 23:59
  • I just wanted to make sure that it won't corrupt the repo; I'm not too worried about accuracy – Camelid Aug 03 '20 at 00:12