Skip to content

Instantly share code, notes, and snippets.

@scambier
Created March 19, 2019 12:41
Show Gist options
  • Select an option

  • Save scambier/0c400a4fcd5f1f1bacc145c4c795ee32 to your computer and use it in GitHub Desktop.

Select an option

Save scambier/0c400a4fcd5f1f1bacc145c4c795ee32 to your computer and use it in GitHub Desktop.
Copy all changed files between two git commits. Respects the folders structure.
#! /usr/bin/python
# Usage: python pyGitDiff.py hash1 hash2
# Help: python pyGitDiff.py -h
import subprocess
import os
import shutil
from datetime import datetime
import argparse
ignoreList = [".gitignore"]
def main():
global ignoreList
descString = "\nThis script will create a folder with all modified files between two git commits.\n"
parser = argparse.ArgumentParser(description=descString)
parser.add_argument(
'first_hash',
help='the first commit\'s hash')
parser.add_argument(
'second_hash',
help='the 2nd commit\'s hash. Use HEAD for the latest commit')
parser.add_argument(
'-f', '--flat',
help='don\'t copy directories',
default=False,
required=False,
action='store_true')
parser.add_argument(
'-l', '--list',
help='copy nothing, only show list',
default=False,
required=False,
action='store_true')
parser.add_argument(
'-d', '--dest',
metavar="folder",
help='destination folder\'s name. If empty, a default name will be used',
default=False,
required=False)
parser.add_argument(
'-i', '--ignore',
metavar="filename",
help='files that you don\'t want to be copied (.gitignore will always be ignored)',
nargs='*',
required=False)
args = vars(parser.parse_args())
commit1, commit2 = args['first_hash'], args['second_hash']
if args['ignore'] is not None:
ignoreList += args['ignore']
# Get files list and split them in an array
p = subprocess.Popen(["git", "diff", "--name-only", commit1, commit2], stdout=subprocess.PIPE)
out, err = p.communicate()
files = out.split("\n")
# Remove the last empty line
files.pop(len(files) - 1)
if not args['dest']:
folderName = "DIFF"
folderName += datetime.now().strftime("_%Y-%m-%d_%Hh%M")
folderName += "_" + commit1 + "-" + commit2 + "/"
else:
folderName = args['dest'] + '/'
print ('\nList of modified files:\n')
for file in files:
print (file)
if not args['list']:
copyFile(file, folderName, args['flat'])
if not args['list']:
print('\nAll files are copied in folder "' + folderName + '"\n')
def copyFile(file, dest, flat):
global ignoreList
struct = file.split('/')
if len(struct) > 1:
filename = struct.pop(len(struct) - 1)
else:
# File in root
filename = file
struct = ['']
if filename in ignoreList:
print (" -> ignored!")
else:
if flat:
path = dest
else:
path = os.path.expanduser(dest + '/'.join(struct) + '/')
if not os.path.exists(path):
#Todo: make dir only if file exists
try:
with open(file) as f:
os.makedirs(path)
except IOError as e:
# file doesn't exist, we don't make the dir
pass
try:
shutil.copy(file, path + filename)
print (" -> copied")
except IOError as e:
print (" -> deleted file")
if __name__ == "__main__":
main()
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment