A couple fixes to git management for pass.

This commit is contained in:
Storm Dragon
2025-12-09 07:05:51 -05:00
parent 390b31d2c5
commit 3fb76772ab

View File

@@ -171,7 +171,10 @@ class PassManager(Gtk.Window):
r'^git@[\w\.-]+:[\w\-/\.]+$', # git@host:path/repo
r'^https?://[\w\.-]+/[\w\-/\.]+\.git$', # https://host/path/repo.git
r'^https?://[\w\.-]+/[\w\-/\.]+$', # https://host/path/repo
r'^https?://[\w\.-]+:\d+/[\w\-/\.]+\.git$', # https://host:port/path/repo.git
r'^https?://[\w\.-]+:\d+/[\w\-/\.]+$', # https://host:port/path/repo
r'^ssh://[\w@\.-]+/[\w\-/\.~]+$', # ssh://user@host/path
r'^ssh://[\w@\.-]+:\d+/[\w\-/\.~]+$', # ssh://user@host:port/path
r'^[\w]+@[\w\.-]+:[\w\-/\.~]+$', # user@host:path
]
@@ -199,18 +202,18 @@ class PassManager(Gtk.Window):
# Git sync info banner (only show if git is not initialized)
if not self.isGitRepo:
infoBanner = Gtk.InfoBar()
infoBanner.set_message_type(Gtk.MessageType.INFO)
contentArea = infoBanner.get_content_area()
self.infoBanner = Gtk.InfoBar()
self.infoBanner.set_message_type(Gtk.MessageType.INFO)
contentArea = self.infoBanner.get_content_area()
infoLabel = Gtk.Label(label="Git sync is not enabled. Passwords are stored locally only.")
contentArea.pack_start(infoLabel, False, False, 0)
setupButton = Gtk.Button(label="Set Up Git Sync")
setupButton.connect("clicked", self.on_setup_git_sync_clicked)
infoBanner.add_action_widget(setupButton, Gtk.ResponseType.NONE)
self.infoBanner.add_action_widget(setupButton, Gtk.ResponseType.NONE)
browseBox.pack_start(infoBanner, False, False, 0)
browseBox.pack_start(self.infoBanner, False, False, 0)
# Search box
searchBox = Gtk.Box(orientation=Gtk.Orientation.HORIZONTAL, spacing=5)
@@ -961,7 +964,7 @@ class PassManager(Gtk.Window):
# Fetch to get latest remote status (quietly)
subprocess.run(
['git', '-C', passwordStoreDir, 'fetch'],
capture_output=True,
stdout=subprocess.DEVNULL,
stderr=subprocess.DEVNULL
)
@@ -1258,12 +1261,51 @@ class PassManager(Gtk.Window):
def on_git_push_clicked(self, button):
"""Handle git push button"""
result = subprocess.run(
['pass', 'git', 'push'],
capture_output=True,
text=True
passwordStoreDir = str(Path.home() / '.password-store')
# Check if there are any commits
hasCommits = subprocess.run(
['git', '-C', passwordStoreDir, 'rev-parse', 'HEAD'],
stdout=subprocess.DEVNULL,
stderr=subprocess.DEVNULL
).returncode == 0
if not hasCommits:
self.show_error(
"No commits to push yet.\n\n"
"Add some passwords first, then they will be automatically committed and you can push."
)
return
# Check if upstream is set
upstreamResult = subprocess.run(
['git', '-C', passwordStoreDir, 'rev-parse', '--abbrev-ref', '@{u}'],
stdout=subprocess.DEVNULL,
stderr=subprocess.DEVNULL
)
if upstreamResult.returncode != 0:
# No upstream set - need to set it with -u
branchResult = subprocess.run(
['git', '-C', passwordStoreDir, 'branch', '--show-current'],
capture_output=True,
text=True
)
currentBranch = branchResult.stdout.strip() if branchResult.returncode == 0 else 'master'
result = subprocess.run(
['pass', 'git', 'push', '-u', 'origin', currentBranch],
capture_output=True,
text=True
)
else:
# Upstream already set, just push
result = subprocess.run(
['pass', 'git', 'push'],
capture_output=True,
text=True
)
if result.returncode == 0:
self.play_sound_effect(1000, 0.1)
self.update_git_status()
@@ -1337,7 +1379,7 @@ class PassManager(Gtk.Window):
# Remove existing remote if present
subprocess.run(
['git', '-C', passwordStoreDir, 'remote', 'remove', 'origin'],
capture_output=True,
stdout=subprocess.DEVNULL,
stderr=subprocess.DEVNULL
)
@@ -1454,7 +1496,7 @@ class PassManager(Gtk.Window):
# Test connectivity checkbox
testCheck = Gtk.CheckButton(label="Test connectivity before setup")
testCheck.set_active(True)
testCheck.set_active(False)
contentArea.pack_start(testCheck, False, False, 0)
# Examples
@@ -1525,8 +1567,11 @@ class PassManager(Gtk.Window):
show_status_message("Invalid URL format. Please check the examples above.", 'error')
continue
# Test connectivity if requested
if testCheck.get_active():
# Skip connectivity test for SSH URLs (can't prompt for auth in GUI)
isSshUrl = remoteUrl.startswith('ssh://') or remoteUrl.startswith('git@')
# Test connectivity if requested and not SSH
if testCheck.get_active() and not isSshUrl:
# Show testing message
testingDialog = Gtk.MessageDialog(
transient_for=dialog,
@@ -1617,28 +1662,57 @@ class PassManager(Gtk.Window):
pushDialog.destroy()
if response == Gtk.ResponseType.YES:
# Push to remote
result = subprocess.run(
['pass', 'git', 'push', '-u', 'origin', 'master'],
# Detect current branch name
branchResult = subprocess.run(
['git', '-C', passwordStoreDir, 'branch', '--show-current'],
capture_output=True,
text=True
)
if result.returncode != 0:
# Try 'main' branch if 'master' fails
currentBranch = branchResult.stdout.strip() if branchResult.returncode == 0 else 'master'
# Check if there are any commits
hasCommits = subprocess.run(
['git', '-C', passwordStoreDir, 'rev-parse', 'HEAD'],
stdout=subprocess.DEVNULL,
stderr=subprocess.DEVNULL
).returncode == 0
if not hasCommits:
# No commits yet - explain to user
noCommitsDialog = Gtk.MessageDialog(
transient_for=self,
flags=0,
message_type=Gtk.MessageType.INFO,
buttons=Gtk.ButtonsType.OK,
text="No commits to push yet"
)
noCommitsDialog.format_secondary_text(
"Your password store doesn't have any commits yet.\n\n"
"Add some passwords first, then use the Git tab to push them to the remote."
)
noCommitsDialog.run()
noCommitsDialog.destroy()
else:
# Push to remote with detected branch
result = subprocess.run(
['pass', 'git', 'push', '-u', 'origin', 'main'],
['pass', 'git', 'push', '-u', 'origin', currentBranch],
capture_output=True,
text=True
)
if result.returncode != 0:
self.show_error(f"Push failed: {result.stderr}\n\nYou can push manually later from the Git tab.")
else:
self.play_sound_effect(1000, 0.1)
if result.returncode != 0:
self.show_error(f"Push failed: {result.stderr}\n\nYou can push manually later from the Git tab.")
else:
self.play_sound_effect(1000, 0.1)
# Update the UI to reflect git is now initialized
self.isGitRepo = True
# Hide the info banner if it exists
if hasattr(self, 'infoBanner'):
self.infoBanner.hide()
self.rebuild_ui_with_git()
def rebuild_ui_with_git(self):