Knaģis
Knaģis

Reputation: 21485

How to tell if a git operation is in progress?

If operation like git pull are run at the same time as a background build in watch mode (in my case, webpack), it can often fail because of the compilation locking files that git wants to overwrite.

I would like to add script to pause the watcher while any git operation is currently modifying the working directory. This should be possible because git itself checks if there is not another git doing something at the same time.

Note that I am not interested if a merge is in progress etc., I am interested if git is currently actively writing files.

Upvotes: 3

Views: 1685

Answers (2)

Knaģis
Knaģis

Reputation: 21485

By using .git/index.lock as suggested by other answer, I ended up modifying my build script to both wait for this file to be removed and to create it on its own during the build so that git cannot be started during build as well.

Posting in case the JavaScript code proves useful to someone else as well.

const gitIndexLock = path.join(__dirname, "..", ".git", "index.lock");
let hasWrittenOwnGitIndexLock = false;
function lockParallelGitOperations(callback) {
    if (!fs.existsSync(gitIndexLock) || hasWrittenOwnGitIndexLock) {
        writeLockFile();
        callback();
        return;
    }

    console.log("Git operation in progress... Waiting...");
    const sleepStarted = Date.now();
    sleep();

    function sleep() {
        setTimeout(() => {
            if (fs.existsSync(gitIndexLock)) {
                if (Date.now() - sleepStarted > 30000) {
                    console.log("Git has been locked for over 30 seconds. Removing foreign lock...");
                    fs.unlinkSync(gitIndexLock);
                } else {
                    sleep();
                    return;
                }
            }

            writeLockFile();
            callback();
        }, 200);
    }

    function writeLockFile() {
        if (!hasWrittenOwnGitIndexLock) {
            console.log("Creating .git/index.lock.");
            fs.writeFileSync(gitIndexLock, "");
            hasWrittenOwnGitIndexLock = true;
        }
    }
}

Upvotes: 0

kabanus
kabanus

Reputation: 25895

I think it may be enough to check if

yourepo/.git/index.lock

exists, when it doesn't create it, run a bit, delete it, sleep a bit, and then repeat. I think this is expensive if the background program really constantly runs. It may also block you at times from working until sleeping.

A feasible option would be to wrap the git commands themselves. Purely in bash a function would do:

function mygit {
    pid=$(ps -eo pid,comm a | grep webpack)
    pid=${pid%% *}
    kill -TSTP $pid
    git $*
    kill -CONT $pid
}

Running mygit will suspend your process, run git, then let it continue. You can also change the way the git command itself behaves, if that's your preference, through the git hook mechanism, which you can fine tune to only affect stuff that only change the index, such as things to run pre (suspend) and post (resume) commit. A tutorial to initialize this can fe found in https://coderwall.com/p/jp7d5q/create-a-global-git-commit-hook - basically it's just scripts with specific names in a specified directory.

EDIT

After reviewing the comments below I want to add that the git-hook solution is completely feasible on Windows, since git comes with it's own bash on Windows. A tutorial on how to do this is https://tygertec.com/git-hooks-practical-uses-windows/ here, but make sure the scripts are all bash and anything above will work. The only caveat is finding and suspending the PID.

taskkill //PID <num>

will kill it, I'm not sure how to suspend though. Maybe on windows 10 with bash it the above will work.

Upvotes: 1

Related Questions