-
-
Save VarunBarad/c291e98dd426b0da1322171290d7bbd0 to your computer and use it in GitHub Desktop.
#!/usr/bin/python3 | |
import os | |
import sys | |
import re | |
import shutil | |
from git import Repo | |
from zipfile import ZipFile | |
def create_backup_zip(directory_to_backup): | |
parent_directory, directory_name = os.path.split(directory_to_backup) | |
repository = Repo(directory_to_backup) | |
git_handle = repository.git | |
git_bundle_file_name = os.path.join(parent_directory, (directory_name + '.bundle')) | |
git_handle.bundle('create', git_bundle_file_name, '--all') | |
pattern_for_untracked_files_flag = re.compile(r'^\?+$') | |
non_staged_files_raw_output = git_handle.status('--porcelain') | |
if len(non_staged_files_raw_output.strip()) > 0: | |
non_staged_files = list(filter( | |
lambda x: pattern_for_untracked_files_flag.match(x[0]) is None, | |
list(map(lambda _: _.strip().split(), non_staged_files_raw_output.split(os.linesep))) | |
)) | |
else: | |
non_staged_files = [] | |
if len(non_staged_files) > 0: | |
git_handle.stash('push', '-m', 'git-backup-stash') | |
stashes = git_handle.stash('list').strip() | |
stash_list = stashes.split(os.linesep) | |
patch_files = [] | |
if (len(stashes) > 0) and (len(stash_list) > 0): | |
patch_files_directory = os.path.join(parent_directory, 'patch-files') | |
os.makedirs(patch_files_directory, exist_ok=True) | |
for stash in stash_list: | |
stash_name = stash.split(': ')[0] | |
stash_branch_name = stash.split(': ')[1].split()[1] | |
stash_message = ': '.join(stash.split(': ')[2:]) | |
patch_file_name = ':'.join([stash_name, stash_branch_name, stash_message]) + '.txt' | |
patch_file_path = os.path.join(patch_files_directory, patch_file_name) | |
patch_contents = git_handle.stash('show', '-p', stash_name) | |
with open(patch_file_path, 'x') as f: | |
f.write(patch_contents) | |
patch_files.append(patch_file_path) | |
zip_file_name = directory_name + '.zip' | |
zip_file_path = os.path.join(parent_directory, zip_file_name) | |
with ZipFile(zip_file_path, 'x') as z: | |
z.write(git_bundle_file_name, arcname=os.path.split(git_bundle_file_name)[1]) | |
for patch_file in patch_files: | |
z.write(patch_file, arcname=os.path.join('patch-files', os.path.split(patch_file)[1])) | |
os.remove(git_bundle_file_name) | |
if len(patch_files) > 0: | |
shutil.rmtree(patch_files_directory) | |
print(zip_file_name + ' created') | |
if __name__ == "__main__": | |
arguments = sys.argv[1:] | |
if len(arguments) == 0: | |
directory_to_backup = os.getcwd() | |
else: | |
directory_to_backup = arguments[0] | |
directory_to_backup = os.path.abspath(directory_to_backup) | |
git_directory = os.path.join(directory_to_backup, '.git') | |
if os.path.exists(git_directory) and os.path.isdir(git_directory): | |
create_backup_zip(directory_to_backup) | |
else: | |
print(directory_to_backup + ' is not a git repository') |
@flandersen I could not understand what you mean by "bare git repos". Can you please explain a bit more?
@VarunBarad I want to backup my repos on my server which are created the following:
git init --bare <directory>
The --bare flag creates a repository that doesn’t have a working directory, making it impossible to edit files and commit changes in that repository. You would create a bare repository to git push and git pull from, but never directly commit to it.
https://www.atlassian.com/git/tutorials/setting-up-a-repository/git-init
@flandersen I guess bare repos won't have any stashes. In that case all you need should be handled by git bundle
@VarunBarad Thank you! I have tested git-bundle and it works fine.
If you are interested, here is the script I came up with which fits my purpose:
https://gist.github.com/flandersen/6d33c609de80247c9059bf8c3e2ade05
Thanks @flandersen
I really liked how you have put the documentation at the top of the script in comments 💯
I want to backup my bare git repos and give it a try, but this script cannot handle those.