Uh oh!
There was an error while loading.Please reload this page.
- Notifications
You must be signed in to change notification settings - Fork938

Description
I am trying to use GitPython for some repo manipulation, but ran into issues with my app, with handles open where i wouldn't expect.
Bug-jarring the issue, it seems that callingrepo.index.commit()
results in a several (4, consistently) git.exe processes being spawned, each holding a handle to the repo's root directorynewRepo
. When the test below goes to delete this TempDir, the processes are still up, causing a failure on context-manager__exit__()
. My app occasionally needs to do a similar cleanup, so hits the same issue.
On the one hand, it looks like there is no contect-manager capable repo-wrapper, meaning it makes sense ifsome resources is open, it will not typically be cleaned/GC'd before the tempdir__exit__()
. On the other hand - ifRepo
is going to behave like that, it really should not persist resources that have such side-effects.
Here is a working unittest:
import unittestimport gitimport tempfileimport os.pathclass Test(unittest.TestCase): def testCreateRepo(self): with tempfile.TemporaryDirectory(prefix=(__loader__.name) + "_") as mydir: # MAKE NEW REPO repo = git.Repo.init(path=os.path.join(mydir, "newRepo"), mkdir=True) self.assertTrue(os.path.isdir(os.path.join(repo.working_dir, ".git")), "Failed to make new repo?") # MAKE FILE, COMMIT REPO testFileName = "testFile.txt" open(os.path.join(repo.working_dir, testFileName) , "w").close() repo.index.add([testFileName]) self.assertTrue(repo.is_dirty()) #### # COMMENTING THIS OUT --> TEST PASSES repo.index.commit("added initial test file") self.assertFalse(repo.is_dirty()) #### # adding this does not affect the handle git.cmd.Git.clear_cache() print("done") # exception thrown right after this, on __exit__ # i can also os.walk(topdown=False) and delete all files and dirs (including .git/) # it is just the newRepo/ folder itself who's handle is held open if __name__ == '__main__': unittest.main()
PermissionError: [WinError 32] The process cannot access the file because it is being used by another process: 'C:\Users\%USER%\AppData\Local\Temp\EXAMPLE_gitpython_v3kbrly_\newRepo'
digging a little deeper, it seems that gitPython spawns multiple instances of git.exe processes, and each of them holds a handle to theroot folder of the reponewRepo
.
- set a breakpoint immediately before the error, use sysinternals/handle to see open handles to
newRepo
... git.exe (4 separate PID's of git.exe to be precise) - using sysinternals/procexp i can see that that they are all spawned from the python instance
-- I'm typically running this from PyDev, but i verified the issue reproduces under vanila command line invocation of python.exe as well - the exception indicates it's a handle to
newRepo
being held. Adding a little extra code to the above I think that is the only handle held. I am able to successfully os.remove/os.rmdir()every dir and file, including all of .git/; and i finally manually recreate the issue seen onexit() in my example when ios.rmdir(newRepo)
stepping through, it's the call to repo.index.commit() that actually leads to the the git.exe(s) being spawned.