Skip to content

Instantly share code, notes, and snippets.

@Ap0dexMe0
Last active April 1, 2025 07:47
Show Gist options
  • Select an option

  • Save Ap0dexMe0/33f435c4e501f8019d15b0fdbb360658 to your computer and use it in GitHub Desktop.

Select an option

Save Ap0dexMe0/33f435c4e501f8019d15b0fdbb360658 to your computer and use it in GitHub Desktop.
Git Manager CLI: stage modified/untracked files, commit and push with interactive selection and colored output.
#!/usr/bin/env python3
import os
import sys
import subprocess
COLORS = {
'blue': '\033[1;34m',
'green': '\033[1;32m',
'red': '\033[1;31m',
'purple': '\033[1;35m',
'cyan': '\033[0;36m',
'yellow': '\033[1;33m',
'bold': '\033[1m',
'reset': '\033[0m'
}
def color_text(text, color):
return f"{COLORS.get(color, '')}{text}{COLORS['reset']}"
def frame_title(title):
line = "═" * (len(title) + 3)
print(color_text(f"\n╔{line}╗", 'blue'))
print(color_text(f"║ {title} ║", 'blue'))
print(color_text(f"╚{line}╝\n", 'blue'))
def run_git_command(cmd):
try:
result = subprocess.run(['git'] + cmd,
check=True,
stdout=subprocess.PIPE,
stderr=subprocess.PIPE,
text=True)
return result.stdout.strip()
except subprocess.CalledProcessError as e:
print(color_text(f"\n❌ Git command failed: {' '.join(cmd)}", 'red'))
print(color_text(e.stderr.strip(), 'red'))
sys.exit(1)
def show_detailed_git_status():
frame_title("🔍 Git Status")
status_output = run_git_command(['status', '--short', '--branch'])
has_output = False
for line in status_output.splitlines():
if line.startswith('##'):
continue # Skip branch info
if line.startswith('??'):
print(f"🆕 {color_text('[untracked]', 'purple')} {line[3:]}")
has_output = True
elif line.startswith(' M'):
print(f"✏️ {color_text('[modified]', 'red')} {line[3:]}")
has_output = True
elif line.startswith('A ') or line.startswith('M '):
print(f"✅ {color_text('[staged]', 'green')} {line[3:]}")
has_output = True
if not has_output:
print(color_text("✅ Working directory clean.", 'green'))
print(color_text("─" * 60, 'blue'))
def select_files():
staged = run_git_command(['diff', '--name-only', '--cached']).splitlines()
unstaged = run_git_command(['diff', '--name-only']).splitlines()
untracked = run_git_command(['ls-files', '--others', '--exclude-standard']).splitlines()
staged_set = set(staged)
modified_files = [f for f in unstaged if f and f not in staged_set]
untracked_files = [f for f in untracked if f and f not in staged_set]
choices = []
for f in modified_files:
choices.append(('modified', f))
for f in untracked_files:
choices.append(('untracked', f))
if not choices:
print(color_text("⚠️ No unstaged or untracked files to select.", 'red'))
sys.exit(0)
frame_title("📁 Select Files to Stage")
for i, (status, file) in enumerate(choices, 1):
emoji = "✏️" if status == 'modified' else "🆕"
status_color = 'red' if status == 'modified' else 'purple'
print(f" {color_text(str(i).rjust(2), 'cyan')}. {emoji} {color_text(f'[{status}]', status_color)} {file}")
print()
print(color_text("Options:", 'yellow'))
print(f" {color_text('0', 'cyan')} - ➕ Stage all listed files")
print(f" {color_text('q', 'cyan')} - ❌ Quit without staging")
selections = input(color_text("\nYour selection ➜ ", 'yellow')).strip()
if selections.lower() == 'q':
print(color_text("❌ Aborted by user.", 'yellow'))
sys.exit(0)
selected_files = []
if selections == '0':
selected_files = [file for _, file in choices]
else:
try:
indices = list(map(int, selections.split()))
for index in indices:
if index < 1 or index > len(choices):
print(color_text(f"❌ Invalid selection: {index}", 'red'))
sys.exit(1)
selected_files.append(choices[index - 1][1])
except ValueError:
print(color_text("❌ Invalid input. Use numbers separated by spaces.", 'red'))
sys.exit(1)
print()
for file in selected_files:
run_git_command(['add', file])
print(color_text(f"✔️ Staged: {file}", 'green'))
print(color_text("─" * 60, 'blue'))
def main():
os.system('cls' if os.name == 'nt' else 'clear')
frame_title("🚀 Git Manager CLI")
show_detailed_git_status()
select_files()
print()
message = input(color_text("📝 Commit message (default: released): ", 'yellow')).strip()
if not message:
message = "released"
print()
print(color_text(f"📦 Committing: '{message}'", 'blue'))
run_git_command(['commit', '-m', message])
print(color_text("📤 Pushing to remote...", 'blue'))
run_git_command(['push'])
print(color_text("\n✅ All done! Your changes have been committed and pushed.", 'green'))
print(color_text("─" * 60, 'blue'))
if __name__ == "__main__":
main()
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment