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
):
60 """Launch the 'Checkout Branch' dialog."""
61 branch
= choose_potential_branch(context
, N_('Checkout Branch'), N_('Checkout'))
64 cmds
.do(cmds
.CheckoutBranch
, context
, branch
)
67 def cherry_pick(context
):
68 """Launch the 'Cherry-Pick' dialog."""
69 revs
, summaries
= gitcmds
.log_helper(context
, all
=True)
70 commits
= select_commits(
71 context
, N_('Cherry-Pick Commit'), revs
, summaries
, multiselect
=False
75 cmds
.do(cmds
.CherryPick
, context
, commits
)
78 def new_repo(context
):
79 """Prompt for a new directory and create a new Git repository
81 :returns str: repository path or None if no repository was created.
85 path
= qtutils
.opendir_dialog(N_('New Repository...'), core
.getcwd())
88 # Avoid needlessly calling `git init`.
89 if git
.is_git_repository(path
):
90 # We could prompt here and confirm that they really didn't
91 # mean to open an existing repository, but I think
92 # treating it like an "Open" is a sensible DWIM answer.
95 status
, out
, err
= git
.init(path
)
99 title
= N_('Error Creating Repository')
100 Interaction
.command_error(title
, 'git init', status
, out
, err
)
104 def open_new_repo(context
):
105 """Create a new repository and open it"""
106 dirname
= new_repo(context
)
109 cmds
.do(cmds
.OpenRepo
, context
, dirname
)
112 def new_bare_repo(context
):
113 """Create a bare repository and configure a remote pointing to it"""
115 repo
= prompt_for_new_bare_repo()
119 ok
= cmds
.do(cmds
.NewBareRepo
, context
, repo
)
122 # Add a new remote pointing to the bare repo
123 parent
= qtutils
.active_window()
124 add_remote
= editremotes
.add_remote(
125 context
, parent
, name
=os
.path
.basename(repo
), url
=repo
, readonly_url
=True
133 def prompt_for_new_bare_repo():
134 """Prompt for a directory and name for a new bare repository"""
135 path
= qtutils
.opendir_dialog(N_('Select Directory...'), core
.getcwd())
140 default
= os
.path
.basename(core
.getcwd())
141 if not default
.endswith('.git'):
144 name
, ok
= qtutils
.prompt(
145 N_('Enter a name for the new bare repo'),
146 title
=N_('New Bare Repository...'),
149 if not name
or not ok
:
151 if not name
.endswith('.git'):
153 repo
= os
.path
.join(path
, name
)
155 Interaction
.critical(N_('Error'), N_('"%s" already exists') % repo
)
162 def export_patches(context
):
163 """Run 'git format-patch' on a list of commits."""
164 revs
, summaries
= gitcmds
.log_helper(context
)
165 to_export_and_output
= select_commits_and_output(
166 context
, N_('Export Patches'), revs
, summaries
168 if not to_export_and_output
['to_export']:
174 reversed(to_export_and_output
['to_export']),
176 to_export_and_output
['output'],
180 def diff_against_commit(context
):
181 """Diff against any commit and checkout changes using the Diff Editor"""
182 icon
= icons
.compare()
183 ref
= choose_ref(context
, N_('Diff Against Commit'), N_('Diff'), icon
=icon
)
186 cmds
.do(cmds
.DiffAgainstCommitMode
, context
, ref
)
189 def diff_expression(context
):
190 """Diff using an arbitrary expression."""
191 tracked
= gitcmds
.tracked_branch(context
)
192 current
= gitcmds
.current_branch(context
)
193 if tracked
and current
:
194 ref
= tracked
+ '..' + current
196 ref
= '@{upstream}..'
197 difftool
.diff_expression(context
, qtutils
.active_window(), ref
)
200 def open_repo(context
):
201 """Open a repository in the current window"""
202 model
= context
.model
203 dirname
= qtutils
.opendir_dialog(N_('Open Git Repository'), model
.getcwd())
206 cmds
.do(cmds
.OpenRepo
, context
, dirname
)
209 def open_repo_in_new_window(context
):
210 """Spawn a new cola session."""
211 model
= context
.model
212 dirname
= qtutils
.opendir_dialog(N_('Open Git Repository'), model
.getcwd())
215 cmds
.do(cmds
.OpenNewRepo
, context
, dirname
)
218 def open_quick_repo_search(context
, parent
=None):
219 """Open a Quick Repository Search dialog"""
221 parent
= qtutils
.active_window()
222 settings
= context
.settings
223 items
= settings
.bookmarks
+ settings
.recent
227 default_repo
= cfg
.get('cola.defaultrepo')
229 entries
= QtGui
.QStandardItemModel()
231 normalize
= display
.normalize_path
232 star_icon
= icons
.star()
233 folder_icon
= icons
.folder()
236 key
= normalize(item
['path'])
241 if default_repo
== item
['path']:
246 entry
= switcher
.switcher_item(key
, icon
, name
)
247 entries
.appendRow(entry
)
250 title
= N_('Quick Open Repository')
251 place_holder
= N_('Search repositories by name...')
252 switcher
.switcher_inner_view(
256 place_holder
=place_holder
,
257 enter_action
=lambda entry
: cmds
.do(cmds
.OpenRepo
, context
, entry
.key
),
262 def load_commitmsg(context
):
263 """Load a commit message from a file."""
264 model
= context
.model
265 filename
= qtutils
.open_file(N_('Load Commit Message'), directory
=model
.getcwd())
267 cmds
.do(cmds
.LoadCommitMessageFromFile
, context
, filename
)
270 def choose_from_dialog(get
, context
, title
, button_text
, default
, icon
=None):
271 """Choose a value from a dialog using the `get` method"""
272 parent
= qtutils
.active_window()
273 return get(context
, title
, button_text
, parent
, default
=default
, icon
=icon
)
276 def choose_ref(context
, title
, button_text
, default
=None, icon
=None):
277 """Choose a Git ref and return it"""
278 return choose_from_dialog(
279 completion
.GitRefDialog
.get
, context
, title
, button_text
, default
, icon
=icon
283 def choose_branch(context
, title
, button_text
, default
=None, icon
=None):
284 """Choose a branch and return either the chosen branch or an empty value"""
285 return choose_from_dialog(
286 completion
.GitBranchDialog
.get
, context
, title
, button_text
, default
, icon
=icon
290 def choose_potential_branch(context
, title
, button_text
, default
=None, icon
=None):
291 """Choose a "potential" branch for checking out.
293 This dialog includes remote branches from which new local branches can be created.
295 return choose_from_dialog(
296 completion
.GitCheckoutBranchDialog
.get
,
305 def choose_remote_branch(context
, title
, button_text
, default
=None, icon
=None):
306 """Choose a remote branch"""
307 return choose_from_dialog(
308 completion
.GitRemoteBranchDialog
.get
,
317 def review_branch(context
):
318 """Diff against an arbitrary revision, branch, tag, etc."""
319 branch
= choose_ref(context
, N_('Select Branch to Review'), N_('Review'))
322 merge_base
= gitcmds
.merge_base_parent(context
, branch
)
323 difftool
.diff_commits(context
, qtutils
.active_window(), merge_base
, branch
)
326 def rename_branch(context
):
327 """Launch the 'Rename Branch' dialogs."""
328 branch
= choose_branch(context
, N_('Rename Existing Branch'), N_('Select'))
331 new_branch
= choose_branch(context
, N_('Enter New Branch Name'), N_('Rename'))
334 cmds
.do(cmds
.RenameBranch
, context
, branch
, new_branch
)
337 def reset_soft(context
):
338 """Run "git reset --soft" to reset the branch HEAD"""
339 title
= N_('Reset Branch (Soft)')
340 ok_text
= N_('Reset Branch')
341 ref
= choose_ref(context
, title
, ok_text
, default
='HEAD^')
343 cmds
.do(cmds
.ResetSoft
, context
, ref
)
346 def reset_mixed(context
):
347 """Run "git reset --mixed" to reset the branch HEAD and staging area"""
348 title
= N_('Reset Branch and Stage (Mixed)')
349 ok_text
= N_('Reset')
350 ref
= choose_ref(context
, title
, ok_text
, default
='HEAD^')
352 cmds
.do(cmds
.ResetMixed
, context
, ref
)
355 def reset_keep(context
):
356 """Run "git reset --keep" safe reset to avoid clobbering local changes"""
357 title
= N_('Reset All (Keep Unstaged Changes)')
358 ref
= choose_ref(context
, title
, N_('Reset and Restore'))
360 cmds
.do(cmds
.ResetKeep
, context
, ref
)
363 def reset_merge(context
):
364 """Run "git reset --merge" to reset the working tree and staging area
366 The staging area is allowed to carry forward unmerged index entries,
367 but if any unstaged changes would be clobbered by the reset then the
370 title
= N_('Restore Worktree and Reset All (Merge)')
371 ok_text
= N_('Reset and Restore')
372 ref
= choose_ref(context
, title
, ok_text
, default
='HEAD^')
374 cmds
.do(cmds
.ResetMerge
, context
, ref
)
377 def reset_hard(context
):
378 """Run "git reset --hard" to fully reset the working tree and staging area"""
379 title
= N_('Restore Worktree and Reset All (Hard)')
380 ok_text
= N_('Reset and Restore')
381 ref
= choose_ref(context
, title
, ok_text
, default
='HEAD^')
383 cmds
.do(cmds
.ResetHard
, context
, ref
)
386 def restore_worktree(context
):
387 """Restore the worktree to the content from the specified commit"""
388 title
= N_('Restore Worktree')
389 ok_text
= N_('Restore Worktree')
390 ref
= choose_ref(context
, title
, ok_text
, default
='HEAD^')
392 cmds
.do(cmds
.RestoreWorktree
, context
, ref
)
396 """Install the GUI-model interaction hooks"""
397 Interaction
.choose_ref
= staticmethod(choose_ref
)