Skip to content


Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP
tree: 522501cb76
Fetching contributors…

Cannot retrieve contributors at this time

169 lines (140 sloc) 6.351 kb
import functools
import tempfile
import os
import sublime
import sublime_plugin
from git import GitTextCommand, GitWindowCommand, plugin_file, view_contents, _make_text_safeish
import add
history = []
class GitQuickCommitCommand(GitTextCommand):
def run(self, edit):
self.get_window().show_input_panel("Message", "",
self.on_input, None, None)
def on_input(self, message):
if message.strip() == "":
self.panel("No commit message provided")
self.run_command(['git', 'add', self.get_file_name()],
functools.partial(self.add_done, message))
def add_done(self, message, result):
if result.strip():
sublime.error_message("Error adding file:\n" + result)
self.run_command(['git', 'commit', '-m', message])
# Commit is complicated. It'd be easy if I just wanted to let it run
# on OSX, and assume that subl was in the $PATH. However... I can't do
# that. Second choice was to set $GIT_EDITOR to sublime text for the call
# to commit, and let that Just Work. However, on Windows you can't pass
# -w to sublime, which means the editor won't wait, and so the commit will fail
# with an empty message.
# Thus this flow:
# 1. `status --porcelain --untracked-files=no` to know whether files need
# to be committed
# 2. `status` to get a template commit message (not the exact one git uses; I
# can't see a way to ask it to output that, which is not quite ideal)
# 3. Create a scratch buffer containing the template
# 4. When this buffer is closed, get its contents with an event handler and
# pass execution back to the original command. (I feel that the way this
# is done is a total hack. Unfortunately, I cannot see a better way right
# now.)
# 5. Strip lines beginning with # from the message, and save in a temporary
# file
# 6. `commit -F [tempfile]`
class GitCommitCommand(GitWindowCommand):
active_message = False
extra_options = ""
def run(self):
self.lines = []
self.working_dir = self.get_working_dir()
['git', 'status', '--untracked-files=no', '--porcelain'],
def porcelain_status_done(self, result):
# todo: split out these status-parsing things... asdf
has_staged_files = False
result_lines = result.rstrip().split('\n')
for line in result_lines:
if line and not line[0].isspace():
has_staged_files = True
if not has_staged_files:
self.panel("Nothing to commit")
# Okay, get the template!
s = sublime.load_settings("Git.sublime-settings")
if s.get("verbose_commits"):
self.run_command(['git', 'diff', '--staged', '--no-color'], self.diff_done)
self.run_command(['git', 'status'], self.diff_done)
def diff_done(self, result):
settings = sublime.load_settings("Git.sublime-settings")
historySize = settings.get('history_size')
def format(line):
return '# ' + line.replace("\n", " ")
if not len(self.lines):
self.lines = ["", ""]
self.lines.extend(map(format, history[:historySize]))
"# --------------",
"# Please enter the commit message for your changes. Everything below",
"# this paragraph is ignored, and an empty message aborts the commit.",
"# Just close the window to accept your message.",
template = "\n".join(self.lines)
msg = self.window.new_file()
self._output_to_view(msg, template, syntax=plugin_file("syntax/Git Commit Message.tmLanguage"))
msg.sel().add(sublime.Region(0, 0))
GitCommitCommand.active_message = self
def message_done(self, message):
# filter out the comments (git commit doesn't do this automatically)
settings = sublime.load_settings("Git.sublime-settings")
historySize = settings.get('history_size')
lines = [line for line in message.split("\n# --------------")[0].split("\n")
if not line.lstrip().startswith('#')]
message = '\n'.join(lines).strip()
if len(message) and historySize:
history.insert(0, message)
# write the temp file
message_file = tempfile.NamedTemporaryFile(delete=False)
message_file.write(_make_text_safeish(message, self.fallback_encoding, 'encode'))
self.message_file = message_file
# and actually commit
self.run_command(['git', 'commit', '-F',, self.extra_options],
self.commit_done, working_dir=self.working_dir)
def commit_done(self, result):
class GitCommitAmendCommand(GitCommitCommand):
extra_options = "--amend"
def diff_done(self, result):
self.after_show = result
self.run_command(['git', 'log', '-n', '1', '--format=format:%B'], self.amend_diff_done)
def amend_diff_done(self, result):
self.lines = result.split("\n")
super(GitCommitAmendCommand, self).diff_done(self.after_show)
class GitCommitMessageListener(sublime_plugin.EventListener):
def on_close(self, view):
command = GitCommitCommand.active_message
if not command:
message = view_contents(view)
class GitCommitHistoryCommand(sublime_plugin.TextCommand):
def run(self, edit):
self.edit = edit
self.view.window().show_quick_panel(history, self.panel_done, sublime.MONOSPACE_FONT)
def panel_done(self, index):
if index > -1:
self.view.replace(self.edit, self.view.sel()[0], history[index] + '\n')
class GitCommitSelectedHunk(add.GitAddSelectedHunkCommand):
def run(self, edit):
self.run_command(['git', 'diff', '--no-color', self.get_file_name()], self.cull_diff)
Jump to Line
Something went wrong with that request. Please try again.