Search code examples
gittimeoutsigtermsigkill

Is it safe to send a SIGKILL to `git status`?


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?


Solution

  • 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.