1 from __future__
import absolute_import
, division
, print_function
, unicode_literals
14 from .interaction
import Interaction
15 from .widgets
import completion
16 from .widgets
import editremotes
17 from .widgets
import switcher
18 from .widgets
.browse
import BrowseBranch
19 from .widgets
.selectcommits
import select_commits
20 from .widgets
.selectcommits
import select_commits_and_output
23 def delete_branch(context
):
24 """Launch the 'Delete Branch' dialog."""
25 icon
= icons
.discard()
26 branch
= choose_branch(context
, N_('Delete Branch'), N_('Delete'), icon
=icon
)
29 cmds
.do(cmds
.DeleteBranch
, context
, branch
)
32 def delete_remote_branch(context
):
33 """Launch the 'Delete Remote Branch' dialog."""
34 remote_branch
= choose_remote_branch(
35 context
, N_('Delete Remote Branch'), N_('Delete'), icon
=icons
.discard()
39 remote
, branch
= gitcmds
.parse_remote_branch(remote_branch
)
41 cmds
.do(cmds
.DeleteRemoteBranch
, context
, remote
, branch
)
44 def browse_current(context
):
45 """Launch the 'Browse Current Branch' dialog."""
46 branch
= gitcmds
.current_branch(context
)
47 BrowseBranch
.browse(context
, branch
)
50 def browse_other(context
):
51 """Prompt for a branch and inspect content at that point in time."""
52 # Prompt for a branch to browse
53 branch
= choose_ref(context
, N_('Browse Commits...'), N_('Browse'))
56 BrowseBranch
.browse(context
, branch
)
59 def checkout_branch(context
, default
=None):
60 """Launch the 'Checkout Branch' dialog."""
61 branch
= choose_potential_branch(
62 context
, N_('Checkout Branch'), N_('Checkout'), default
=default
66 cmds
.do(cmds
.CheckoutBranch
, context
, branch
)
69 def cherry_pick(context
):
70 """Launch the 'Cherry-Pick' dialog."""
71 revs
, summaries
= gitcmds
.log_helper(context
, all
=True)
72 commits
= select_commits(
73 context
, N_('Cherry-Pick Commit'), revs
, summaries
, multiselect
=False
77 cmds
.do(cmds
.CherryPick
, context
, commits
)
80 def new_repo(context
):
81 """Prompt for a new directory and create a new Git repository
83 :returns str: repository path or None if no repository was created.
87 path
= qtutils
.opendir_dialog(N_('New Repository...'), core
.getcwd())
90 # Avoid needlessly calling `git init`.
91 if git
.is_git_repository(path
):
92 # We could prompt here and confirm that they really didn't
93 # mean to open an existing repository, but I think
94 # treating it like an "Open" is a sensible DWIM answer.
97 status
, out
, err
= git
.init(path
)
101 title
= N_('Error Creating Repository')
102 Interaction
.command_error(title
, 'git init', status
, out
, err
)
106 def open_new_repo(context
):
107 """Create a new repository and open it"""
108 dirname
= new_repo(context
)
111 cmds
.do(cmds
.OpenRepo
, context
, dirname
)
114 def new_bare_repo(context
):
115 """Create a bare repository and configure a remote pointing to it"""
117 repo
= prompt_for_new_bare_repo()
121 ok
= cmds
.do(cmds
.NewBareRepo
, context
, repo
)
124 # Add a new remote pointing to the bare repo
125 parent
= qtutils
.active_window()
126 add_remote
= editremotes
.add_remote(
127 context
, parent
, name
=os
.path
.basename(repo
), url
=repo
, readonly_url
=True
135 def prompt_for_new_bare_repo():
136 """Prompt for a directory and name for a new bare repository"""
137 path
= qtutils
.opendir_dialog(N_('Select Directory...'), core
.getcwd())
142 default
= os
.path
.basename(core
.getcwd())
143 if not default
.endswith('.git'):
146 name
, ok
= qtutils
.prompt(
147 N_('Enter a name for the new bare repo'),
148 title
=N_('New Bare Repository...'),
151 if not name
or not ok
:
153 if not name
.endswith('.git'):
155 repo
= os
.path
.join(path
, name
)
157 Interaction
.critical(N_('Error'), N_('"%s" already exists') % repo
)
164 def export_patches(context
):
165 """Run 'git format-patch' on a list of commits."""
166 revs
, summaries
= gitcmds
.log_helper(context
)
167 to_export_and_output
= select_commits_and_output(
168 context
, N_('Export Patches'), revs
, summaries
170 if not to_export_and_output
['to_export']:
176 reversed(to_export_and_output
['to_export']),
178 to_export_and_output
['output'],
182 def diff_against_commit(context
):
183 """Diff against any commit and checkout changes using the Diff Editor"""
184 icon
= icons
.compare()
185 ref
= choose_ref(context
, N_('Diff Against Commit'), N_('Diff'), icon
=icon
)
188 cmds
.do(cmds
.DiffAgainstCommitMode
, context
, ref
)
191 def diff_expression(context
):
192 """Diff using an arbitrary expression."""
193 tracked
= gitcmds
.tracked_branch(context
)
194 current
= gitcmds
.current_branch(context
)
195 if tracked
and current
:
196 ref
= tracked
+ '..' + current
198 ref
= '@{upstream}..'
199 difftool
.diff_expression(context
, qtutils
.active_window(), ref
)
202 def open_repo(context
):
203 """Open a repository in the current window"""
204 model
= context
.model
205 dirname
= qtutils
.opendir_dialog(N_('Open Git Repository'), model
.getcwd())
208 cmds
.do(cmds
.OpenRepo
, context
, dirname
)
211 def open_repo_in_new_window(context
):
212 """Spawn a new cola session."""
213 model
= context
.model
214 dirname
= qtutils
.opendir_dialog(N_('Open Git Repository'), model
.getcwd())
217 cmds
.do(cmds
.OpenNewRepo
, context
, dirname
)
220 def open_quick_repo_search(context
, parent
=None):
221 """Open a Quick Repository Search dialog"""
223 parent
= qtutils
.active_window()
224 settings
= context
.settings
225 items
= settings
.bookmarks
+ settings
.recent
229 default_repo
= cfg
.get('cola.defaultrepo')
231 entries
= QtGui
.QStandardItemModel()
233 normalize
= display
.normalize_path
234 star_icon
= icons
.star()
235 folder_icon
= icons
.folder()
238 key
= normalize(item
['path'])
243 if default_repo
== item
['path']:
248 entry
= switcher
.switcher_item(key
, icon
, name
)
249 entries
.appendRow(entry
)
252 title
= N_('Quick Open Repository')
253 place_holder
= N_('Search repositories by name...')
254 switcher
.switcher_inner_view(
258 place_holder
=place_holder
,
259 enter_action
=lambda entry
: cmds
.do(cmds
.OpenRepo
, context
, entry
.key
),
264 def load_commitmsg(context
):
265 """Load a commit message from a file."""
266 model
= context
.model
267 filename
= qtutils
.open_file(N_('Load Commit Message'), directory
=model
.getcwd())
269 cmds
.do(cmds
.LoadCommitMessageFromFile
, context
, filename
)
272 def choose_from_dialog(get
, context
, title
, button_text
, default
, icon
=None):
273 """Choose a value from a dialog using the `get` method"""
274 parent
= qtutils
.active_window()
275 return get(context
, title
, button_text
, parent
, default
=default
, icon
=icon
)
278 def choose_ref(context
, title
, button_text
, default
=None, icon
=None):
279 """Choose a Git ref and return it"""
280 return choose_from_dialog(
281 completion
.GitRefDialog
.get
, context
, title
, button_text
, default
, icon
=icon
285 def choose_branch(context
, title
, button_text
, default
=None, icon
=None):
286 """Choose a branch and return either the chosen branch or an empty value"""
287 return choose_from_dialog(
288 completion
.GitBranchDialog
.get
, context
, title
, button_text
, default
, icon
=icon
292 def choose_potential_branch(context
, title
, button_text
, default
=None, icon
=None):
293 """Choose a "potential" branch for checking out.
295 This dialog includes remote branches from which new local branches can be created.
297 return choose_from_dialog(
298 completion
.GitCheckoutBranchDialog
.get
,
307 def choose_remote_branch(context
, title
, button_text
, default
=None, icon
=None):
308 """Choose a remote branch"""
309 return choose_from_dialog(
310 completion
.GitRemoteBranchDialog
.get
,
319 def review_branch(context
):
320 """Diff against an arbitrary revision, branch, tag, etc."""
321 branch
= choose_ref(context
, N_('Select Branch to Review'), N_('Review'))
324 merge_base
= gitcmds
.merge_base_parent(context
, branch
)
325 difftool
.diff_commits(context
, qtutils
.active_window(), merge_base
, branch
)
328 def rename_branch(context
):
329 """Launch the 'Rename Branch' dialogs."""
330 branch
= choose_branch(context
, N_('Rename Existing Branch'), N_('Select'))
333 new_branch
= choose_branch(context
, N_('Enter New Branch Name'), N_('Rename'))
336 cmds
.do(cmds
.RenameBranch
, context
, branch
, new_branch
)
339 def reset_soft(context
):
340 """Run "git reset --soft" to reset the branch HEAD"""
341 title
= N_('Reset Branch (Soft)')
342 ok_text
= N_('Reset Branch')
343 ref
= choose_ref(context
, title
, ok_text
, default
='HEAD^')
345 cmds
.do(cmds
.ResetSoft
, context
, ref
)
348 def reset_mixed(context
):
349 """Run "git reset --mixed" to reset the branch HEAD and staging area"""
350 title
= N_('Reset Branch and Stage (Mixed)')
351 ok_text
= N_('Reset')
352 ref
= choose_ref(context
, title
, ok_text
, default
='HEAD^')
354 cmds
.do(cmds
.ResetMixed
, context
, ref
)
357 def reset_keep(context
):
358 """Run "git reset --keep" safe reset to avoid clobbering local changes"""
359 title
= N_('Reset All (Keep Unstaged Changes)')
360 ref
= choose_ref(context
, title
, N_('Reset and Restore'))
362 cmds
.do(cmds
.ResetKeep
, context
, ref
)
365 def reset_merge(context
):
366 """Run "git reset --merge" to reset the working tree and staging area
368 The staging area is allowed to carry forward unmerged index entries,
369 but if any unstaged changes would be clobbered by the reset then the
372 title
= N_('Restore Worktree and Reset All (Merge)')
373 ok_text
= N_('Reset and Restore')
374 ref
= choose_ref(context
, title
, ok_text
, default
='HEAD^')
376 cmds
.do(cmds
.ResetMerge
, context
, ref
)
379 def reset_hard(context
):
380 """Run "git reset --hard" to fully reset the working tree and staging area"""
381 title
= N_('Restore Worktree and Reset All (Hard)')
382 ok_text
= N_('Reset and Restore')
383 ref
= choose_ref(context
, title
, ok_text
, default
='HEAD^')
385 cmds
.do(cmds
.ResetHard
, context
, ref
)
388 def restore_worktree(context
):
389 """Restore the worktree to the content from the specified commit"""
390 title
= N_('Restore Worktree')
391 ok_text
= N_('Restore Worktree')
392 ref
= choose_ref(context
, title
, ok_text
, default
='HEAD^')
394 cmds
.do(cmds
.RestoreWorktree
, context
, ref
)
398 """Install the GUI-model interaction hooks"""
399 Interaction
.choose_ref
= staticmethod(choose_ref
)