How to Mock Git Stash and Pop in Python
Mock Git stash, apply, and pop operations using unittest.mock so you can test Git automation without touching a real repository.
pip install GitPython
Python code
28 linesimport git
from unittest.mock import Mock, patch
def stash_and_pop(repo):
"""Mock a stash operation and then pop it back."""
repo.git.stash("save", "WIP: temp changes")
stashed_output = repo.git.stash("list")
# Simulate the stash was applied, then pop
repo.git.stash("apply", "stash@{0}")
repo.git.stash("pop", "stash@{0}")
return stashed_output
if __name__ == "__main__":
# Create a fake repo with mocked git command
fake_repo = Mock()
fake_repo.git.stash.side_effect = ["Saved working directory", "stash@{0}: On main: WIP: temp changes", "Applied", "Dropped"]
# Patch a real Repo object to return the fake
with patch("git.Repo", return_value=fake_repo):
repo = git.Repo("/fake/path")
result = stash_and_pop(repo)
print("Stash operation result:", result)
# Verify the sequence of calls
print("Calls made:", [str(call) for call in fake_repo.git.stash.call_args_list])
Output
Stash operation result: stash@{0}: On main: WIP: temp changes
Calls made: [call('save', 'WIP: temp changes'), call('list'), call('apply', 'stash@{0}'), call('pop', 'stash@{0}')]
How it works
The Mock() object replaces a real GitPython Repo instance, and side_effect queues up fake return values for successive stash calls. Patching git.Repo with patch() makes git.Repo('/fake/path') return the mock, so stash_and_pop runs against a controlled fake. The function invokes stash save, stash list, stash apply, and stash pop in sequence; the mock records each call so you can assert the exact Git commands issued. This pattern isolates your Git logic from the filesystem, making tests fast, deterministic, and safe.
Common mistakes
- Calling `repo.git.stash` without mocking, which raises `GitCommandNotFound` or touches real repos.
- Forgetting `side_effect` must supply one value per call — too few values raises `StopIteration`.
- Using `return_value` instead of `side_effect` so every call returns the same string, hiding call order.
- Patching `git.Repo` globally instead of using a context manager, leaking the mock into other tests.
Variations
- Use `patch.object(repo, 'git')` and set `repo.git.stash.side_effect` directly for finer control.
- Capture calls with `fake_repo.git.stash.assert_has_calls([...])` to verify exact call order.
Real-world use cases
- Unit-testing a script that auto-stashes uncommitted work before pulling in a CI job.
- Validating a tool that applies then pops a stash after generating code changes, without polluting the repo.
- Simulating stash recovery logic in a Git maintenance script so edge cases are covered offline.
Sponsored
More from Git + Python
- Amend Last Commit Message in Python easy
- Bisect Good Bad Automation Script in Python easy
- Build a Simple Log Graph in Python easy
- Bump Semantic Version Git Tag in Python easy
- Count Unique Contributors from Git Shortlog in Python easy
- Create a Mock GitHub Release API in Python for Testing gh CLI easy
Keep learning
Related tutorials and quizzes for this topic.