A couple fixes to git management for pass.
This commit is contained in:
@@ -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):
|
||||
|
||||
Reference in New Issue
Block a user