diff --git a/.gitignore b/.gitignore index 56c6b572..8fb9cd82 100644 --- a/.gitignore +++ b/.gitignore @@ -2,4 +2,5 @@ *.tmLanguage.cache *.tmPreferences.cache .DS_Store -package-metadata.json \ No newline at end of file +package-metadata.json +*.sublime-project diff --git a/Default.sublime-commands b/Default.sublime-commands index 61bb55c5..9326b140 100644 --- a/Default.sublime-commands +++ b/Default.sublime-commands @@ -58,6 +58,10 @@ "caption": "Git: Diff Staged Files", "command": "git_diff_commit" } + ,{ + "caption": "Git: Diff Branch", + "command": "git_diff_branch" + } ,{ "caption": "Git: Diff Current File (Ignore Whitespace)", "command": "git_diff", @@ -73,6 +77,11 @@ "command": "git_diff_commit", "args": { "ignore_whitespace": true } } + ,{ + "caption": "Git: Diff Branch (Ignore Whitespace)", + "command": "git_diff_branch", + "args": { "ignore_whitespace": true } + } ,{ "caption": "Git: Diff Tool Current File", "command": "git_raw", "args": { "command": "git difftool", "append_current_file": true, "may_change_files": false } diff --git a/Git.sublime-settings b/Git.sublime-settings index 10bb9eee..98e4d93d 100644 --- a/Git.sublime-settings +++ b/Git.sublime-settings @@ -16,6 +16,9 @@ // use the panel for diff output, rather than a new scratch window (new tab) ,"diff_panel": false + // show line numbers in output views + ,"line_numbers": false + // If you'd rather have your status command open files instead of show you a // diff, set this to true. You can still do `Git: Status` followed by // 'Git: Diff Current File' to get a file diff diff --git a/Main.sublime-menu b/Main.sublime-menu index 40c7d0b4..c9c2b9c9 100644 --- a/Main.sublime-menu +++ b/Main.sublime-menu @@ -43,6 +43,8 @@ ,{ "caption": "Diff (no whitespace)", "command": "git_diff_all", "args": { "ignore_whitespace": true } } ,{ "caption": "Diff Staged", "command": "git_diff_commit" } ,{ "caption": "Diff Staged (no whitespace)", "command": "git_diff_commit", "args": { "ignore_whitespace": true } } + ,{ "caption": "Diff Branch", "command": "git_diff_branch" } + ,{ "caption": "Diff Branch (Ignore Whitespace)", "command": "git_diff_branch", "args": { "ignore_whitespace": true } } ,{ "caption": "Diff Tool", "command": "git_raw", "args": { "command": "git difftool", "may_change_files": false } } ,{ "caption": "Reset Hard", "command": "git_reset_hard_head" } ,{ "caption": "-" } @@ -88,6 +90,7 @@ ,{ "caption": "Init", "command": "git_init"} ,{ "caption": "Status...", "command": "git_status" } ,{ "caption": "Branches...", "command": "git_branch" } + ,{ "caption": "Track Remote Branch", "command": "git_track_remote_branch" } ,{ "caption": "Merge...", "command": "git_merge" } ,{ "caption": "See commit history...", "command": "git_commit_history"} ] diff --git a/git/__init__.py b/git/__init__.py index 003ed6a4..1b9a4324 100644 --- a/git/__init__.py +++ b/git/__init__.py @@ -101,7 +101,10 @@ def _make_text_safeish(text, fallback_encoding, method='decode'): try: unitext = getattr(text, method)('utf-8') except (UnicodeEncodeError, UnicodeDecodeError): - unitext = getattr(text, method)(fallback_encoding) + try: + unitext = getattr(text, method)(fallback_encoding) + except (UnicodeEncodeError, UnicodeDecodeError): + unitext = str(text) except AttributeError: # strongly implies we're already unicode, but just in case let's cast # to string @@ -283,6 +286,9 @@ def _output_to_view(self, output_file, output, clear=False, 'output': output, 'clear': clear } + s = sublime.load_settings("Git.sublime-settings") + if (s.has('line_numbers')): + output_file.settings().set('line_numbers', s.get('line_numbers', False)) output_file.run_command('git_scratch_output', args) def scratch(self, output, title=False, position=None, **kwargs): diff --git a/git/diff.py b/git/diff.py index 5abdc390..0c9a2f3a 100644 --- a/git/diff.py +++ b/git/diff.py @@ -42,7 +42,6 @@ def diff_done(self, result): if not result.strip(): self.panel("No output") return - s = sublime.load_settings("Git.sublime-settings") syntax = s.get("diff_syntax", "Packages/Diff/Diff.tmLanguage") self.scratch(result, title="Git Diff", syntax=syntax) @@ -137,3 +136,65 @@ def on_path_confirmed(self, git_root_dir): new_view = v.window().open_file(full_path_file_name) do_when(lambda: not new_view.is_loading(), lambda: goto_xy(new_view, self.goto_line, self.column)) + + +class GitDiffBranch (GitDiffAllCommand): + ignore_whitespace = False + branches = [] + files = [] + command = [] + picked_file = '' + + def run(self, edit = None, ignore_whitespace = False): + self.ignore_whitespace = ignore_whitespace; + self.run_command(['git', 'branch', '--no-color'], + self.panel_branch) + + def panel_branch(self, result): + self.branches = result.rstrip().split('\n') + self.branches = [item.strip() for item in self.branches + if not (item.startswith('*') or item.strip().find(' ') > -1)] + self.quick_panel(self.branches, self.panel_branch_done, + sublime.MONOSPACE_FONT) + + def panel_branch_done(self, picked = 0): + if 0 > picked < len(self.branches): + return + self.picked_branch = self.branches[picked] + self.run_command(['git', 'diff', '--name-status', self.picked_branch], + self.panel_file) + + def panel_file(self, result): + self.files = [['All', 'Compare all files']] + for item in result.rstrip().split('\n'): + item = item.split('\t', 1)[::-1] + self.files.append(item) + + if (len(self.files) == 1): + self.panel("No changed files") + return + + self.quick_panel(self.files, self.panel_file_done, sublime.MONOSPACE_FONT) + + def panel_file_done(self, picked = 0): + if 0 > picked < len(self.branches): + return + command = ['git', 'diff', '--cached', '--no-color', self.picked_branch] + if self.ignore_whitespace: + command += ['--ignore-all-space', '--ignore-blank-lines'] + + if picked == 0: + self.run_command(command, self.diff_done) + else: + self.picked_file = self.files[picked][0] + self.command = command + self.run_command(['git', 'rev-parse', '--show-toplevel'], self.show_toplevel_done) + + def show_toplevel_done(self, result): + result = result.strip() + if not result: + sublime.status_message("Can't retrieve git toplevel") + return + command = self.command + ['--', result.rstrip('/') + '/' + self.picked_file.lstrip('/')] + print(command, result, result.rstrip('/'), self.picked_file.lstrip('/')) + self.run_command(command, self.diff_done) diff --git a/git/repo.py b/git/repo.py index 303606b5..4c34959b 100644 --- a/git/repo.py +++ b/git/repo.py @@ -32,12 +32,18 @@ class GitBranchCommand(GitWindowCommand): may_change_files = True command_to_run_after_branch = ['checkout'] extra_flags = [] + filter_invalid_items = False + strip_items = False def run(self): self.run_command(['git', 'branch', '--no-color'] + self.extra_flags, self.branch_done) def branch_done(self, result): self.results = result.rstrip().split('\n') + if self.strip_items: + self.results = [item.strip() for item in self.results] + if self.filter_invalid_items: + self.results = [item for item in self.results if item.strip().find(' ') < 0] self.quick_panel(self.results, self.panel_done, sublime.MONOSPACE_FONT) @@ -80,8 +86,10 @@ def on_input(self, branchname): class GitTrackRemoteBranchCommand(GitBranchCommand): - command_to_run_after_branch = ['checkout', '-t'] - extra_flags = ['-r'] + command_to_run_after_branch = ['checkout', '-t'] + extra_flags = ['-r'] + filter_invalid_items = True + strip_items = True class GitNewTagCommand(GitWindowCommand):