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
+98 -24
View File
@@ -171,7 +171,10 @@ class PassManager(Gtk.Window):
r'^git@[\w\.-]+:[\w\-/\.]+$', # git@host:path/repo r'^git@[\w\.-]+:[\w\-/\.]+$', # git@host:path/repo
r'^https?://[\w\.-]+/[\w\-/\.]+\.git$', # https://host/path/repo.git r'^https?://[\w\.-]+/[\w\-/\.]+\.git$', # https://host/path/repo.git
r'^https?://[\w\.-]+/[\w\-/\.]+$', # https://host/path/repo 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@\.-]+/[\w\-/\.~]+$', # ssh://user@host/path
r'^ssh://[\w@\.-]+:\d+/[\w\-/\.~]+$', # ssh://user@host:port/path
r'^[\w]+@[\w\.-]+:[\w\-/\.~]+$', # user@host: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) # Git sync info banner (only show if git is not initialized)
if not self.isGitRepo: if not self.isGitRepo:
infoBanner = Gtk.InfoBar() self.infoBanner = Gtk.InfoBar()
infoBanner.set_message_type(Gtk.MessageType.INFO) self.infoBanner.set_message_type(Gtk.MessageType.INFO)
contentArea = infoBanner.get_content_area() contentArea = self.infoBanner.get_content_area()
infoLabel = Gtk.Label(label="Git sync is not enabled. Passwords are stored locally only.") infoLabel = Gtk.Label(label="Git sync is not enabled. Passwords are stored locally only.")
contentArea.pack_start(infoLabel, False, False, 0) contentArea.pack_start(infoLabel, False, False, 0)
setupButton = Gtk.Button(label="Set Up Git Sync") setupButton = Gtk.Button(label="Set Up Git Sync")
setupButton.connect("clicked", self.on_setup_git_sync_clicked) 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 # Search box
searchBox = Gtk.Box(orientation=Gtk.Orientation.HORIZONTAL, spacing=5) searchBox = Gtk.Box(orientation=Gtk.Orientation.HORIZONTAL, spacing=5)
@@ -961,7 +964,7 @@ class PassManager(Gtk.Window):
# Fetch to get latest remote status (quietly) # Fetch to get latest remote status (quietly)
subprocess.run( subprocess.run(
['git', '-C', passwordStoreDir, 'fetch'], ['git', '-C', passwordStoreDir, 'fetch'],
capture_output=True, stdout=subprocess.DEVNULL,
stderr=subprocess.DEVNULL stderr=subprocess.DEVNULL
) )
@@ -1258,12 +1261,51 @@ class PassManager(Gtk.Window):
def on_git_push_clicked(self, button): def on_git_push_clicked(self, button):
"""Handle git push button""" """Handle git push button"""
result = subprocess.run( passwordStoreDir = str(Path.home() / '.password-store')
['pass', 'git', 'push'],
capture_output=True, # Check if there are any commits
text=True 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: if result.returncode == 0:
self.play_sound_effect(1000, 0.1) self.play_sound_effect(1000, 0.1)
self.update_git_status() self.update_git_status()
@@ -1337,7 +1379,7 @@ class PassManager(Gtk.Window):
# Remove existing remote if present # Remove existing remote if present
subprocess.run( subprocess.run(
['git', '-C', passwordStoreDir, 'remote', 'remove', 'origin'], ['git', '-C', passwordStoreDir, 'remote', 'remove', 'origin'],
capture_output=True, stdout=subprocess.DEVNULL,
stderr=subprocess.DEVNULL stderr=subprocess.DEVNULL
) )
@@ -1454,7 +1496,7 @@ class PassManager(Gtk.Window):
# Test connectivity checkbox # Test connectivity checkbox
testCheck = Gtk.CheckButton(label="Test connectivity before setup") testCheck = Gtk.CheckButton(label="Test connectivity before setup")
testCheck.set_active(True) testCheck.set_active(False)
contentArea.pack_start(testCheck, False, False, 0) contentArea.pack_start(testCheck, False, False, 0)
# Examples # Examples
@@ -1525,8 +1567,11 @@ class PassManager(Gtk.Window):
show_status_message("Invalid URL format. Please check the examples above.", 'error') show_status_message("Invalid URL format. Please check the examples above.", 'error')
continue continue
# Test connectivity if requested # Skip connectivity test for SSH URLs (can't prompt for auth in GUI)
if testCheck.get_active(): 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 # Show testing message
testingDialog = Gtk.MessageDialog( testingDialog = Gtk.MessageDialog(
transient_for=dialog, transient_for=dialog,
@@ -1617,28 +1662,57 @@ class PassManager(Gtk.Window):
pushDialog.destroy() pushDialog.destroy()
if response == Gtk.ResponseType.YES: if response == Gtk.ResponseType.YES:
# Push to remote # Detect current branch name
result = subprocess.run( branchResult = subprocess.run(
['pass', 'git', 'push', '-u', 'origin', 'master'], ['git', '-C', passwordStoreDir, 'branch', '--show-current'],
capture_output=True, capture_output=True,
text=True text=True
) )
if result.returncode != 0: currentBranch = branchResult.stdout.strip() if branchResult.returncode == 0 else 'master'
# Try 'main' branch if 'master' fails
# 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( result = subprocess.run(
['pass', 'git', 'push', '-u', 'origin', 'main'], ['pass', 'git', 'push', '-u', 'origin', currentBranch],
capture_output=True, capture_output=True,
text=True text=True
) )
if result.returncode != 0: if result.returncode != 0:
self.show_error(f"Push failed: {result.stderr}\n\nYou can push manually later from the Git tab.") self.show_error(f"Push failed: {result.stderr}\n\nYou can push manually later from the Git tab.")
else: else:
self.play_sound_effect(1000, 0.1) self.play_sound_effect(1000, 0.1)
# Update the UI to reflect git is now initialized # Update the UI to reflect git is now initialized
self.isGitRepo = True self.isGitRepo = True
# Hide the info banner if it exists
if hasattr(self, 'infoBanner'):
self.infoBanner.hide()
self.rebuild_ui_with_git() self.rebuild_ui_with_git()
def rebuild_ui_with_git(self): def rebuild_ui_with_git(self):