Skip to content

Instantly share code, notes, and snippets.

@joe42
Last active February 16, 2016 11:32
Show Gist options
  • Save joe42/984fb415942b67ddf70f to your computer and use it in GitHub Desktop.
Save joe42/984fb415942b67ddf70f to your computer and use it in GitHub Desktop.
Stash all modified files, not just their changes.
#!/usr/bin/python2.7
from git import Repo
import tempfile
import shutil
import sys
import os
import shelve
import errno
from os.path import join as joinpath
from os.path import dirname, basename
command = sys.argv[1]
stash_name = ""
if command != "list":
stash_name = sys.argv[2]
BACKUPDIR = os.path.expanduser("~/.git_modified_files")
def mkdir_p(path):
try:
os.makedirs(path)
except OSError as exc: # Python >2.5
if exc.errno == errno.EEXIST and os.path.isdir(path):
pass
else:
raise
def get_untracked(repo):
return repo.git.ls_files("--exclude-standard", "--others").splitlines()
def gitstash(command, stash_name):
repo = Repo(os.path.curdir)
backup_modified_files_dir = joinpath(BACKUPDIR, repo.git_dir[1:]))
session_dir = joinpath(backup_modified_files_dir, stash_name)
session_files_dir = joinpath(session_dir, "files")
session_files_dict = joinpath(session_dir,"files_dict")
mkdir_p(session_files_dir)
realpath_to_tmpfile_map = shelve.open(session_files_dict)
if command == "list":
for stash_name in os.listdir(backup_modified_files_dir):
if stash_name != "files" and stash_name != "files_dict":
print(stash_name)
exit(0)
if command == "drop":
shutil.rmtree(session_dir)
print("Dropped stash "+stash_name+".")
exit(0)
if command == "apply" or command == "pop":
# TODO: Do not overwrite files that are not yet under version control.
for (realpath, temppath) in realpath_to_tmpfile_map.items():
absolute_realpath = joinpath(repo.working_dir, realpath)
mkdir_p(dirname(absolute_realpath))
shutil.copy(temppath, absolute_realpath)
if command == "pop":
shutil.rmtree(session_dir)
print("Popped stash "+stash_name+".")
else:
print("Applied stash "+stash_name+".")
exit(0)
if command == "stash":
for untracked in get_untracked(repo):
tmpfile = tempfile.NamedTemporaryFile(dir=session_files_dir,prefix=basename(untracked)).name
realpath_to_tmpfile_map[untracked] = tmpfile
# print(untracked+" --> "+tmpfile)
shutil.move(joinpath(repo.working_dir, untracked), tmpfile)
for diff in repo.head.commit.diff(None):
if diff.deleted_file:
continue
tmpfile = tempfile.NamedTemporaryFile(dir=session_files_dir,prefix=diff.b_blob.name).name
realpath_to_tmpfile_map[diff.b_blob.path] = tmpfile
# print(diff.b_blob.path+" --> "+tmpfile)
shutil.copy(joinpath(repo.working_dir, diff.b_blob.path), tmpfile)
try:
repo.git.reset("--hard")
except Exception, e:
print(e)
realpath_to_tmpfile_map.sync()
realpath_to_tmpfile_map.close()
if __name__ == '__main__':
gitstash(command, stash_name)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment