Skip to content

Instantly share code, notes, and snippets.

@mnieber
Last active May 10, 2022 06:44
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save mnieber/774e868e96d3cdb16eeec3c1982abb19 to your computer and use it in GitHub Desktop.
Save mnieber/774e868e96d3cdb16eeec3c1982abb19 to your computer and use it in GitHub Desktop.
#!/usr/bin/env python
# -*- coding: utf-8 -*-
# The purpose of this script is to use a "local" git-directory alongside
# a "main" git working directory, and keep the two in sync. The "local" directory
# is used for storing local files that are associated with the "main" files but cannot
# be stored in the "main" directory (for example, local editor config files).
#
# Synopsis:
#
# // Create local directory with a file. This creates a .git-local.json file in the
# // main directory.
# git local init
# touch .git-local/my-editor.config
# git local save
#
# // Commit the .git-local.json file to the main directory.
# git add .git-local.json
# git commit -m "Add .git-local.json"
#
# // Switch to a different branch in the main directory, and change the local files
# // to suit the needs for working with that branch
# git checkout -b experimental-branch
# echo "split-window=1" >> .git-local/my-editor.config
# git local save // This step updates .git-local.json in the main directory
# git add .git-local.json
# git commit -m "Update .git-local.json"
#
# // Switch back to the main branch
# git checkout main
#
# // Update the local files to reflect that we are now on the main branch.
# // Do this step whenever you switch between "main" and "experimental"
# git local load
#
#
# Note: place this script on the path, so git can find it,
# and make it executable (chmod +x git-fixdown).
#
# Author: Maarten Nieber
# Url: https://gist.github.com/mnieber/774e868e96d3cdb16eeec3c1982abb19
#
import argparse
import json
import os
import subprocess
import sys
def git(*args, cwd="."):
pipes = subprocess.Popen(
["git"] + list(args), stdout=subprocess.PIPE, stderr=subprocess.PIPE, cwd=cwd
)
std_out, std_err = pipes.communicate()
if pipes.returncode != 0:
print(std_out)
print(std_err.strip())
sys.exit(pipes.returncode)
result = std_out.decode("utf-8")
if result.endswith("\n"):
result = result[:-1]
return result
def load_json(fn):
with open(fn, "r") as f:
return json.load(f)
def save_json(data, fn):
with open(fn, "w") as f:
json.dump(data, f)
def add_line_to_file(fn, line):
with open(fn, "a") as f:
f.write(line + "\n")
if __name__ == "__main__":
parser = argparse.ArgumentParser()
parser.add_argument("command", choices=["init", "save", "load"])
args = parser.parse_args()
user_name = git("config", "user.name")
main_repo_dir = git("rev-parse", "--show-toplevel")
main_repo_sha = git("rev-parse", "HEAD")
branch_name = git("rev-parse", "--abbrev-ref", "HEAD")
local_dir = os.path.join(main_repo_dir, ".git-local")
local_gitignore_file = os.path.join(local_dir, ".gitignore")
local_git_dir = os.path.join(local_dir, ".git")
local_files_json_fn = os.path.join(main_repo_dir, ".git-local.json")
lut = load_json(local_files_json_fn) if os.path.exists(local_files_json_fn) else {}
if args.command == "init":
os.makedirs(local_dir)
if not os.path.exists(local_git_dir):
git("init", cwd=local_dir)
add_line_to_file(local_gitignore_file, f"")
if args.command in ("save", "init"):
if git("status", "--porcelain", cwd=local_dir):
git("add", "-A", cwd=local_dir)
git("commit", "-m", f"{branch_name}: Save local files", cwd=local_dir)
local_files_sha = git("rev-parse", "HEAD", cwd=local_dir)
if lut[user_name] != local_files_sha:
lut[user_name] = local_files_sha
save_json(lut, local_files_json_fn)
print("M .git-local.json")
if args.command == "load":
if git("status", "--porcelain", cwd=local_dir) and not args.force:
print("Local files are not clean. Please commit or stash them first.")
sys.exit(1)
local_files_sha = lut.get(user_name)
if not local_files_sha:
print(f"No local files found for user {user_name}")
sys.exit(1)
git("revert", "--no-commit", f"{local_files_sha}..HEAD", cwd=local_dir)
git("commit", "-m", f"{branch_name}: Load local files", cwd=local_dir)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment