Since I am still learning, sometimes when I'm using vim I just forget and edit / commit a file directly to main.
I don't like having to roll the change back and re-commit on a non-main git branch. I don't want to rebase or merge my main branch into development prematurely.
Is there something I can configure in my git client so it will stop me before I make a direct edit or commit to main? FYI, this is a occupational problem that may be foreign to some; in my job, git / vim / python are intimately woven together in this tapestry and I cannot expect everyone to get all the nuances of the relationships.
Is there something I can configure in my git client so it will stop me before I make a direct commit to main?
I am not sure about configuring a git client to do that; as one alternative you can wrap vim with a script such that it checks the git branch before editing.
I wrote a vim
wrapper in python to do the checks for you.
Save this and make it executable; /usr/bin/env
is native to Linux and WSL... I'm not sure about running it native to a Windows filesystem.
#!/usr/bin/env python
from subprocess import run
import locale
import shutil
import shlex
import sys
import os
class bcolors:
HEADER = '\033[95m'
OKBLUE = '\033[94m'
OKCYAN = '\033[96m'
OKGREEN = '\033[92m'
RED = '\033[91m'
RED_FLASH = '\033[5;37;91m'
RED_REVERSE = '\033[0;37;41m'
RED_FLASH_REVERSE = '\033[5;37;41m'
WARNING = '\033[93m'
ENDC = '\033[0m'
BOLD = '\033[1m'
UNDERLINE = '\033[4m'
class _GetchUnix:
def __call__(self):
import termios
import tty
import sys
fd = sys.stdin.fileno()
old_settings = termios.tcgetattr(fd)
try:
tty.setraw(sys.stdin.fileno())
ch = sys.stdin.read(1)
finally:
termios.tcsetattr(fd, termios.TCSADRAIN, old_settings)
return ch
class _GetchWindows:
def __init__(self):
pass
def __call__(self):
import msvcrt
return msvcrt.getch()
class Getchar:
"""Gets a single character from standard input. Does not echo to the screen."""
def __init__(self):
try:
import msvcrt
msvcrt.LK_LOCK
self.impl = _GetchWindows()
except ImportError:
self.impl = _GetchUnix()
def __call__(self):
return self.impl()
class cd:
"""Context manager for changing the current working directory"""
def __init__(self, newPath):
self.newPath = os.path.expanduser(newPath)
def __enter__(self):
self.savedPath = os.getcwd()
os.chdir(self.newPath)
def __exit__(self, etype, value, traceback):
os.chdir(self.savedPath)
getchar = Getchar()
def find_git_branch(directory):
"""cd into a directory and return the git branch that it's on"""
with cd(directory):
enc_str = locale.getpreferredencoding()
proc = run(shlex.split("git status"), capture_output=True)
try:
git_branch_list = proc.stdout.decode(enc_str).splitlines()[0].split()[2:]
git_branch = ' '.join(git_branch_list).strip()
except IndexError:
git_branch = ""
return git_branch
def check_git_edit(directory, vi_command):
"""if a file is on a git master branch, ask before editing it"""
# check the git branch of the directory...
git_branch = find_git_branch(directory)
if git_branch == "main" or git_branch == "master":
print(f"{bcolors.RED_FLASH_REVERSE}You are editing on git {git_branch}, are you sure? (Y/N){bcolors.ENDC}")
user_input = getchar()
if user_input.upper() == "Y":
# Run vim.basic which allows ~/.vimrc... vim.tiny does not!
run(shlex.split(vi_command))
else:
run(shlex.split(vi_command))
if __name__ == "__main__":
if shutil.which("vim") and not shutil.which("vim.basic"):
vim = "vim"
elif shutil.which("vim.basic"):
vim = "vim.basic"
else:
raise OSError("vim is not installed")
vi_command = f"{vim} {' '.join(sys.argv[1:])}"
filepath = os.path.expanduser(' '.join(sys.argv[1:]))
dir_part = os.path.split(filepath)[0]
if dir_part != "":
dirname = os.path.dirname(filepath)
check_git_edit(dirname, vi_command)
else:
check_git_edit(os.getcwd(), vi_command)