Tracking 1400+ client codes, multi-threading nightmare
First, I'm pretty sure that it's impossible for
os.chdir(path)

to meaningfully apply different working directories per thread; and even if it were possible it would be a bad idea. subprocess supports a cwd parameter directly that you should use.
If you were opening files yourself, you would want to make a semaphore where the lock only applies to the section of the code where the file is opened. However, you aren't opening the files - it's probably your invocation of git that opens the most files.
I think the only practical way around this is to just limit the number of concurrent threads. You could either estimate this ahead of time, or keep spinning up threads until you hit the first OSError and start no new threads, running one-out-one-in until your work pool is complete.
If you deeply care about performance, subprocess-ing out to git should be replaced with in-process computation; either calling into a library or manually processing entries in .git (I have not researched either).