├── .python-version
├── CONTRIBUTING.md
├── Context.sublime-menu
├── Default (Linux).sublime-keymap
├── Default (OSX).sublime-keymap
├── Default (Windows).sublime-keymap
├── Default.sublime-commands
├── Default.sublime-keymap
├── GitSavvy.sublime-project
├── GitSavvy.sublime-settings
├── GitSavvy.tmPreferences
├── LICENSE
├── Main.sublime-menu
├── README.md
├── common
├── __init__.py
├── commands
│ ├── __init__.py
│ ├── debug.py
│ ├── help.py
│ └── view_manipulation.py
├── global_events.py
├── interwebs.py
├── theme_generator.py
├── ui.py
└── util
│ ├── __init__.py
│ ├── actions.py
│ ├── dates.py
│ ├── debug.py
│ ├── diff_string.py
│ ├── file.py
│ ├── log.py
│ ├── parse_diff.py
│ ├── reload.py
│ └── view.py
├── core
├── __init__.py
├── base_commands.py
├── commands
│ ├── __init__.py
│ ├── amend.py
│ ├── blame.py
│ ├── branch.py
│ ├── changelog.py
│ ├── checkout.py
│ ├── cherry_pick.py
│ ├── commit.py
│ ├── commit_compare.py
│ ├── config.py
│ ├── context_menu.py
│ ├── custom.py
│ ├── diff.py
│ ├── fetch.py
│ ├── fixup.py
│ ├── flow.py
│ ├── help_panel.py
│ ├── ignore.py
│ ├── init.py
│ ├── inline_diff.py
│ ├── intra_line_colorizer.py
│ ├── line_history.py
│ ├── log.py
│ ├── log_graph.py
│ ├── log_graph_colorizer.py
│ ├── log_graph_rebase_actions.py
│ ├── log_graph_smart_copy.py
│ ├── merge.py
│ ├── mv.py
│ ├── navigate.py
│ ├── next_hunk.py
│ ├── pull.py
│ ├── push.py
│ ├── quick_commit.py
│ ├── quick_stage.py
│ ├── reflog.py
│ ├── remote.py
│ ├── reset.py
│ ├── revert.py
│ ├── show_commit.py
│ ├── show_commit_info.py
│ ├── show_file_at_commit.py
│ ├── stage_diff.py
│ ├── stage_hunk.py
│ ├── stash.py
│ ├── status_bar.py
│ └── tag.py
├── exceptions.py
├── fns.py
├── git_command.py
├── git_mixins
│ ├── __init__.py
│ ├── active_branch.py
│ ├── branches.py
│ ├── checkout_discard.py
│ ├── history.py
│ ├── ignore.py
│ ├── merge.py
│ ├── rebase.py
│ ├── remotes.py
│ ├── rewrite.py
│ ├── stage_unstage.py
│ ├── stash.py
│ ├── status.py
│ └── tags.py
├── interfaces
│ ├── __init__.py
│ ├── branch.py
│ ├── rebase.py
│ ├── status.py
│ └── tags.py
├── parse_diff.py
├── runtime.py
├── settings.py
├── store.py
├── types.py
├── ui_mixins
│ ├── __init__.py
│ ├── input_panel.py
│ └── quick_panel.py
├── utils.py
└── view.py
├── dependencies.json
├── docs
├── README.md
├── branch_mgmt.md
├── commit.md
├── custom.md
├── debug.md
├── flow.md
├── github.md
├── gitlab.md
├── history.md
├── ignoring.md
├── misc.md
├── rebase.md
├── remotes.md
├── staging.md
├── stash.md
├── status.md
├── tag_mgmt.md
└── testing.md
├── git_savvy.py
├── github
├── __init__.py
├── commands
│ ├── __init__.py
│ ├── add_fork_as_remote.py
│ ├── commit.py
│ ├── configure.py
│ ├── create_fork.py
│ ├── create_repo.py
│ ├── open_issue.py
│ ├── open_on_remote.py
│ └── pull_request.py
├── git_mixins
│ ├── __init__.py
│ └── remotes.py
└── github.py
├── gitlab
├── __init__.py
├── commands
│ ├── __init__.py
│ ├── configure.py
│ ├── merge_request.py
│ └── open_on_remote.py
├── git_mixins
│ ├── __init__.py
│ └── remotes.py
└── gitlab.py
├── messages.json
├── messages
├── 1.1.0.txt
├── 1.2.0.txt
├── 1.3.1.txt
├── 1.4.0.txt
├── 2.0.0.txt
├── 2.1.0.txt
├── 2.10.0.txt
├── 2.11.0.txt
├── 2.12.0.txt
├── 2.12.1.txt
├── 2.13.0.txt
├── 2.14.0.txt
├── 2.14.1.txt
├── 2.14.2.txt
├── 2.16.2.txt
├── 2.16.4.txt
├── 2.16.5.txt
├── 2.16.6.txt
├── 2.16.7.txt
├── 2.17.0.txt
├── 2.17.1.txt
├── 2.17.3.txt
├── 2.17.4.txt
├── 2.18.0.txt
├── 2.19.0.txt
├── 2.2.0.txt
├── 2.20.0.txt
├── 2.21.0.txt
├── 2.22.0.txt
├── 2.23.0.txt
├── 2.25.0.txt
├── 2.26.0.txt
├── 2.27.0.txt
├── 2.28.0.txt
├── 2.3.0.txt
├── 2.30.0.txt
├── 2.31.0.txt
├── 2.34.0.txt
├── 2.36.0.txt
├── 2.38.0.txt
├── 2.39.0.txt
├── 2.4.0.txt
├── 2.41.0.txt
├── 2.42.0.txt
├── 2.5.0.txt
├── 2.6.0.txt
├── 2.7.0.txt
├── 2.8.0.txt
├── 2.9.0.txt
└── install.txt
├── pyproject.toml
├── requirements-dev.lock
├── requirements.lock
└── syntax
├── blame.sublime-settings
├── blame.sublime-syntax
├── branch.sublime-settings
├── branch.sublime-syntax
├── dashboard.sublime-syntax
├── diff.sublime-settings
├── diff.sublime-syntax
├── diff_view.sublime-settings
├── diff_view.sublime-syntax
├── graph.sublime-settings
├── graph.sublime-syntax
├── help.sublime-settings
├── help.sublime-syntax
├── make_commit.sublime-settings
├── make_commit.sublime-syntax
├── output_panel.sublime-settings
├── output_panel.sublime-syntax
├── rebase.sublime-settings
├── rebase.sublime-syntax
├── show_commit.sublime-settings
├── show_commit.sublime-syntax
├── show_commit_diffstat.sublime-syntax
├── status.sublime-settings
├── status.sublime-syntax
├── tags.sublime-settings
├── tags.sublime-syntax
└── test
├── syntax_test_blame.txt
├── syntax_test_branch.txt
├── syntax_test_dashboard.txt
├── syntax_test_diff.txt
├── syntax_test_graph.txt
├── syntax_test_graph_pick_axe.txt
├── syntax_test_make_commit.txt
├── syntax_test_output_panel.txt
├── syntax_test_rebase.txt
├── syntax_test_show_commit.txt
├── syntax_test_show_commit_with_stat.txt
├── syntax_test_status.txt
└── syntax_test_tags.txt
/.python-version:
--------------------------------------------------------------------------------
1 | 3.8
--------------------------------------------------------------------------------
/CONTRIBUTING.md:
--------------------------------------------------------------------------------
1 | # Contribute
2 |
3 | If you're interested in adding features, reporting/fixing bugs, or just discussing the future of GitSavvy, this is the place to start. Please feel free to reach out if you have questions or comments by opening an [issue](https://github.com/timbrel/GitSavvy/issues).
4 |
5 |
6 | ## Adding new features
7 |
8 | If there's a feature you'd like to see that isn't already in-progress or documented, there are two ways you can go about it:
9 |
10 | - open an issue for discussion; or
11 | - fork and submit a PR.
12 |
13 | Either way is fine, so long as you remember your PR may not be accepted as-is or at all. If a feature request is reasonable, though, it'll most likely be included one way or another.
14 |
15 | Some other things to remember:
16 |
17 | - Please respect the project layout and hierarchy, to keep things organized.
18 | - All Python code should be PEP8 compliant with few exceptions (e.g. imports in `__init__.py` files).
19 | - Include docstrings for all classes and functions, unless functionality is obvious at a glance.
20 | - Include descriptions for issues and PRs.
21 |
22 |
23 | ## Commit message structure
24 |
25 | Please follow the following commit message structure when submitting your pull request to GitSavvy:
26 |
27 | TYPE: Short commit message
28 |
29 | Detailed
30 | commit
31 | info
32 |
33 | For the value of **`TYPE`**, please use one of **`Feature`**, **`Enhancement`**, or **`Fix`**.
34 |
35 | This is done in order to help us automate tasks such as changelog generation.
36 |
37 |
38 | # Bugs
39 |
40 | If you encounter a bug, please check for an open issue that already captures the problem you've run into. If it doesn't exist yet, create it!
41 |
42 | Please include the following information when filing a bug:
43 |
44 | - Sublime Text version number
45 | - Git version number
46 | - OS type and version
47 | - Console error output
48 | - A description of the problem.
49 | - Steps to reproduce, if possible
50 | - If the bug is caused by a failing command, [include a debug log](docs/debug.md#providing-a-debug-log).
51 |
52 |
53 | # Documentation
54 |
55 | If you make changes, please remember to update the user documentation to reflect the new behavior.
56 |
57 |
58 | ## Package Testing
59 |
60 | Check the implementation details of the [tests](docs/testing.md).
61 |
62 | # Publishing
63 |
64 | Hotfixes should be submitted to `master` branch. As part of the PR process,
65 | you will be asked to provide the information necessary to make that happen.
66 |
67 | Pull requests on new features should be submitted to `dev` branch and will be
68 | regularly merged into `master` after evaluations over an extended period of
69 | time.
70 |
71 | # Issue Triage [](https://www.codetriage.com/divmain/gitsavvy)
72 |
73 | You can triage issues which may include reproducing bug reports or asking for vital information, such as version numbers or reproduction instructions. If you would like to start triaging issues, one easy way to get started is to [subscribe to gitsavvy on CodeTriage](https://www.codetriage.com/divmain/gitsavvy).
74 |
--------------------------------------------------------------------------------
/Context.sublime-menu:
--------------------------------------------------------------------------------
1 | [
2 | {
3 | "caption": "GitSavvy: Line History",
4 | "command": "gs_ctx_line_history"
5 | },
6 | {
7 | "caption": "GitSavvy: Pick-axe",
8 | "command": "gs_ctx_pick_axe"
9 | },
10 | {
11 | "caption": "GitSavvy: Stage selected hunk",
12 | "command": "gs_ctx_stage_hunk"
13 | }
14 | // {
15 | // "caption": " ...",
16 | // "children": [
17 | // {
18 | // "caption": "Repo History",
19 | // "command": "gs_graph",
20 | // "args": { "all": true }
21 | // },
22 | // {
23 | // "caption": "Path History",
24 | // "command": "gs_graph_current_path"
25 | // },
26 | // {
27 | // "caption": "File History",
28 | // "command": "gs_graph_current_file",
29 | // "args": { "all": false }
30 | // },
31 | // { "caption": "-" },
32 | // {
33 | // "caption": "Show current file revision at HEAD",
34 | // "command": "gs_show_file_at_commit"
35 | // },
36 | // ]
37 | // },
38 | ]
39 |
--------------------------------------------------------------------------------
/GitSavvy.sublime-project:
--------------------------------------------------------------------------------
1 | {
2 | "build_systems":
3 | [
4 | {
5 | "name": "Reload GitSavvy",
6 | "target": "gs_reload_modules_debug",
7 | },
8 | {
9 | "name": "Test GitSavvy",
10 | "target": "unit_testing_current_package",
11 | }
12 | ],
13 | "folders":
14 | [
15 | {
16 | "folder_exclude_patterns":
17 | [
18 | ".git",
19 | "__pycache__"
20 | ],
21 | "path": ".",
22 | }
23 | ],
24 | "settings":
25 | {
26 | "GitSavvy":
27 | {
28 | },
29 | "SublimeLinter.linters.mypy.excludes": ["*/tests/*"],
30 | "rulers":
31 | [
32 | 100,
33 | 120
34 | ],
35 | "tab_size": 4,
36 | "translate_tabs_to_spaces": true,
37 | "SublimeLinter.linters.ruff.disable": true,
38 | "SublimeLinter.linters.ruff-lsp.disable": true,
39 | },
40 | }
41 |
--------------------------------------------------------------------------------
/GitSavvy.tmPreferences:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | name
6 | Symbol List
7 | scope
8 | gitsavvy.gotosymbol
9 | settings
10 |
11 | showInSymbolList
12 | 1
13 |
14 |
15 |
16 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | The MIT License (MIT)
2 |
3 | Copyright (c) 2015 Dale Bustad
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy
6 | of this software and associated documentation files (the "Software"), to deal
7 | in the Software without restriction, including without limitation the rights
8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | copies of the Software, and to permit persons to whom the Software is
10 | furnished to do so, subject to the following conditions:
11 |
12 | The above copyright notice and this permission notice shall be included in
13 | all copies or substantial portions of the Software.
14 |
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
21 | THE SOFTWARE.
--------------------------------------------------------------------------------
/Main.sublime-menu:
--------------------------------------------------------------------------------
1 | [
2 | {
3 | "id": "preferences",
4 | "children": [
5 | {
6 | "caption": "Package Settings",
7 | "mnemonic": "P",
8 | "id": "package-settings",
9 | "children": [
10 | {
11 | "caption": "GitSavvy",
12 | "children": [
13 | {
14 | "caption": "Settings",
15 | "command": "edit_settings",
16 | "args": {
17 | "base_file": "${packages}/GitSavvy/GitSavvy.sublime-settings",
18 | "default": "// Settings in here override those in \"GitSavvy/GitSavvy.sublime-settings\",\n\n{\n\t$0\n}\n"
19 | }
20 | }, {
21 | "caption": "Key Bindings",
22 | "command": "edit_settings",
23 | "args": {
24 | "base_file": "${packages}/GitSavvy/Default (${platform}).sublime-keymap"
25 | }
26 | }
27 | ]
28 | }
29 | ]
30 | }
31 | ]
32 | }
33 | ]
34 |
--------------------------------------------------------------------------------
/common/__init__.py:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/timbrel/GitSavvy/f0c9067eb061498ba7a07960e5cbaefb414b4994/common/__init__.py
--------------------------------------------------------------------------------
/common/commands/__init__.py:
--------------------------------------------------------------------------------
1 | from .debug import *
2 | from .view_manipulation import *
3 | from .help import *
4 |
--------------------------------------------------------------------------------
/common/commands/debug.py:
--------------------------------------------------------------------------------
1 | """
2 | Sublime commands related to development and debugging.
3 | """
4 |
5 | from sublime_plugin import WindowCommand
6 |
7 | from ..util import debug, reload
8 | from ...core.settings import GitSavvySettings
9 | from ...core.view import replace_view_content
10 |
11 |
12 | __all__ = (
13 | "gs_reload_modules_debug",
14 | "gs_start_logging",
15 | "gs_stop_logging",
16 | "gs_view_git_log",
17 | )
18 |
19 |
20 | class gs_reload_modules_debug(WindowCommand):
21 |
22 | """
23 | When triggered, reload all GitSavvy submodules.
24 | """
25 |
26 | def run(self):
27 | reload.reload_plugin()
28 |
29 | def is_visible(self):
30 | return GitSavvySettings().get("dev_mode")
31 |
32 |
33 | class gs_start_logging(WindowCommand):
34 |
35 | """
36 | Starts recording all interactions with Git for reporting issues.
37 | """
38 |
39 | def run(self):
40 | debug.start_logging()
41 |
42 |
43 | class gs_stop_logging(WindowCommand):
44 |
45 | """
46 | Stops recording interactions with Git.
47 | """
48 |
49 | def run(self):
50 | debug.stop_logging()
51 |
52 |
53 | class gs_view_git_log(WindowCommand):
54 |
55 | """
56 | Displays the recent recording.
57 | """
58 |
59 | def run(self):
60 | log = debug.get_log()
61 | view = self.window.new_file()
62 | view.set_scratch(True)
63 | view.settings().set("syntax", "Packages/JavaScript/JSON.sublime-syntax")
64 | replace_view_content(view, log)
65 |
--------------------------------------------------------------------------------
/common/commands/view_manipulation.py:
--------------------------------------------------------------------------------
1 | from sublime_plugin import TextCommand
2 | from ...core.git_command import GitCommand
3 |
4 |
5 | __all__ = (
6 | "gs_handle_vintageous",
7 | "gs_handle_arrow_keys"
8 | )
9 |
10 |
11 | class gs_handle_vintageous(TextCommand, GitCommand):
12 |
13 | """
14 | Set the vintageous_friendly view setting if needed.
15 | Enter insert mode if vintageous_enter_insert_mode option is enabled.
16 | """
17 |
18 | def run(self, edit):
19 | if self.savvy_settings.get("vintageous_friendly"):
20 | self.view.settings().set("git_savvy.vintageous_friendly", True)
21 | if self.savvy_settings.get("vintageous_enter_insert_mode"):
22 | self.view.settings().set("vintageous_reset_mode_when_switching_tabs", False)
23 | # NeoVintageous renamed the command starting with v1.22.0.
24 | # We call both commands for backwards compatibility.
25 | self.view.run_command("_enter_insert_mode")
26 | self.view.run_command("nv_enter_insert_mode") # since NeoVintageous 1.22.0
27 |
28 |
29 | class gs_handle_arrow_keys(TextCommand, GitCommand):
30 |
31 | """
32 | Set the arrow_keys_navigation view setting if needed.
33 | It allows navigation by using arrow keys.
34 | """
35 |
36 | def run(self, edit):
37 | if self.savvy_settings.get("arrow_keys_navigation"):
38 | self.view.settings().set("git_savvy.arrow_keys_navigation", True)
39 |
--------------------------------------------------------------------------------
/common/util/__init__.py:
--------------------------------------------------------------------------------
1 | import sys
2 |
3 | from .parse_diff import parse_diff
4 | from . import dates
5 | from . import view
6 | from . import file
7 | from . import log
8 | from . import actions
9 | from . import debug
10 | from . import diff_string
11 | from . import reload
12 |
13 | super_key = "super" if sys.platform == "darwin" else "ctrl"
14 |
--------------------------------------------------------------------------------
/common/util/actions.py:
--------------------------------------------------------------------------------
1 | from functools import wraps
2 |
3 | import sublime
4 |
5 | from ...core.settings import GitSavvySettings
6 |
7 | from typing import Callable, Optional, TypeVar, TYPE_CHECKING
8 | T = TypeVar('T')
9 |
10 | if TYPE_CHECKING:
11 | from typing_extensions import ParamSpec
12 | P = ParamSpec('P')
13 |
14 |
15 | def destructive(description: str) -> "Callable[[Callable[P, T]], Callable[P, Optional[T]]]":
16 | def decorator(fn: "Callable[P, T]") -> "Callable[P, Optional[T]]":
17 | @wraps(fn)
18 | def wrapped_fn(*args: "P.args", **kwargs: "P.kwargs") -> Optional[T]:
19 | if GitSavvySettings().get("prompt_before_destructive_action"):
20 | message = (
21 | "You are about to {desc}. "
22 | "This is a destructive action. \n\n"
23 | "Are you SURE you want to do this? \n\n"
24 | "(you can disable this prompt in "
25 | "GitSavvy settings)").format(desc=description)
26 | if not sublime.ok_cancel_dialog(message):
27 | return None
28 |
29 | return fn(*args, **kwargs)
30 | return wrapped_fn
31 | return decorator
32 |
--------------------------------------------------------------------------------
/common/util/dates.py:
--------------------------------------------------------------------------------
1 | from datetime import datetime
2 |
3 | TEN_MINS = 600
4 | ONE_HOUR = 3600
5 | TWO_HOURS = 7200
6 | ONE_DAY = 86400
7 |
8 |
9 | def fuzzy(event, base=None, date_format=None):
10 | if not base:
11 | base = datetime.now()
12 |
13 | if date_format:
14 | event = datetime.strptime(event, date_format)
15 | elif type(event) == str:
16 | event = datetime.fromtimestamp(int(event))
17 | elif type(event) == int:
18 | event = datetime.fromtimestamp(event)
19 | elif type(event) != datetime:
20 | raise Exception(
21 | "Cannot convert object `{}` to fuzzy date string".format(event))
22 |
23 | delta = base - event
24 |
25 | if delta.days == 0:
26 | if delta.seconds < 60:
27 | return "{} seconds ago".format(delta.seconds)
28 |
29 | elif delta.seconds < 120:
30 | return "1 min and {} secs ago".format(delta.seconds - 60)
31 |
32 | elif delta.seconds < TEN_MINS:
33 | return "{} mins and {} secs ago".format(
34 | delta.seconds // 60,
35 | delta.seconds % 60)
36 |
37 | elif delta.seconds < ONE_HOUR:
38 | return "{} minutes ago".format(delta.seconds // 60)
39 |
40 | elif delta.seconds < TWO_HOURS:
41 | return "1 hour and {} mins ago".format(
42 | delta.seconds % ONE_HOUR // 60)
43 |
44 | return "over {} hours ago".format(delta.seconds // ONE_HOUR)
45 |
46 | elif delta.days < 2:
47 | return "over a day ago"
48 |
49 | elif delta.days < 7:
50 | return "over {} days ago".format(delta.days)
51 |
52 | return "{date:%b} {date.day}, {date.year}".format(date=event)
53 |
--------------------------------------------------------------------------------
/common/util/diff_string.py:
--------------------------------------------------------------------------------
1 | import re
2 | from difflib import SequenceMatcher
3 | from collections import namedtuple
4 |
5 | Change = namedtuple("Change", (
6 | "type",
7 | "old_start",
8 | "old_end",
9 | "new_start",
10 | "new_end"
11 | ))
12 | REPLACE = "replace"
13 | DELETE = "delete"
14 | INSERT = "insert"
15 |
16 |
17 | boundary = re.compile(r"(\W)")
18 |
19 |
20 | def get_indices(chunks):
21 | idx = 0
22 | indices = []
23 | for chunk in chunks:
24 | indices.append(idx)
25 | idx += len(chunk)
26 | indices.append(idx)
27 | return indices
28 |
29 |
30 | def get_changes(old, new):
31 | # if one of the inputs, either old or new is more then 10 000 characters
32 | # we skip trying to find the words which changed. If a hunk is more than
33 | # 10 000 characters it is most likely a generated change.
34 | # We skip since this calculation take a lot of time then it gets bigger.
35 | if max(len(old), len(new)) > 10000:
36 | return []
37 |
38 | old_chunks = tuple(filter(lambda x: x, boundary.split(old)))
39 | new_chunks = tuple(filter(lambda x: x, boundary.split(new)))
40 | old_indices = get_indices(old_chunks)
41 | new_indices = get_indices(new_chunks)
42 |
43 | matcher = SequenceMatcher(a=old_chunks, b=new_chunks, autojunk=False)
44 |
45 | if matcher.quick_ratio() < 0.75 or matcher.ratio() < 0.75:
46 | return []
47 |
48 | return [Change(change_type, old_indices[os], old_indices[oe], new_indices[ns], new_indices[ne])
49 | for change_type, os, oe, ns, ne in matcher.get_opcodes()
50 | if not change_type == "equal"]
51 |
--------------------------------------------------------------------------------
/common/util/file.py:
--------------------------------------------------------------------------------
1 | from contextlib import contextmanager
2 | import os
3 |
4 | import sublime
5 |
6 | from GitSavvy.core.fns import maybe
7 | from typing import Dict
8 |
9 |
10 | syntax_file_map = {} # type: Dict[str, str]
11 |
12 |
13 | def guess_syntax_for_file(window, filename):
14 | # type: (sublime.Window, str) -> str
15 | view = window.find_open_file(filename)
16 | if view:
17 | syntax = view.settings().get("syntax")
18 | remember_syntax_choice(filename, syntax)
19 | return syntax
20 | return get_syntax_for_file(filename)
21 |
22 |
23 | def remember_syntax_choice(filename, syntax):
24 | # type: (str, str) -> None
25 | syntax_file_map[get_file_extension(filename) or filename] = syntax
26 |
27 |
28 | def get_syntax_for_file(filename, default="Packages/Text/Plain text.tmLanguage"):
29 | # type: (str, str) -> str
30 | return (
31 | syntax_file_map.get(filename)
32 | or syntax_file_map.get(get_file_extension(filename))
33 | or maybe(lambda: sublime.find_syntax_for_file(filename).path) # type: ignore[union-attr]
34 | or default
35 | )
36 |
37 |
38 | def get_file_extension(filename):
39 | # type: (str) -> str
40 | return os.path.splitext(filename)[1][1:]
41 |
42 |
43 | def get_file_contents_binary(repo_path, file_path):
44 | """
45 | Given an absolute file path, return the binary contents of that file
46 | as a string.
47 | """
48 | file_path = os.path.join(repo_path, file_path)
49 | with safe_open(file_path, "rb") as f:
50 | binary = f.read()
51 | binary = binary.replace(b"\r\n", b"\n")
52 | binary = binary.replace(b"\r", b"")
53 | return binary
54 |
55 |
56 | def get_file_contents(repo_path, file_path):
57 | """
58 | Given an absolute file path, return the text contents of that file
59 | as a string.
60 | """
61 | binary = get_file_contents_binary(repo_path, file_path)
62 | try:
63 | return binary.decode('utf-8')
64 | except UnicodeDecodeError:
65 | return binary.decode('latin-1')
66 |
67 |
68 | @contextmanager
69 | def safe_open(filename, mode, *args, **kwargs):
70 | try:
71 | with open(filename, mode, *args, **kwargs) as file:
72 | yield file
73 | except PermissionError as e:
74 | sublime.ok_cancel_dialog("GitSavvy could not access file: \n{}".format(e))
75 | raise e
76 | except OSError as e:
77 | sublime.ok_cancel_dialog("GitSavvy encountered an OS error: \n{}".format(e))
78 | raise e
79 |
--------------------------------------------------------------------------------
/common/util/log.py:
--------------------------------------------------------------------------------
1 | import re
2 | import sublime
3 |
4 | from GitSavvy.core.view import replace_view_content
5 |
6 | from typing import Optional
7 |
8 |
9 | PANEL_NAME = "GitSavvy"
10 | ANSI_ESCAPE_RE = re.compile(r'\x1B\[[0-?]*[ -/]*[@-~]')
11 |
12 |
13 | def normalize(string):
14 | # type: (str) -> str
15 | return ANSI_ESCAPE_RE.sub('', string.replace('\r\n', '\n').replace('\r', '\n'))
16 |
17 |
18 | def init_panel(window):
19 | # type: (sublime.Window) -> sublime.View
20 | panel_view = create_panel(window)
21 | show_panel(window)
22 | return panel_view
23 |
24 |
25 | def display_panel(window, message):
26 | # type: (sublime.Window, str) -> sublime.View
27 | panel_view = init_panel(window)
28 | append_to_panel(panel_view, message)
29 | panel_view.show(0)
30 | return panel_view
31 |
32 |
33 | def ensure_panel(window):
34 | # type: (sublime.Window) -> sublime.View
35 | return get_panel(window) or create_panel(window)
36 |
37 |
38 | def get_panel(window):
39 | # type: (sublime.Window) -> Optional[sublime.View]
40 | return window.find_output_panel(PANEL_NAME)
41 |
42 |
43 | def create_panel(window):
44 | # type: (sublime.Window) -> sublime.View
45 | panel_view = window.create_output_panel(PANEL_NAME)
46 | panel_view.set_syntax_file("Packages/GitSavvy/syntax/output_panel.sublime-syntax")
47 | return panel_view
48 |
49 |
50 | def show_panel(window):
51 | # type: (sublime.Window) -> None
52 | window.run_command("show_panel", {"panel": "output.{}".format(PANEL_NAME)})
53 |
54 |
55 | def append_to_panel(panel, message):
56 | # type: (sublime.View, str) -> None
57 | # We support standard progress bars with "\r" line endings!
58 | # If we see such a line ending, we remember where we started
59 | # our write as `virtual_cursor` as this is where the next
60 | # write must begin.
61 | has_trailing_carriage_return = message.endswith("\r")
62 | message = normalize(message)
63 |
64 | eof = panel.size()
65 | cursor = panel.settings().get("virtual_cursor") or eof
66 | region = sublime.Region(cursor, eof)
67 | replace_view_content(panel, message, region=region)
68 | panel.settings().set("virtual_cursor", cursor if has_trailing_carriage_return else None)
69 |
70 | eof_after_append = panel.size()
71 | panel.show(eof_after_append)
72 |
--------------------------------------------------------------------------------
/common/util/parse_diff.py:
--------------------------------------------------------------------------------
1 | """
2 | Parse and process output from `git diff` command.
3 | """
4 |
5 | from GitSavvy.core.parse_diff import HunkLine, SplittedDiff
6 |
7 | from typing import Iterator, List, NamedTuple
8 | from GitSavvy.core.types import LineNo
9 |
10 |
11 | class Change(NamedTuple):
12 | raw: str
13 | type: str
14 | head_pos: LineNo
15 | saved_pos: LineNo
16 | text: str
17 |
18 |
19 | class Hunk(NamedTuple):
20 | raw_lines: List[str]
21 | changes: List[Change]
22 | head_start: LineNo
23 | head_length: int
24 | saved_start: LineNo
25 | saved_length: int
26 |
27 |
28 | def parse_diff(diff_str):
29 | # type: (str) -> List[Hunk]
30 | """
31 | Given the string output from a `git diff` command, parse the string into
32 | hunks and, more granularly, meta-data and change information for each of
33 | those hunks.
34 | """
35 | hunks = []
36 | for hunk in SplittedDiff.from_string(diff_str).hunks:
37 | head_start, head_length, saved_start, saved_length = hunk.header().parse()
38 | changes = _get_changes(hunk.content().lines(), head_start, saved_start)
39 | # Remove lines warning about "No newline at end of file"; change.type will == `\`.
40 | changes_filtered = [change for change in changes if change.type != "\\"]
41 | hunks.append(
42 | Hunk(
43 | hunk.text.splitlines(keepends=True),
44 | changes_filtered,
45 | head_start,
46 | head_length,
47 | saved_start,
48 | saved_length
49 | )
50 | )
51 |
52 | return hunks
53 |
54 |
55 | def _get_changes(hunk_lines, head_start, saved_start):
56 | # type: (List[HunkLine], LineNo, LineNo) -> Iterator[Change]
57 | """
58 | Transform a list of `+` or `-` lines from a `git diff` output
59 | into tuples with the original raw line, the type of the change,
60 | the position of the HEAD- and saved- versions at that line, and
61 | the text of the line with the `+` or `-` removed.
62 | """
63 | head_pos = head_start
64 | saved_pos = saved_start
65 |
66 | for line in hunk_lines:
67 | yield Change(line.text, line.mode, head_pos, saved_pos, line.content)
68 | if line.is_from_line():
69 | head_pos += 1
70 | elif line.is_to_line():
71 | saved_pos += 1
72 |
--------------------------------------------------------------------------------
/core/__init__.py:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/timbrel/GitSavvy/f0c9067eb061498ba7a07960e5cbaefb414b4994/core/__init__.py
--------------------------------------------------------------------------------
/core/commands/__init__.py:
--------------------------------------------------------------------------------
1 | from .amend import *
2 | from .blame import *
3 | from .branch import *
4 | from .changelog import *
5 | from .checkout import *
6 | from .cherry_pick import *
7 | from .commit import *
8 | from .commit_compare import *
9 | from .config import *
10 | from .context_menu import *
11 | from .custom import *
12 | from .diff import *
13 | from .fetch import *
14 | from .fixup import *
15 | from .flow import *
16 | from .help_panel import *
17 | from .ignore import *
18 | from .init import *
19 | from .inline_diff import *
20 | from .line_history import *
21 | from .log import *
22 | from .log_graph import *
23 | from .log_graph_rebase_actions import *
24 | from .log_graph_smart_copy import *
25 | from .merge import *
26 | from .mv import *
27 | from .navigate import *
28 | from .next_hunk import *
29 | from .pull import *
30 | from .push import *
31 | from .quick_commit import *
32 | from .quick_stage import *
33 | from .reflog import *
34 | from .remote import *
35 | from .reset import *
36 | from .revert import *
37 | from .show_commit import *
38 | from .show_commit_info import *
39 | from .show_file_at_commit import *
40 | from .stage_diff import *
41 | from .stage_hunk import *
42 | from .stash import *
43 | from .status_bar import *
44 | from .tag import *
45 |
--------------------------------------------------------------------------------
/core/commands/amend.py:
--------------------------------------------------------------------------------
1 | from sublime_plugin import WindowCommand
2 |
3 | from ..git_command import GitCommand
4 |
5 |
6 | __all__ = (
7 | "gs_amend",
8 | "gs_quick_stage_current_file_and_amend",
9 | )
10 |
11 |
12 | class gs_amend(WindowCommand, GitCommand):
13 | def run(self):
14 | self.window.run_command("gs_commit", {"amend": True})
15 |
16 |
17 | class gs_quick_stage_current_file_and_amend(gs_amend, GitCommand):
18 | def run(self):
19 | file_path = self.file_path
20 | if not file_path:
21 | self.window.status_message("Cannot staged unnamed buffer.")
22 | return
23 |
24 | self.git("add", "--", file_path)
25 | self.window.status_message("staged {}".format(self.get_rel_path(file_path)))
26 | super().run()
27 |
--------------------------------------------------------------------------------
/core/commands/cherry_pick.py:
--------------------------------------------------------------------------------
1 | import sublime
2 |
3 | from .log import gs_log_by_branch
4 | from ...common import util
5 | from GitSavvy.core.base_commands import GsWindowCommand
6 | from GitSavvy.core.runtime import on_worker
7 |
8 |
9 | __all__ = (
10 | "gs_cherry_pick",
11 | "gs_cherry_pick_abort",
12 | "gs_cherry_pick_continue",
13 | "gs_cherry_pick_skip",
14 | )
15 |
16 |
17 | class gs_cherry_pick(gs_log_by_branch):
18 |
19 | def log(self, **kwargs): # type: ignore[override]
20 | kwargs["cherry"] = True
21 | kwargs["start_end"] = ("", kwargs["branch"])
22 | return super().log(**kwargs)
23 |
24 | def do_action(self, commit_hash, **kwargs):
25 | self.git("cherry-pick", commit_hash)
26 | sublime.active_window().status_message("Commit %s cherry-picked successfully." % commit_hash)
27 | util.view.refresh_gitsavvy(self.window.active_view())
28 |
29 |
30 | class gs_cherry_pick_abort(GsWindowCommand):
31 | @on_worker
32 | def run(self):
33 | self.git("cherry-pick", "--abort")
34 | util.view.refresh_gitsavvy_interfaces(self.window, refresh_sidebar=True)
35 |
36 |
37 | class gs_cherry_pick_continue(GsWindowCommand):
38 | @on_worker
39 | def run(self):
40 | self.git("cherry-pick", "--continue")
41 | util.view.refresh_gitsavvy_interfaces(self.window, refresh_sidebar=True)
42 |
43 |
44 | class gs_cherry_pick_skip(GsWindowCommand):
45 | @on_worker
46 | def run(self):
47 | self.git("cherry-pick", "--skip")
48 | util.view.refresh_gitsavvy_interfaces(self.window, refresh_sidebar=True)
49 |
--------------------------------------------------------------------------------
/core/commands/config.py:
--------------------------------------------------------------------------------
1 | import sublime_plugin
2 |
3 | import os
4 |
5 | from GitSavvy.core.git_command import GitCommand
6 |
7 |
8 | __all__ = (
9 | "gs_open_repo_config",
10 | "gs_open_repo_exclude",
11 | )
12 |
13 |
14 | class gs_open_repo_config(sublime_plugin.WindowCommand, GitCommand):
15 | def run(self) -> None:
16 | try:
17 | repo_path = self.get_repo_path()
18 | except ValueError:
19 | self.window.status_message("No .git repo found")
20 | return
21 |
22 | wanted_file = os.path.join(repo_path, '.git', 'config')
23 | if not os.path.exists(wanted_file):
24 | self.window.status_message("No config file found for {}".format(repo_path))
25 | return
26 |
27 | self.window.open_file(wanted_file)
28 |
29 |
30 | class gs_open_repo_exclude(sublime_plugin.WindowCommand, GitCommand):
31 | def run(self) -> None:
32 | try:
33 | repo_path = self.get_repo_path()
34 | except ValueError:
35 | self.window.status_message("No .git repo found")
36 | return
37 |
38 | wanted_file = os.path.join(repo_path, '.git', 'info', 'exclude')
39 | if not os.path.exists(wanted_file):
40 | self.window.status_message("No exclude file found for {}".format(repo_path))
41 | return
42 |
43 | self.window.open_file(wanted_file)
44 |
--------------------------------------------------------------------------------
/core/commands/context_menu.py:
--------------------------------------------------------------------------------
1 | from functools import lru_cache
2 |
3 | import sublime
4 |
5 | from GitSavvy.core.base_commands import GsTextCommand
6 |
7 | from typing import Callable, List, Optional, TypeVar
8 | T = TypeVar("T")
9 |
10 | __all__ = (
11 | "gs_ctx_line_history",
12 | "gs_ctx_pick_axe",
13 | "gs_ctx_stage_hunk",
14 | )
15 |
16 |
17 | # Provide a `CommandContext` as the global `Context` which
18 | # is valid for this exact "runtime-task". This is to speed-up
19 | # the preconditions in `is_enabled` and `is_visible`.
20 |
21 | def cached_property(fn: Callable[..., T]) -> T:
22 | return property(lru_cache(1)(fn)) # type: ignore[return-value]
23 |
24 |
25 | class CommandContext:
26 | def __init__(self, cmd: GsTextCommand):
27 | self._cmd = cmd
28 |
29 | @cached_property
30 | def enabled(self) -> bool:
31 | return not self._cmd.savvy_settings.get("disable_context_menus")
32 |
33 | @cached_property
34 | def sel(self) -> List[sublime.Region]:
35 | return list(self._cmd.view.sel())
36 |
37 | @cached_property
38 | def repo_path(self) -> Optional[str]:
39 | return self._cmd.find_repo_path()
40 |
41 | @cached_property
42 | def file_path(self) -> Optional[str]:
43 | return self._cmd.file_path
44 |
45 |
46 | Context = None
47 |
48 |
49 | def get_context(self) -> CommandContext:
50 | global Context
51 | if not Context:
52 | Context = CommandContext(self)
53 | sublime.set_timeout(reset_context)
54 |
55 | return Context
56 |
57 |
58 | def reset_context():
59 | global Context
60 | Context = None
61 |
62 |
63 | class gs_ctx_line_history(GsTextCommand):
64 | def is_enabled(self) -> bool:
65 | ctx = get_context(self)
66 | return bool(
67 | ctx.sel
68 | and ctx.repo_path
69 | )
70 |
71 | def is_visible(self) -> bool:
72 | ctx = get_context(self)
73 | return ctx.enabled and bool(ctx.repo_path)
74 |
75 | def run(self, edit) -> None:
76 | self.view.run_command("gs_line_history")
77 |
78 |
79 | class gs_ctx_stage_hunk(GsTextCommand):
80 | def is_enabled(self) -> bool:
81 | ctx = get_context(self)
82 | return bool(
83 | ctx.sel
84 | and ctx.repo_path
85 | and self.view.file_name()
86 | and not self.view.is_dirty()
87 | )
88 |
89 | def is_visible(self) -> bool:
90 | ctx = get_context(self)
91 | return ctx.enabled and bool(ctx.repo_path)
92 |
93 | def run(self, edit) -> None:
94 | self.view.run_command("gs_stage_hunk")
95 |
96 |
97 | class gs_ctx_pick_axe(GsTextCommand):
98 | def is_enabled(self) -> bool:
99 | ctx = get_context(self)
100 | return bool(
101 | ctx.sel
102 | and ctx.repo_path
103 | and all(self.view.substr(r).strip() for r in ctx.sel)
104 | )
105 |
106 | def is_visible(self) -> bool:
107 | ctx = get_context(self)
108 | return ctx.enabled and bool(ctx.repo_path)
109 |
110 | def run(self, edit) -> None:
111 | self.view.run_command("gs_graph_pickaxe")
112 |
--------------------------------------------------------------------------------
/core/commands/custom.py:
--------------------------------------------------------------------------------
1 | import sublime
2 | from sublime_plugin import WindowCommand
3 |
4 | from ..git_command import GitCommand
5 | from ..runtime import enqueue_on_worker
6 | from ..ui_mixins.input_panel import show_single_line_input_panel
7 | from ..view import replace_view_content
8 | from ...common import util
9 | from GitSavvy.core.runtime import run_new_daemon_thread
10 |
11 |
12 | __all__ = (
13 | "gs_custom",
14 | )
15 |
16 |
17 | class gs_custom(WindowCommand, GitCommand):
18 |
19 | """
20 | Run the specified custom command asynchronously.
21 | """
22 |
23 | def run(self, **kwargs):
24 | args = kwargs.get('args')
25 | if not args:
26 | sublime.error_message("Custom command must provide args.")
27 | return
28 |
29 | # prompt for custom command argument
30 | if '{PROMPT_ARG}' in args:
31 | prompt_msg = kwargs.pop("prompt_msg", "Command argument: ")
32 | return show_single_line_input_panel(
33 | prompt_msg,
34 | "",
35 | lambda arg: self.run_impl(custom_argument=arg, **kwargs)
36 | )
37 |
38 | self.run_impl(**kwargs)
39 |
40 | def run_impl(
41 | self,
42 | output_to_panel=False,
43 | output_to_buffer=False,
44 | args=None,
45 | start_msg="Starting custom command...",
46 | complete_msg="Completed custom command.",
47 | syntax=None,
48 | run_in_thread=False,
49 | custom_argument=None,
50 | custom_environ=None,
51 | ):
52 |
53 | for idx, arg in enumerate(args):
54 | if arg == "{REPO_PATH}":
55 | args[idx] = self.repo_path
56 | elif arg == "{FILE_PATH}":
57 | args[idx] = self.file_path
58 | elif arg == "{PROMPT_ARG}":
59 | args[idx] = custom_argument
60 |
61 | def program():
62 | self.window.status_message(start_msg)
63 | stdout = self.git(*args, custom_environ=custom_environ)
64 | self.window.status_message(complete_msg)
65 |
66 | if output_to_panel:
67 | util.log.display_panel(self.window, stdout)
68 | if output_to_buffer:
69 | view = self.window.new_file()
70 | view.set_scratch(True)
71 | if syntax:
72 | view.set_syntax_file(syntax)
73 | replace_view_content(view, stdout.replace("\r", "\n"))
74 |
75 | util.view.refresh_gitsavvy_interfaces(self.window)
76 |
77 | if run_in_thread:
78 | run_new_daemon_thread(program)
79 | else:
80 | enqueue_on_worker(program)
81 |
--------------------------------------------------------------------------------
/core/commands/fetch.py:
--------------------------------------------------------------------------------
1 | from ..runtime import on_worker
2 | from ...common import util
3 | from ..ui_mixins.quick_panel import show_remote_panel
4 | from GitSavvy.core.base_commands import ask_for_branch, GsWindowCommand
5 |
6 |
7 | __all__ = (
8 | "gs_fetch",
9 | "gs_ff_update_branch"
10 | )
11 |
12 |
13 | from GitSavvy.core.base_commands import Args, GsCommand, Kont
14 |
15 |
16 | def ask_for_remote(cmd, args, done):
17 | # type: (GsCommand, Args, Kont) -> None
18 | show_remote_panel(done, allow_direct=True, show_option_all=True)
19 |
20 |
21 | class gs_fetch(GsWindowCommand):
22 | """
23 | Display a panel of all git remotes for active repository and
24 | do a `git fetch` asynchronously.
25 | """
26 | defaults = {
27 | "remote": ask_for_remote
28 | }
29 |
30 | @on_worker
31 | def run(self, remote, refspec=None):
32 | fetch_all = remote == ""
33 | if fetch_all:
34 | self.window.status_message("Start fetching all remotes...")
35 | else:
36 | self.window.status_message("Start fetching {}...".format(remote))
37 |
38 | self.fetch(None if fetch_all else remote, refspec)
39 | self.window.status_message("Fetch complete.")
40 | util.view.refresh_gitsavvy_interfaces(self.window)
41 |
42 |
43 | class gs_ff_update_branch(GsWindowCommand):
44 | defaults = {
45 | "branch": ask_for_branch(local_branches_only=True)
46 | }
47 |
48 | @on_worker
49 | def run(self, branch):
50 | local_branch = self.get_local_branch_by_name(branch)
51 | if not local_branch:
52 | raise RuntimeError(
53 | "repo and view inconsistent. "
54 | "can't fetch more info about branch {}"
55 | .format(branch)
56 | )
57 |
58 | if not local_branch.upstream:
59 | self.window.status_message("{} has no upstream set.".format(branch))
60 | return
61 |
62 | self.window.run_command("gs_fetch", {
63 | "remote": local_branch.upstream.remote,
64 | "refspec": "{}:{}".format(local_branch.upstream.branch, branch)
65 | })
66 |
--------------------------------------------------------------------------------
/core/commands/fixup.py:
--------------------------------------------------------------------------------
1 | import sublime
2 | import re
3 | from .log import gs_log_current_branch
4 | from ...common import util
5 |
6 | fixup_command = re.compile("^fixup! (.*)")
7 |
8 |
9 | class GsFixupFromStageCommand(gs_log_current_branch):
10 | def run(self): # type: ignore[override]
11 | status = self.get_working_dir_status()
12 | if status.unstaged_files or status.merge_conflicts:
13 | sublime.message_dialog(
14 | "Unable to perform rebase actions while repo is in unclean state."
15 | )
16 | return
17 | if not status.staged_files:
18 | sublime.message_dialog("No staged files.")
19 | return
20 | super().run()
21 |
22 | def auto_squash(self, commit_chain):
23 | fixup_idx = len(commit_chain) - 1
24 | msg = commit_chain[fixup_idx].msg
25 | m = fixup_command.match(msg)
26 | if m:
27 | orig_msg = m.group(1)
28 | orig_commit_indx = fixup_idx - 1
29 | while orig_commit_indx >= 0:
30 | if commit_chain[orig_commit_indx].msg.startswith(orig_msg):
31 | break
32 | orig_commit_indx = orig_commit_indx - 1
33 |
34 | if orig_commit_indx >= 0:
35 | commit_chain.insert(orig_commit_indx + 1, commit_chain.pop(fixup_idx))
36 | original_commit = commit_chain[orig_commit_indx]
37 | next_commit = commit_chain[orig_commit_indx + 1]
38 | original_commit.do_commit = False
39 | next_commit.msg = original_commit.msg
40 | next_commit.datetime = original_commit.datetime
41 | next_commit.author = original_commit.author
42 | next_commit.modified = True
43 |
44 | return commit_chain
45 |
46 | def do_action(self, commit_hash, **kwargs):
47 | commit = self.git("rev-parse", commit_hash).strip()
48 | self.git("commit", "--fixup", commit)
49 | try:
50 | base_commit = self.git("rev-parse", "{}~1".format(commit)).strip()
51 | entries = self.log_rebase(base_commit, preserve=True)
52 | commit_chain = self.auto_squash(self.perpare_rewrites(entries))
53 |
54 | self.rewrite_active_branch(base_commit, commit_chain)
55 | except Exception as e:
56 | self.git("reset", "--soft", "HEAD^")
57 | sublime.message_dialog("Error encountered. Cannot autosquash fixup.")
58 | raise e
59 | finally:
60 | util.view.refresh_gitsavvy(self.window.active_view())
61 |
62 |
63 | class GsQuickStageCurrentFileAndFixupCommand(GsFixupFromStageCommand):
64 | def run(self): # type: ignore[override]
65 | self.git("add", "--", self.file_path)
66 | super().run()
67 |
--------------------------------------------------------------------------------
/core/commands/merge.py:
--------------------------------------------------------------------------------
1 | from ...common import util
2 | from GitSavvy.core.base_commands import ask_for_branch, GsWindowCommand
3 | from GitSavvy.core.utils import show_noop_panel, show_panel
4 | from GitSavvy.core.runtime import on_worker
5 |
6 |
7 | __all__ = (
8 | "gs_merge",
9 | "gs_merge_abort",
10 | "gs_merge_continue",
11 | "gs_restart_merge_for_file",
12 | )
13 |
14 |
15 | class gs_merge(GsWindowCommand):
16 |
17 | """
18 | Display a list of branches available to merge against the active branch.
19 | When selected, perform merge with specified branch.
20 | """
21 |
22 | defaults = {
23 | "branch": ask_for_branch(ignore_current_branch=True, merged=False),
24 | }
25 |
26 | @on_worker
27 | def run(self, branch):
28 | try:
29 | self.git("merge", branch)
30 | finally:
31 | util.view.refresh_gitsavvy_interfaces(self.window, refresh_sidebar=True)
32 |
33 |
34 | class gs_merge_abort(GsWindowCommand):
35 |
36 | """
37 | Reset all files to pre-merge conditions, and abort the merge.
38 | """
39 |
40 | @on_worker
41 | def run(self):
42 | self.git("merge", "--abort")
43 | util.view.refresh_gitsavvy_interfaces(self.window, refresh_sidebar=True)
44 |
45 |
46 | class gs_merge_continue(GsWindowCommand):
47 |
48 | """
49 | Continue an ongoing merge. Here for completeness as a user could just commit
50 | as well.
51 | """
52 |
53 | @on_worker
54 | def run(self):
55 | self.git("merge", "--continue")
56 | util.view.refresh_gitsavvy_interfaces(self.window, refresh_sidebar=True)
57 |
58 |
59 | class gs_restart_merge_for_file(GsWindowCommand):
60 |
61 | """
62 | Reset a single file to pre-merge condition, but do not abort the merge.
63 | """
64 |
65 | def run(self):
66 | paths = self.conflicting_files_()
67 | if not paths:
68 | show_noop_panel(
69 | self.window, "There are no files which have or had merge conflicts."
70 | )
71 |
72 | def on_done(index):
73 | fpath = paths[index]
74 | self.git("checkout", "-m", "--", fpath)
75 |
76 | util.view.refresh_gitsavvy_interfaces(self.window)
77 |
78 | show_panel(self.window, paths, on_done)
79 |
--------------------------------------------------------------------------------
/core/commands/mv.py:
--------------------------------------------------------------------------------
1 | import functools
2 | import os
3 | import sublime
4 | from sublime_plugin import WindowCommand
5 |
6 | from ..git_command import GitCommand
7 | from ..ui_mixins.input_panel import show_single_line_input_panel
8 |
9 |
10 | class GsMvCurrentFileCommand(WindowCommand, GitCommand):
11 |
12 | """
13 | Prompt the user for a new name for the current file.
14 | """
15 |
16 | def run(self):
17 | if self.file_path:
18 | parent, base_name = os.path.split(self.file_path)
19 | on_done = functools.partial(
20 | self.on_done,
21 | self.file_path, parent, base_name)
22 | v = show_single_line_input_panel(
23 | "New Name:", base_name,
24 | on_done, None, None)
25 | name, ext = os.path.splitext(base_name)
26 | v.sel().clear()
27 | v.sel().add(sublime.Region(0, len(name)))
28 |
29 | def on_done(self, file_path, parent, base_name, new_name):
30 | if new_name == base_name:
31 | return
32 | new_path = os.path.join(parent, new_name)
33 |
34 | self.git("mv", file_path, new_path)
35 | v = self.window.find_open_file(file_path)
36 | if v:
37 | v.retarget(new_path)
38 |
--------------------------------------------------------------------------------
/core/commands/pull.py:
--------------------------------------------------------------------------------
1 | from ...common import util
2 | from GitSavvy.core.base_commands import GsWindowCommand, ask_for_branch
3 | from GitSavvy.core.fns import flatten, unique
4 | from GitSavvy.core.runtime import on_worker
5 |
6 | from typing import Callable, List, Optional, Sequence
7 | from ..git_mixins.branches import Branch
8 |
9 |
10 | __all__ = (
11 | "gs_pull",
12 | "gs_pull_from_branch",
13 | )
14 |
15 |
16 | class GsPullBase(GsWindowCommand):
17 | def do_pull(self, remote, remote_branch, rebase):
18 | # type: (str, str, Optional[bool]) -> None
19 | """
20 | Perform `git pull remote branch`.
21 | """
22 | self.window.status_message("Starting pull...")
23 | output = self.pull(remote, remote_branch, rebase).strip()
24 | self.window.status_message(
25 | output if output == "Already up to date." else "Pull complete."
26 | )
27 | util.view.refresh_gitsavvy(self.window.active_view())
28 |
29 |
30 | class gs_pull(GsPullBase):
31 | """
32 | Pull from remote tracking branch if it is found. Otherwise, use `gs_pull_from_branch`.
33 | """
34 |
35 | @on_worker
36 | def run(self, rebase=None):
37 | upstream = self.get_upstream_for_active_branch()
38 | if upstream:
39 | self.do_pull(upstream.remote, upstream.branch, rebase)
40 | else:
41 | self.window.run_command("gs_pull_from_branch", {"rebase": rebase})
42 |
43 |
44 | ask_for_branch_ = ask_for_branch(
45 | ask_remote_first=False,
46 | ignore_current_branch=True,
47 | memorize_key="last_branch_used_to_pull_from"
48 | )
49 |
50 |
51 | class gs_pull_from_branch(GsPullBase):
52 | """
53 | Through a series of panels, allow the user to pull from a branch.
54 | """
55 | defaults = {
56 | "branch": ask_for_branch_
57 | }
58 |
59 | @on_worker
60 | def run(self, branch, rebase=None):
61 | # type: (str, bool) -> None
62 | sources: Sequence[Callable[[], List[Branch]]] = (
63 | # Typically, `ask_for_branch_`s `show_branch_panel` has just called
64 | # `get_branches` so the cached value in the store should be fresh
65 | # and good to go.
66 | lambda: self.current_state().get("branches", []),
67 | self.get_branches,
68 | )
69 | branches = unique(flatten(getter() for getter in sources))
70 | for branch_ in branches:
71 | if branch_.canonical_name == branch:
72 | self.do_pull(branch_.remote or ".", branch_.name, rebase)
73 | break
74 | else:
75 | self.window.status_message(
76 | f"fatal: the name '{branch}' is not in the list of the current branches")
77 |
--------------------------------------------------------------------------------
/core/commands/quick_commit.py:
--------------------------------------------------------------------------------
1 | import sublime
2 | from sublime_plugin import WindowCommand
3 |
4 | from ..git_command import GitCommand
5 | from ...common import util
6 | from ..ui_mixins.input_panel import show_single_line_input_panel
7 |
8 |
9 | COMMIT_MSG_PROMPT = "Commit message:"
10 |
11 |
12 | class GsQuickCommitCommand(WindowCommand, GitCommand):
13 |
14 | """
15 | Present the user with a input panel where they can enter a commit message.
16 | Once provided, perform a commit with that message.
17 | """
18 |
19 | def run(self):
20 | show_single_line_input_panel(
21 | COMMIT_MSG_PROMPT,
22 | "",
23 | lambda msg: sublime.set_timeout_async(lambda: self.on_done(msg), 0)
24 | )
25 |
26 | def on_done(self, commit_message):
27 | self.window.status_message("Commiting...")
28 | self.git("commit", "-q", "-F", "-", stdin=commit_message)
29 | self.window.status_message("Committed successfully.")
30 | util.view.refresh_gitsavvy(self.window.active_view())
31 |
32 |
33 | class GsQuickStageCurrentFileCommitCommand(WindowCommand, GitCommand):
34 |
35 | """
36 | Present the user with a input panel where they can enter a commit message.
37 | Once provided, stage the current file and perform a commit with the
38 | provided message.
39 | """
40 |
41 | def run(self):
42 | show_single_line_input_panel(
43 | COMMIT_MSG_PROMPT,
44 | "",
45 | lambda msg: sublime.set_timeout_async(lambda: self.on_done(msg), 0)
46 | )
47 |
48 | def on_done(self, commit_message):
49 | self.window.status_message("Commiting...")
50 | self.git("add", "--", self.file_path)
51 | self.git("commit", "-q", "-F", "-", stdin=commit_message)
52 | self.window.status_message("Committed successfully.")
53 | util.view.refresh_gitsavvy(self.window.active_view())
54 |
--------------------------------------------------------------------------------
/core/commands/reflog.py:
--------------------------------------------------------------------------------
1 | import sublime
2 |
3 | from ..ui_mixins.quick_panel import show_paginated_panel
4 | from GitSavvy.core.base_commands import GsWindowCommand
5 |
6 |
7 | __all__ = (
8 | "gs_ref_log",
9 | )
10 |
11 |
12 | class RefLogMixin(GsWindowCommand):
13 |
14 | _limit = 6000
15 |
16 | def run(self):
17 | sublime.set_timeout_async(self.run_async)
18 |
19 | def run_async(self):
20 | show_paginated_panel(
21 | self.reflog_generator(limit=self._limit), self.on_done, limit=self._limit)
22 |
23 | def on_done(self, commit):
24 | if commit:
25 | self.do_action(commit)
26 |
27 | def do_action(self, commit_hash):
28 | self.window.run_command("gs_log_action", {
29 | "commit_hash": commit_hash
30 | })
31 |
32 |
33 | class gs_ref_log(RefLogMixin):
34 | pass
35 |
--------------------------------------------------------------------------------
/core/commands/remote.py:
--------------------------------------------------------------------------------
1 | import sublime
2 |
3 | from . import init
4 | from ...common import util
5 | from ..ui_mixins.quick_panel import show_remote_panel
6 | from ..ui_mixins.input_panel import show_single_line_input_panel
7 | from GitSavvy.core.runtime import run_on_new_thread
8 | from GitSavvy.core.base_commands import GsWindowCommand
9 |
10 |
11 | __all__ = (
12 | "gs_remote_add",
13 | "gs_remote_remove",
14 | "gs_remote_rename",
15 | )
16 |
17 |
18 | class gs_remote_add(GsWindowCommand):
19 | """
20 | Add remotes
21 | """
22 |
23 | def run(self, url=None, set_as_push_default=False):
24 | self.set_as_push_default = set_as_push_default
25 | if url:
26 | self.on_enter_remote(url)
27 | else:
28 | clip_content = sublime.get_clipboard(256).strip()
29 | show_single_line_input_panel(
30 | "Remote URL",
31 | init.parse_url_from_clipboard(clip_content),
32 | self.on_enter_remote)
33 |
34 | def on_enter_remote(self, input_url):
35 | self.url = input_url
36 | owner = self.username_from_url(input_url)
37 |
38 | show_single_line_input_panel("Remote name", owner, self.on_enter_name)
39 |
40 | def on_enter_name(self, remote_name):
41 | self.git("remote", "add", remote_name, self.url)
42 | if self.set_as_push_default:
43 | run_on_new_thread(self.git, "config", "--local", "gitsavvy.pushdefault", remote_name)
44 | self.update_store({"last_remote_used_for_push": remote_name})
45 |
46 | if self.savvy_settings.get("fetch_new_remotes", True) or sublime.ok_cancel_dialog(
47 | "Your remote was added successfully. "
48 | "Would you like to fetch from this remote?"
49 | ):
50 | self.window.run_command("gs_fetch", {"remote": remote_name})
51 |
52 |
53 | class gs_remote_remove(GsWindowCommand):
54 | """
55 | Remove remotes
56 | """
57 |
58 | def run(self):
59 | show_remote_panel(self.on_remote_selection, show_url=True)
60 |
61 | @util.actions.destructive(description="remove a remote")
62 | def on_remote_selection(self, remote):
63 | self.git("remote", "remove", remote)
64 | util.view.refresh_gitsavvy_interfaces(self.window, refresh_status_bar=False)
65 |
66 |
67 | class gs_remote_rename(GsWindowCommand):
68 | """
69 | Reame remotes
70 | """
71 |
72 | def run(self):
73 | show_remote_panel(self.on_remote_selection, show_url=True)
74 |
75 | def on_remote_selection(self, remote):
76 | self.remote = remote
77 | show_single_line_input_panel("New name", remote, self.on_enter_name)
78 |
79 | def on_enter_name(self, new_name):
80 | if not new_name:
81 | return
82 | if new_name == self.remote:
83 | return
84 | self.git("remote", "rename", self.remote, new_name)
85 | self.window.status_message("remote {} was renamed as {}.".format(self.remote, new_name))
86 | util.view.refresh_gitsavvy_interfaces(self.window, refresh_status_bar=False)
87 |
--------------------------------------------------------------------------------
/core/commands/reset.py:
--------------------------------------------------------------------------------
1 | import sublime
2 | from .log import LogMixin
3 | from .reflog import RefLogMixin
4 | from ...common import util
5 | from ..ui_mixins.quick_panel import show_branch_panel
6 | from GitSavvy.core.base_commands import GsWindowCommand
7 |
8 |
9 | __all__ = (
10 | "gs_reset",
11 | "gs_reset_branch",
12 | "gs_reset_reflog",
13 | )
14 |
15 |
16 | GIT_RESET_MODES = [
17 | # See analysis at
18 | # http://stackoverflow.com/questions/34149356/what-exactly-is-the-difference-between-all-the-git-reset-modes/34155307#34155307
19 | ["--soft", "stage differences (safe)"],
20 | ["--mixed", "unstage differences (safe)"],
21 | ["--hard", "discard uncommitted changes, overwrite working dir (unsafe)"],
22 | ["--keep", "keep uncommitted changes, update working dir (safe)"],
23 | ["--merge", "discard staged, keep unstaged, update working (abort if unsafe)"]
24 | ]
25 | MODES = [mode for mode, _ in GIT_RESET_MODES]
26 |
27 |
28 | class ResetMixin(GsWindowCommand):
29 |
30 | def do_action(self, commit_hash, **kwargs):
31 | if not commit_hash:
32 | return
33 | self._selected_hash = commit_hash
34 |
35 | use_reset_mode = self.savvy_settings.get("use_reset_mode")
36 | last_reset_mode_used = \
37 | self.current_state().get("last_reset_mode_used", use_reset_mode)
38 | reset_modes = (
39 | GIT_RESET_MODES
40 | + (
41 | [[use_reset_mode, ""]]
42 | if use_reset_mode and use_reset_mode not in MODES
43 | else []
44 | )
45 | )
46 | try:
47 | selected_index = (
48 | [m for m, _ in reset_modes]
49 | .index(last_reset_mode_used)
50 | )
51 | except ValueError:
52 | selected_index = -1
53 |
54 | def on_done(index):
55 | if index == -1:
56 | return
57 | self.on_reset(reset_modes[index][0].strip())
58 |
59 | self.window.show_quick_panel(
60 | reset_modes,
61 | on_done,
62 | flags=sublime.MONOSPACE_FONT,
63 | selected_index=selected_index
64 | )
65 |
66 | def on_reset(self, reset_mode):
67 | # Split the reset mode to support multiple args, e.g. "--mixed -N"
68 | args = reset_mode.split() + [self._selected_hash]
69 |
70 | def do_reset():
71 | self.update_store({"last_reset_mode_used": reset_mode})
72 | self.git("reset", *args)
73 | util.view.refresh_gitsavvy_interfaces(self.window, refresh_sidebar=True)
74 |
75 | if reset_mode == "--hard":
76 | util.actions.destructive("perform a hard reset")(do_reset)()
77 | else:
78 | do_reset()
79 |
80 |
81 | class gs_reset(ResetMixin, LogMixin):
82 | pass
83 |
84 |
85 | class gs_reset_branch(ResetMixin):
86 | def run(self, **kwargs):
87 | show_branch_panel(self.on_branch_selection)
88 |
89 | def on_branch_selection(self, branch):
90 | self.do_action(branch)
91 |
92 |
93 | class gs_reset_reflog(ResetMixin, RefLogMixin):
94 | pass
95 |
--------------------------------------------------------------------------------
/core/commands/revert.py:
--------------------------------------------------------------------------------
1 | from sublime_plugin import WindowCommand
2 |
3 | from .log import LogMixin
4 | from ..git_command import GitCommand
5 | from ...common import util
6 | from GitSavvy.core.base_commands import GsWindowCommand
7 | from GitSavvy.core.runtime import on_worker
8 |
9 |
10 | __all__ = (
11 | "gs_revert_commit",
12 | "gs_revert_abort",
13 | "gs_revert_continue",
14 | "gs_revert_skip",
15 | )
16 |
17 |
18 | class gs_revert_commit(LogMixin, WindowCommand, GitCommand):
19 | @on_worker
20 | def do_action(self, commit_hash, **kwargs):
21 | try:
22 | self.git("revert", *(commit_hash if isinstance(commit_hash, list) else [commit_hash]))
23 | finally:
24 | util.view.refresh_gitsavvy(self.window.active_view(), refresh_sidebar=True)
25 |
26 |
27 | class gs_revert_abort(GsWindowCommand):
28 | @on_worker
29 | def run(self):
30 | try:
31 | self.git("revert", "--abort")
32 | finally:
33 | util.view.refresh_gitsavvy_interfaces(self.window, refresh_sidebar=True)
34 |
35 |
36 | class gs_revert_continue(GsWindowCommand):
37 | @on_worker
38 | def run(self):
39 | try:
40 | self.git("revert", "--continue")
41 | finally:
42 | util.view.refresh_gitsavvy_interfaces(self.window, refresh_sidebar=True)
43 |
44 |
45 | class gs_revert_skip(GsWindowCommand):
46 | @on_worker
47 | def run(self):
48 | try:
49 | self.git("revert", "--skip")
50 | finally:
51 | util.view.refresh_gitsavvy_interfaces(self.window, refresh_sidebar=True)
52 |
--------------------------------------------------------------------------------
/core/commands/stage_diff.py:
--------------------------------------------------------------------------------
1 | """
2 | Implements a special view that displays an editable diff of unstaged changes.
3 | """
4 |
5 | import os
6 |
7 | import sublime
8 | from sublime_plugin import WindowCommand, TextCommand
9 |
10 | from ..git_command import GitCommand
11 | from ..view import replace_view_content
12 | from ...common import util
13 |
14 |
15 | TITLE = "STAGE-DIFF: {}"
16 | MESSAGE = "Press {}-Enter to apply the diff. Close the window to cancel.".format(util.super_key)
17 |
18 |
19 | class GsStageDiffCommand(WindowCommand, GitCommand):
20 |
21 | """
22 | Create a new view to display the project's unstaged changes.
23 | """
24 |
25 | def run(self):
26 | repo_path = self.repo_path
27 | stage_diff_view = util.view.create_scratch_view(self.window, "git_stage_diff", {
28 | "syntax": "Packages/GitSavvy/syntax/diff.sublime_syntax",
29 | "title": TITLE.format(os.path.basename(repo_path)),
30 | "read_only": False,
31 | "git_savvy.repo_path": repo_path,
32 | })
33 |
34 | stdout = self.git("diff", "--no-color")
35 | content = MESSAGE + "\n\n" + stdout
36 | replace_view_content(stage_diff_view, content)
37 |
38 |
39 | class GsStageDiffApplyCommand(TextCommand, GitCommand):
40 |
41 | """
42 | Apply the commit as it is presented in the view to the index. Then close the view.
43 | """
44 |
45 | def run(self, edit):
46 | diff_content = self.view.substr(sublime.Region(0, self.view.size()))
47 | self.git("apply", "--cached", "-", stdin=diff_content)
48 | self.view.close()
49 |
--------------------------------------------------------------------------------
/core/commands/status_bar.py:
--------------------------------------------------------------------------------
1 | import sublime
2 | from sublime_plugin import TextCommand, EventListener
3 |
4 | from ..git_command import GitCommand
5 | from ..runtime import run_when_worker_is_idle, throttled
6 | from GitSavvy.core import store
7 |
8 |
9 | STATUSBAR_KEY = "gitsavvy-repo-status"
10 |
11 |
12 | class GsStatusBarEventListener(EventListener):
13 | def on_activated(self, view):
14 | view.run_command("gs_draw_status_bar")
15 |
16 | def on_post_save(self, view):
17 | view.run_command("gs_update_status")
18 |
19 |
20 | class gs_update_status(TextCommand, GitCommand):
21 | def run(self, edit):
22 | run_when_worker_is_idle(throttled(self.run_impl, self.view))
23 |
24 | def run_impl(self, view):
25 | repo_path = self.find_repo_path()
26 | if repo_path:
27 | try:
28 | self.update_working_dir_status()
29 | except RuntimeError:
30 | # Although with `if repo_path` we have enough to make the
31 | # status call to git safe, the processing of the status
32 | # asks `self.repo_path` multiple times.
33 | # A user might have closed the view in between so we MUST
34 | # catch potential `RuntimeError`s.
35 | pass
36 |
37 |
38 | class gs_draw_status_bar(TextCommand, GitCommand):
39 |
40 | """
41 | Update the short Git status in the Sublime status bar.
42 | """
43 |
44 | def run(self, edit, repo_path=None):
45 | view = self.view
46 | if not self.savvy_settings.get("git_status_in_status_bar"):
47 | view.erase_status(STATUSBAR_KEY)
48 | return
49 |
50 | if not repo_path:
51 | repo_path = self.find_repo_path()
52 | if not repo_path:
53 | return
54 | elif repo_path != self.find_repo_path():
55 | return
56 |
57 | try:
58 | short_status = store.current_state(repo_path)["short_status"]
59 | except Exception:
60 | ...
61 | else:
62 | view.set_status(STATUSBAR_KEY, short_status)
63 |
64 |
65 | def on_status_update(repo_path, state):
66 | view = sublime.active_window().active_view()
67 | if view:
68 | view.run_command("gs_draw_status_bar", {"repo_path": repo_path})
69 |
70 |
71 | store.subscribe("*", {"short_status"}, on_status_update)
72 |
--------------------------------------------------------------------------------
/core/exceptions.py:
--------------------------------------------------------------------------------
1 | import sublime
2 | from ..common import util
3 |
4 |
5 | from typing import Optional, Sequence
6 |
7 |
8 | class GitSavvyError(Exception):
9 | def __init__(self, msg, *, cmd=None, stdout="", stderr="", show_panel=True, window=None):
10 | # type: (str, Sequence[str], str, str, bool, Optional[sublime.Window]) -> None
11 | super(GitSavvyError, self).__init__(msg)
12 | self.message = msg
13 | self.cmd = cmd
14 | self.stdout = stdout
15 | self.stderr = stderr
16 | self.show_panel = show_panel
17 | self.window = window
18 | if msg:
19 | if show_panel:
20 | self.show_error_panel()
21 | util.debug.log_error(msg)
22 |
23 | def show_error_panel(self):
24 | util.log.display_panel(self.window or sublime.active_window(), self.message)
25 |
26 |
27 | class FailedGithubRequest(GitSavvyError):
28 | pass
29 |
30 |
31 | class FailedGitLabRequest(GitSavvyError):
32 | pass
33 |
34 |
35 | class DetachedView(RuntimeError):
36 | pass
37 |
--------------------------------------------------------------------------------
/core/git_mixins/__init__.py:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/timbrel/GitSavvy/f0c9067eb061498ba7a07960e5cbaefb414b4994/core/git_mixins/__init__.py
--------------------------------------------------------------------------------
/core/git_mixins/checkout_discard.py:
--------------------------------------------------------------------------------
1 | from GitSavvy.core.git_command import mixin_base
2 |
3 |
4 | class CheckoutDiscardMixin(mixin_base):
5 |
6 | def discard_all_unstaged(self):
7 | """
8 | Any changes that are not staged or committed will be reverted
9 | to their state in HEAD. Any new files will be deleted.
10 | """
11 | self.git("clean", "-df")
12 | self.git("checkout", "--", ".")
13 |
14 | def discard_untracked_file(self, *fpaths):
15 | """
16 | Given a list of absolute paths or paths relative to the repo's root,
17 | remove the file or directory from the working tree.
18 | """
19 | self.git("clean", "-df", "--", *fpaths)
20 |
21 | def checkout_file(self, *fpaths):
22 | """
23 | Given a list of absolute paths or paths relative to the repo's root,
24 | discard any changes made to the file and revert it in the working
25 | directory to the state it is in HEAD.
26 | """
27 | self.git("checkout", "--", *fpaths)
28 |
29 | def checkout_ref(self, ref, fpath=None):
30 | """
31 | Given a ref (local branch, remote branch, tag, etc), check it out.
32 | """
33 | if fpath:
34 | self.git("checkout", ref, "--", fpath)
35 | else:
36 | self.git("checkout", ref)
37 |
--------------------------------------------------------------------------------
/core/git_mixins/ignore.py:
--------------------------------------------------------------------------------
1 | import os
2 | from ...common import util
3 |
4 | from GitSavvy.core.git_command import mixin_base
5 | from GitSavvy.core.utils import cache_in_store_as
6 |
7 | from typing import List
8 |
9 |
10 | linesep = None
11 |
12 |
13 | class IgnoreMixin(mixin_base):
14 | @cache_in_store_as("skipped_files")
15 | def get_skipped_files(self) -> List[str]:
16 | """Return all files for which skip-worktree is set."""
17 | return [
18 | file_path
19 | for line in self.git("ls-files", "-v").splitlines()
20 | if line.startswith("S")
21 | if (file_path := line[2:])
22 | ]
23 |
24 | def set_skip_worktree(self, *file_paths: str) -> None:
25 | self.git("update-index", "--skip-worktree", *file_paths)
26 |
27 | def unset_skip_worktree(self, *file_paths: str) -> None:
28 | self.git("update-index", "--no-skip-worktree", *file_paths)
29 |
30 | def add_ignore(self, path_or_pattern):
31 | """
32 | Add the provided relative path or pattern to the repo's `.gitignore` file.
33 | """
34 | global linesep
35 |
36 | if not linesep:
37 | # Use native line ending on Windows only when `autocrlf` is set to `true`.
38 | if os.name == "nt":
39 | autocrlf = self.git("config", "--global", "core.autocrlf",
40 | throw_on_error=False).strip() == "true"
41 | linesep = os.linesep if autocrlf else "\n"
42 | else:
43 | linesep = os.linesep
44 |
45 | gitignore = os.path.join(self.repo_path, ".gitignore")
46 | if os.path.exists(gitignore):
47 | with util.file.safe_open(gitignore, "r", encoding="utf-8") as fp:
48 | ignore_lines = fp.read().splitlines()
49 | else:
50 | ignore_lines = []
51 |
52 | ignore_lines += [path_or_pattern, ""]
53 | with util.file.safe_open(gitignore, "w", encoding="utf-8", newline=linesep) as fp:
54 | fp.write("\n".join(ignore_lines))
55 |
--------------------------------------------------------------------------------
/core/git_mixins/rebase.py:
--------------------------------------------------------------------------------
1 | import re
2 |
3 | from GitSavvy.core.fns import filter_
4 | from GitSavvy.core.git_command import mixin_base
5 |
6 |
7 | from typing import List, Optional
8 |
9 |
10 | EXTRACT_BRANCH_NAME = re.compile(r'^[^[]+\[(.*?)(?:[\^\~]+[\d]*)*\]')
11 |
12 |
13 | class NearestBranchMixin(mixin_base):
14 | """ Provide reusable methods for detecting the nearest of a branch relatives """
15 |
16 | def branch_relatives(self, branch):
17 | # type: (str) -> List[str]
18 | """ Get list of all relatives from ``git show-branch`` results """
19 | output = self.git("show-branch", "--no-color") # type: str
20 |
21 | try:
22 | prelude, body = re.split(r'^-+$', output, flags=re.M)
23 | except ValueError:
24 | # If there is only one branch, git changes the output format
25 | # and omits the prelude and column indicator.
26 | lines = filter_(output.splitlines())
27 | else:
28 | match = re.search(r'^(\s+)\*', prelude, re.M)
29 | if not match:
30 | print("branch {} not found in header information".format(branch))
31 | return []
32 |
33 | branch_column = len(match.group(1))
34 | lines = (
35 | line
36 | for line in filter_(body.splitlines())
37 | if line[branch_column] != ' '
38 | )
39 |
40 | relatives = [] # type: List[str]
41 | for line in lines:
42 | match = EXTRACT_BRANCH_NAME.match(line)
43 | if match:
44 | branch_name = match.group(1)
45 | if branch_name != branch and branch_name not in relatives:
46 | relatives.append(branch_name)
47 |
48 | return relatives
49 |
50 | def nearest_branch(self, branch, default="master"):
51 | # type: (Optional[str], str) -> str
52 | """
53 | Find the nearest commit in current branch history that exists
54 | on a different branch and return that branch name.
55 |
56 | If no such branch is found, return the given default ("master" if not
57 | specified).
58 |
59 | """
60 | relatives = self.branch_relatives(branch or default)
61 | if not relatives:
62 | return default
63 |
64 | return relatives[0]
65 |
--------------------------------------------------------------------------------
/core/git_mixins/stage_unstage.py:
--------------------------------------------------------------------------------
1 | from GitSavvy.core.git_command import mixin_base
2 |
3 |
4 | class StageUnstageMixin(mixin_base):
5 |
6 | def stage_file(self, *fpath, force=True):
7 | # type: (str, bool) -> None
8 | """
9 | Given an absolute path or path relative to the repo's root, stage
10 | the file.
11 | """
12 | # Ensure we don't run "add --all" without any paths which
13 | # would add everything
14 | if not fpath:
15 | return
16 |
17 | self.git(
18 | "add",
19 | "-f" if force else None,
20 | "--all",
21 | "--",
22 | *fpath
23 | )
24 |
25 | def unstage_file(self, *fpath):
26 | # type: (str) -> None
27 | """
28 | Given an absolute path or path relative to the repo's root, unstage
29 | the file.
30 | """
31 | # Ensure we don't run "reset" without any paths which
32 | # would unstage everything
33 | if not fpath:
34 | return
35 |
36 | self.git("reset", "HEAD", "--", *fpath)
37 |
38 | def add_all_tracked_files(self):
39 | """
40 | Add to index all files that have been deleted or modified, but not
41 | those that have been created.
42 | """
43 | return self.git("add", "-u")
44 |
45 | def add_all_files(self):
46 | """
47 | Add to index all files that have been deleted, modified, or
48 | created.
49 | """
50 | return self.git("add", "-A")
51 |
52 | def unstage_all_files(self):
53 | """
54 | Remove all staged files from the index.
55 | """
56 | return self.git("reset")
57 |
58 | def intent_to_add(self, *file_paths: str) -> None:
59 | self.git("add", "--intent-to-add", "--", *file_paths)
60 |
61 | def undo_intent_to_add(self, *file_paths: str) -> None:
62 | # Ensure we don't run "reset" without any paths which
63 | # would unstage everything
64 | if not file_paths:
65 | return
66 |
67 | self.git("reset", "--", *file_paths)
68 |
--------------------------------------------------------------------------------
/core/git_mixins/stash.py:
--------------------------------------------------------------------------------
1 | import re
2 |
3 | from GitSavvy.core.git_command import mixin_base
4 | from GitSavvy.core.utils import cache_in_store_as
5 |
6 | from typing import List, NamedTuple, Union
7 | StashId = Union[str, int]
8 |
9 |
10 | class Stash(NamedTuple):
11 | id: str
12 | description: str
13 |
14 |
15 | class StashMixin(mixin_base):
16 |
17 | @cache_in_store_as("stashes")
18 | def get_stashes(self):
19 | # type: () -> List[Stash]
20 | """
21 | Return a list of stashes in the repo.
22 | """
23 | stdout = self.git("stash", "list")
24 | stashes = []
25 | for entry in stdout.split("\n"):
26 | if not entry:
27 | continue
28 | match = re.match("^stash@\\{(\\d+)}: (.*?: )?(.*)", entry)
29 | assert match
30 | num, _, description = match.groups()
31 | stashes.append(Stash(num, description))
32 |
33 | return stashes
34 |
35 | def show_stash(self, id):
36 | # type: (StashId) -> str
37 | stash_name = "stash@{{{}}}".format(id)
38 | return self.git("stash", "show", "--no-color", "-p", stash_name)
39 |
40 | def apply_stash(self, id):
41 | # type: (StashId) -> None
42 | """
43 | Apply stash with provided id.
44 | """
45 | self.git("stash", "apply", "stash@{{{}}}".format(id))
46 |
47 | def pop_stash(self, id):
48 | # type: (StashId) -> None
49 | """
50 | Pop stash with provided id.
51 | """
52 | self.git("stash", "pop", "stash@{{{}}}".format(id))
53 |
54 | def create_stash(self, description, include_untracked=False):
55 | # type: (str, bool) -> None
56 | """
57 | Create stash with provided description from working files.
58 | """
59 | self.git("stash", "save", "-k", "-u" if include_untracked else None, description)
60 |
61 | def drop_stash(self, id):
62 | # type: (StashId) -> str
63 | """
64 | Drop stash with provided id.
65 | """
66 | return self.git("stash", "drop", "stash@{{{}}}".format(id))
67 |
--------------------------------------------------------------------------------
/core/interfaces/__init__.py:
--------------------------------------------------------------------------------
1 | import sublime
2 | from sublime_plugin import TextCommand
3 |
4 | from .status import * # noqa: F401, F403
5 | from .branch import * # noqa: F401, F403
6 | from .rebase import * # noqa: F401, F403
7 | from .tags import * # noqa: F401, F403
8 | from ..git_command import GitCommand
9 |
10 |
11 | class gs_tab_cycle(TextCommand, GitCommand):
12 | commands = {
13 | "status": "gs_show_status",
14 | "branch": "gs_show_branch",
15 | "rebase": "gs_show_rebase",
16 | "tags": "gs_show_tags",
17 | "graph": "gs_log_graph_tab_in"
18 | }
19 |
20 | def run(self, edit, source=None, target=None, reverse=False):
21 | to_load = target or self.get_next(source, reverse)
22 | if not to_load:
23 | return
24 |
25 | window = self.view.window()
26 | if window:
27 | window.run_command(self.commands[to_load])
28 | if not self.view.settings().get("git_savvy.log_graph_view"):
29 | self.view.close()
30 |
31 | def get_next(self, source, reverse=False):
32 | tab_order = self.savvy_settings.get("tab_order")
33 |
34 | try:
35 | idx = tab_order.index(source)
36 | except ValueError:
37 | return None
38 |
39 | delta = (-1 if reverse else +1)
40 | next_idx = (idx + delta) % len(tab_order)
41 | return tab_order[next_idx]
42 |
--------------------------------------------------------------------------------
/core/settings.py:
--------------------------------------------------------------------------------
1 | from functools import lru_cache
2 |
3 | import sublime
4 | import sublime_plugin
5 |
6 | from GitSavvy.core.fns import maybe
7 |
8 |
9 | __all__ = (
10 | "ProjectFileChanges",
11 | )
12 |
13 | from typing import Dict
14 |
15 |
16 | class GitSavvySettings:
17 | def __init__(self, window=None):
18 | # type: (sublime.Window) -> None
19 | self._window = window or sublime.active_window()
20 | self._global_settings = get_global_settings()
21 |
22 | def get(self, key, default=None):
23 | try:
24 | return get_project_settings(self._window)[key]
25 | except KeyError:
26 | return self._global_settings.get(key, default)
27 |
28 | def set(self, key, value):
29 | self._global_settings.set(key, value)
30 |
31 |
32 | CHANGE_COUNT = 0
33 |
34 |
35 | class ProjectFileChanges(sublime_plugin.EventListener):
36 | def on_post_save(self, view):
37 | # type: (sublime.View) -> None
38 | global CHANGE_COUNT
39 | file_path = view.file_name()
40 | if file_path and file_path.endswith(".sublime-project"):
41 | CHANGE_COUNT += 1
42 |
43 |
44 | def get_project_settings(window):
45 | # type: (sublime.Window) -> Dict
46 | global CHANGE_COUNT
47 | return _get_project_settings(window.id(), CHANGE_COUNT)
48 |
49 |
50 | @lru_cache(maxsize=16)
51 | def _get_project_settings(wid, _counter):
52 | # type: (sublime.WindowId, int) -> Dict
53 | window = sublime.Window(wid)
54 | project_data = window.project_data()
55 | if not project_data:
56 | return {}
57 | return project_data.get("settings", {}).get("GitSavvy", {})
58 |
59 |
60 | @lru_cache(maxsize=1)
61 | def get_global_settings():
62 | return GlobalSettings("GitSavvy.sublime-settings")
63 |
64 |
65 | class GlobalSettings:
66 | def __init__(self, name):
67 | self._settings = s = sublime.load_settings(name)
68 | s.clear_on_change(name)
69 | s.add_on_change(name, self._on_update)
70 | self._cache = {}
71 |
72 | def get(self, name, default=None):
73 | try:
74 | return self._cache[name]
75 | except KeyError:
76 | self._cache[name] = current_value = self._settings.get(name, default) # type: ignore[var-annotated]
77 | return current_value
78 |
79 | def set(self, name, value):
80 | self._settings.set(name, value) # implicitly calls `_on_update` to clear cache
81 |
82 | def _on_update(self):
83 | self._cache.clear()
84 |
85 |
86 | class SettingsMixin:
87 | _savvy_settings = None
88 |
89 | @property
90 | def savvy_settings(self):
91 | if not self._savvy_settings:
92 | window = self.some_window()
93 | self._savvy_settings = GitSavvySettings(window)
94 | return self._savvy_settings
95 |
96 | def some_window(self):
97 | # type: () -> sublime.Window
98 | return (
99 | maybe(lambda: self.window) # type: ignore[attr-defined]
100 | or maybe(lambda: self.view.window()) # type: ignore[attr-defined]
101 | or sublime.active_window()
102 | )
103 |
--------------------------------------------------------------------------------
/core/store.py:
--------------------------------------------------------------------------------
1 | from collections import defaultdict, deque
2 | from functools import partial
3 | import threading
4 | import uuid
5 |
6 | from .utils import eat_but_log_errors
7 |
8 |
9 | from typing import (
10 | AbstractSet, Callable, DefaultDict, Deque, Dict, List, Optional, Set, Tuple, TypedDict,
11 | TYPE_CHECKING
12 | )
13 |
14 | if TYPE_CHECKING:
15 | from GitSavvy.core.git_mixins.active_branch import Commit
16 | from GitSavvy.core.git_mixins.branches import Branch
17 | from GitSavvy.core.git_mixins.stash import Stash
18 | from GitSavvy.core.git_mixins.tags import TagList
19 | from GitSavvy.core.git_mixins.status import HeadState, WorkingDirState
20 |
21 | class RepoStore(TypedDict, total=False):
22 | status: WorkingDirState
23 | head: HeadState
24 | long_status: str
25 | short_status: str
26 | branches: List[Branch]
27 | remotes: Dict[str, str]
28 | remotes_with_no_tags_set: Set[str]
29 | local_tags: TagList
30 | last_branches: Deque[Optional[str]]
31 | last_branch_used_to_pull_from: Optional[str]
32 | last_branch_used_to_rebase_from: Optional[str]
33 | last_remote_used: Optional[str]
34 | last_remote_used_for_push: Optional[str]
35 | last_remote_used_with_option_all: Optional[str]
36 | last_reset_mode_used: Optional[str]
37 | short_hash_length: int
38 | skipped_files: List[str]
39 | slow_repo: bool
40 | stashes: List[Stash]
41 | recent_commits: List[Commit]
42 | descriptions: Dict[str, str]
43 | default_graph_options: Dict[str, str]
44 | RepoPath = str
45 | SubscriberKey = str
46 | Keys = AbstractSet[str]
47 |
48 |
49 | def initial_state():
50 | # type: () -> RepoStore
51 | return {
52 | "last_branches": deque([None] * 2, 2),
53 | }
54 |
55 |
56 | state = defaultdict(initial_state) # type: DefaultDict[RepoPath, RepoStore]
57 | subscribers = {} # type: Dict[SubscriberKey, Tuple[RepoPath, Keys, Callable]]
58 |
59 | lock = threading.Lock()
60 |
61 |
62 | def update_state(repo_path, partial_state):
63 | # type: (RepoPath, RepoStore) -> None
64 | with lock:
65 | state[repo_path].update(partial_state)
66 | notify_all(repo_path, partial_state.keys(), state[repo_path])
67 |
68 |
69 | def notify_all(repo_path, updated_keys, current_state):
70 | # type: (RepoPath, Keys, RepoStore) -> None
71 | for (subscribed_repo_path, keys, fn) in subscribers.values():
72 | if (
73 | subscribed_repo_path in {repo_path, "*"}
74 | and updated_keys & keys
75 | ):
76 | with eat_but_log_errors():
77 | fn(repo_path, current_state)
78 |
79 |
80 | def current_state(repo_path):
81 | # type: (RepoPath) -> RepoStore
82 | return state[repo_path]
83 |
84 |
85 | def subscribe(repo_path, keys, fn):
86 | # type: (RepoPath, Keys, Callable) -> Callable[[], None]
87 | key = uuid.uuid4().hex
88 | subscribers[key] = (repo_path, keys, fn)
89 | return partial(_unsubscribe, key)
90 |
91 |
92 | def _unsubscribe(key):
93 | # type: (SubscriberKey) -> None
94 | subscribers.pop(key, None)
95 |
--------------------------------------------------------------------------------
/core/types.py:
--------------------------------------------------------------------------------
1 |
2 | # Use LineNo, ColNo for 1-based line column counting (like git or `window.open_file`),
3 | # use Row, Col for 0-based counting like Sublime's `view.rowcol`!
4 | LineNo = int
5 | ColNo = int
6 | Row = int
7 | Col = int
8 |
--------------------------------------------------------------------------------
/core/ui_mixins/__init__.py:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/timbrel/GitSavvy/f0c9067eb061498ba7a07960e5cbaefb414b4994/core/ui_mixins/__init__.py
--------------------------------------------------------------------------------
/core/ui_mixins/input_panel.py:
--------------------------------------------------------------------------------
1 | import sublime
2 |
3 |
4 | from typing import Callable, Optional
5 | ValueCallback = Callable[[str], None]
6 | CancelCallback = Callable[[], None]
7 |
8 |
9 | def show_single_line_input_panel(
10 | caption, # type: str
11 | initial_text, # type: str
12 | on_done, # type: ValueCallback
13 | on_change=None, # type: Optional[ValueCallback]
14 | on_cancel=None, # type: Optional[CancelCallback]
15 | select_text=True # type: bool
16 | ): # type: (...) -> sublime.View
17 | window = sublime.active_window()
18 | v = window.show_input_panel(caption, initial_text, on_done, on_change, on_cancel)
19 | if select_text:
20 | v.run_command("select_all")
21 | v.settings().set("git_savvy.single_line_input_panel", True)
22 | return v
23 |
--------------------------------------------------------------------------------
/dependencies.json:
--------------------------------------------------------------------------------
1 | {
2 | "*": {
3 | ">=4000": [
4 | "typing_extensions"
5 | ]
6 | }
7 | }
8 |
--------------------------------------------------------------------------------
/docs/debug.md:
--------------------------------------------------------------------------------
1 | # Debug
2 |
3 | If you're doing development on GitSavvy, the following commands may be useful.
4 |
5 |
6 | ## `GitSavvy: reload modules (debug)`
7 |
8 | This command will reload all GitSavvy-related Python modules and initiate a plugin reset for Sublime Text 3. Note that the editor's interface may become unresponsive for a second or two while the plugins are reloaded. However, this workflow is often preferable to closing and re-opening Sublime when testing changes to GitSavvy.
9 |
10 | This command will only have an effect if `dev_mode` is set to `true` in `GitSavvy` settings.
11 |
12 |
13 | ## `GitSavvy: enable logging`
14 |
15 | This will start tracking the inputs and outputs of all Git commands that are running under the hood. Aggregating this data can be useful for those wanting to learn how GitSavvy works, as well as for debugging purposes.
16 |
17 | **Note:** If you've logged a sequence of Git commands before, running this again will overwrite what was previously recorded.
18 |
19 |
20 | ## `GitSavvy: disable logging`
21 |
22 | This stops all recording Git command inputs and outputs, but does not destroy the record.
23 |
24 | ## `GitSavvy: view recorded log`
25 |
26 | Once you have started and stopped logging, this command will display the log in JSON format in a new scratch view.
27 |
28 | # Providing a Debug Log
29 |
30 | Ocasionally when creating a new issue in GitSavvy, you will be requested to provide a debug log. The above commands make it easy to do, by following these steps:
31 |
32 | 1. Open sublime, and get to the state just prior to running the failing command.
33 | 2. Open command palette, and run the command "GitSavvy: enable logging".
34 | 3. Perform the failing command.
35 | 4. Run the command "GitSavvy: disable logging"
36 | 5. Run the command "GitSavvy: view recorded log",
37 | save the file locally and attach it to your issue.
38 |
39 | _Note: Take care to remove any sensitive information that may be recorded in GitSavvy._
40 |
41 | # Other tools / PATH issues / Different behavior from terminal and inside Sublime
42 |
43 | Please check the tool is in your PATH inside sublime.
44 | First find the path to where the tool binaries are, open a system terminal/shell and paste:
45 |
46 | which ;
47 |
48 | Check if that path is the `$PATH` inside sublime. To do that open the sublime console and paste in:
49 |
50 | from os import environ; environ['PATH']
51 |
52 | If the tool path is missing from your sublime environment's `PATH` variable, you need to look into correcting the env variables available to sublime on launch. The unofficial docs mention how to set it globally for windows and mac in [the "Troubleshooting Build Systems" page][2]. Alternatively, you may want to look at the packages ["Environment Settings"][3] and ["Fix Mac Path"][4].
53 |
54 | If, however, the path is in your sublime environment, please open an issue and include these values in an issue.
55 |
56 | [1]: https://github.com/timbrel/GitSavvy/issues/684#issuecomment-323579850
57 | [2]: http://docs.sublimetext.info/en/latest/reference/build_systems/troubleshooting.html
58 | [3]: https://packagecontrol.io/packages/Environment%20Settings
59 | [4]: https://packagecontrol.io/packages/Fix%20Mac%20Path
60 |
--------------------------------------------------------------------------------
/docs/flow.md:
--------------------------------------------------------------------------------
1 | # git-flow
2 |
3 | Vincent Driessen's [git-flow](https://github.com/nvie/gitflow) extension is fully supported, allowing you to run flow commands with sublime commands. To enable `git-flow` integration you must set `show_git_flow_commands` to `true` in `GitSavvy` settings.
4 |
5 | Most commands attempt to mirror `git-flow` 's interface with the added ability to select a target from local branches/remotes.
6 |
7 | #### Notes
8 | - Requires _version **0.4.1**_ and above.
9 | - In some environments, like OS X, Sublime Text does not inherit the shell PATH environment value, and prevents `git-flow` extension from being located. This can be fixed with a plugin such as [SublimeFixMacPath](https://github.com/int3h/SublimeFixMacPath).
10 |
11 | ## `flow: init`
12 |
13 | A required step when you wish to setup a project to use `git-flow`. This will present a series of prompts to configure `git-flow` very much like the interactive shell command does.
14 |
15 | ## `flow: feature/release/hotfix/support start`
16 |
17 | When running this command, you will prompted first for the feature/release/hotfix/support name (without the prefix), and then the branch will be created and checked out.
18 |
19 | ## `flow: feature/release/hotfix/support finish`
20 |
21 | When running this command when an existing feature/release/hotfix/support branch is checked out, you will asked to confirm finish. Otherwise, you will be asked to select the relevant branch. This flow merges the changes from this branch into the "develop" branch (without fast-forwarding, unless branch has only a single commit).
22 |
23 | ## `flow: feature/release/hotfix publish`
24 |
25 | When running this command when an existing feature/release/hotfix branch is checked out, you will asked to confirm publish. Otherwise, you will be asked to select the relevant branch. This flow pushes the target branch to the configured remote.
26 |
27 | ## `flow: feature/release track`
28 |
29 | When running this command you will be prompted to provide a feature name. The command will pull a feature/release from a configured remote and check it out.
30 |
31 | ## `flow: feature pull`
32 |
33 | This will pull a feature from a given remote (not necessarily the configured default remote) and check it out. You will be first prompted to select a remote and then to provide a feature name.
34 |
--------------------------------------------------------------------------------
/docs/gitlab.md:
--------------------------------------------------------------------------------
1 | # GitLab integration
2 |
3 | GitSavvy provides some basic integration with GitLab. More features are planned for future versions. At present, both GitLab.com and GitLab enterprise are supported.
4 |
5 |
6 | ## Setup
7 |
8 | When interacting with a public repository, no configuration is required. However, if your repository is private, you will need to add an API key to the GitSavvy configuration. To do so:
9 |
10 | 1. [Create a personal access token.](https://docs.gitlab.com/ee/user/profile/personal_access_tokens.html#creating-a-personal-access-token); `api` scope should be checked.
11 | 2. After submitting, copy the generated API key.
12 | 3. In the Sublime Menu, open `Preferences > Package Settings > GitSavvy > Settings - User`.
13 | 4. Add your key to the `api_tokens` object (you can find an example in `Preferences > Package Settings > GitSavvy > Settings`).
14 |
15 |
16 | ## Choosing a remote
17 |
18 | By default, GitSavvy will use the URL of `origin` to get its GitLab API URL. If you would like to use a remote other than origin, run `gitlab: set remote for integration` in the command palette. You will be presented with a list of remotes. Once one is selected, this remote will be used for all attempts at integration with GitLab.
19 |
20 | ## `gitlab: review pull request`
21 |
22 | This command will display all open pull requests for the integrated GitLab remote. Once you have made a selection, you can either checkout the pull request as a detached HEAD, checkout the pull request as a local branch, create a branch but not check it out, view the diff of the pull request, or open the pull request in the browser.
23 |
--------------------------------------------------------------------------------
/docs/ignoring.md:
--------------------------------------------------------------------------------
1 | # Ignoring changes
2 |
3 | **Note:** None of the following commands are destructive. However, keep in mind that their use may result in unexpected results if specific files are ignored and forgotten.
4 |
5 |
6 | ## `git: ignore current file`
7 |
8 | This command adds an entry for the currently open file to the Git repository's root `.gitignore` file. The command is accessible both through the command palette and through the status dashboard.
9 |
10 |
11 | ## `git: ignore pattern`
12 |
13 | This command adds an entry to the Git repository's root `.gitignore` file. When it is run, you will be prompted for the pattern to add (based on the currently open file).
14 |
15 |
16 | ## `git: assume file unchanged`
17 |
18 | This command instructs Git to temporarily treat the currently open file as if it is unchanged. This may be useful if editing configuration files, etc, without adding an entry to `.gitignore` (which would also show up in the Git status).
19 |
20 | **Note:** These entries are stored in the local `.git` directory and are not tracked in any transparent way.
21 |
22 | ## `git: restore file assumed unchanged`
23 |
24 | This command displays a list of any files for which you've run `git: assume file unchanged`. When selected, the file will no longer be treated as unchanged by Git.
25 |
--------------------------------------------------------------------------------
/docs/misc.md:
--------------------------------------------------------------------------------
1 | # Miscellaneous features
2 |
3 | ## `git: init`
4 |
5 | This command will initialize a new repository, or re-initialize a pre-existing one. As such, use it carefully - if GitSavvy detects that Git is already initialized, you will be prompted to confirm.
6 |
7 | When run, you will asked to confirm the root directory of the new Git repository. GitSavvy will attempt to auto-detect this for you.
8 |
9 | This command will also be suggested to you should you attempt to run a GitSavvy command on a file that is not within a valid Git repository.
10 |
11 | ## `git: reset`
12 |
13 | This command will change the HEAD of the current branch to a previous commit.
14 |
15 | When run, you will be asked to select a commit from a list of previous commits. Once you select a commit, you will prompted for a reset mode. Once you select a reset mode the HEAD of the current branch will be changed to the selected commit, and your index and working directory will be updated depending on the reset mode you selected. For more information about reset modes, see the [git reset documentation](https://git-scm.com/docs/git-reset).
16 |
17 | To always use a specific reset mode, set `use_reset_mode` to a valid git reset mode flag (e.g. `--soft`, `--hard`) in `GitSavvy` settings.
18 |
19 | ## `git: reset to branch`
20 |
21 | Like `git: reset`, but it changes the HEAD of the current branch to the HEAD of a selected branch.
22 |
23 | ## `git: reset (reflog)`
24 |
25 | Like `git: reset`, this command will change the HEAD of the current branch to a previous commit, but uses `git reflog` rather than `git log` as the source of available commits.
26 |
27 | ## `git: cherry-pick`
28 |
29 | This command applies a commit from a different branch to the current branch.
30 |
31 | Running the command first prompts for branch selection; then it displays a limited log with commits unique to the chosen branch. Upon selection, the commit is [cherry-picked][1] into the current branch.
32 |
33 | [1]: https://git-scm.com/docs/git-cherry-pick
34 |
35 | ## `git: mv current file`
36 |
37 | Move or rename the current file. The command will prompt for the new filename.
38 |
--------------------------------------------------------------------------------
/docs/remotes.md:
--------------------------------------------------------------------------------
1 | # Interacting with remotes
2 |
3 | GitSavvy provides a few mechanisms for interact with remotes.
4 |
5 | ## `git: fetch`
6 |
7 | This updates the local history of remote branches, and downloads all commit objects referenced in that history. If the repository has multiple remotes you will prompted to indicate the remote from which you'd like to fetch, when running this command from the palette.
8 |
9 | ## `git: checkout remote branch as local`
10 |
11 | Assuming you've recently fetched, this command allows you to create a local branch (e.g. `feature-branch-one`) with the same history as a remote branch. Upon running the command, you will be presented with a list of remote branches and, once selected, the local branch will be created and checked out.
12 |
13 | ## `git: pull`
14 |
15 | This command will pull current branch from the tracking branch. If the tracking branch is not set, you will be prompted. If the git config `pull.rebase` is set true, the command will be execulated with `--rebase`.
16 |
17 |
18 | ## `git: pull with rebase`
19 |
20 | Like `git: pull`, but rebasing on the remote branch explictly.
21 |
22 | ## `git: pull from branch`
23 |
24 | When running this command, you will be prompted first for the remote you want to pull from, and then the branch. If your local branch tracks a remote, that branch name will be pre-selected at the second prompt.
25 |
26 | ## `git: pull from branch with rebase`
27 |
28 | Like `git: pull from branch`, but rebasing on the remote branch instead of merging.
29 |
30 | **For the following commands you need to configure a username and password in git, so GitSavvy can use it.**
31 |
32 | ## `git: push`
33 |
34 | This command will push current branch to the tracking branch. If the tracking branch is not set, you will be prompted for a remote and a branch name.
35 |
36 | ## `git: push to branch`
37 |
38 | When running this command, you will be prompted first for the remote you want to push to, and then the branch.
39 |
40 | ## `git: push to branch name`
41 |
42 | When running this command, you will prompted first for the remote you want to push to. Next, you'll be provided a text field to enter the name of the remote branch. This is useful if the remote branch does not yet exist.
43 |
--------------------------------------------------------------------------------
/docs/stash.md:
--------------------------------------------------------------------------------
1 | ## Stash
2 |
3 | Command to manipulate stashes. For those commands where you would need to pick a commit it will open a panel to pick which stash to action on.
4 |
5 | ## `git: stash save`
6 |
7 | Create a stash.
8 |
9 | ## `git: stash save including untracked files`
10 |
11 | Create a stash including untracked files.
12 |
13 | ## `git: stash save staged changes only`
14 |
15 | Create a stash from staged changes only. This works by creating a stash of only unstages files. Then creating a stash of all files and pop the first stash(or something in these lines).
16 |
17 | ## `git: stash show`
18 |
19 | Show a stash
20 |
21 | ## `git: stash apply`
22 |
23 | Apply a stash
24 |
25 | ## `git: stash pop`
26 |
27 | Pop a stash
28 |
29 | ## `git: stash drop`
30 |
31 | Discard a stash
32 |
--------------------------------------------------------------------------------
/docs/tag_mgmt.md:
--------------------------------------------------------------------------------
1 | # Tag management
2 |
3 | The following commands are provided to manage local and remote tags.
4 |
5 |
6 | ## `git: tags`
7 |
8 | GitSavvy's tag dashboard displays all local and remote tags, and enables you to:
9 |
10 | - create a new tag (`c`)
11 | - select and delete existing tags(s) (`d`)
12 | - select and push tag(s) to a remote (`p`)
13 | - push all tags to a remote (`P`), and
14 | - view the diff commit that is tagged (`l`)
15 |
16 | Remote tags are retrieved asynchronously, and may not display immediately when the view opens.
17 |
18 |
19 | ## `git: quick tag`
20 |
21 | You will be prompted first for a tag name, followed by a tag message. Once entered, a tag will created and associated with the commit at HEAD.
22 |
23 | ## `git: smart tag`
24 |
25 | Similar to `git: quick tag`. A tag name will be automatically generated when the release type is selected.
26 |
--------------------------------------------------------------------------------
/docs/testing.md:
--------------------------------------------------------------------------------
1 | # Package Testing
2 |
3 | We try to cover the most crucial functionality with unit tests using
4 | [UnitTesting](https://github.com/randy3k/UnitTesting). To run the tests
5 | locally, you should install UnitTesting via Package Control.
6 |
7 | ## Run the test specs locally
8 |
9 | First you need to [clone](https://github.com/timbrel/GitSavvy#less-simple) GitSavvy repo from source.
10 | Open the directory `GitSavvy` and simply run the command `UnitTesting: Test Current Project`
11 |
12 | ## Some details about DeferrableTestCase
13 |
14 | [DeferrableTestCase][1] is used to write the test cases. They are executed by
15 | the [DeferringTextTestRunner][2] and the runner expects not only regular test
16 | functions, but also generators. If the test function is a generator, it does
17 | the following
18 |
19 | - if the yielded object is a callable, the runner will evaluate the
20 | [callable][3] and check its returned value. If the result is `True`, the
21 | runner continues the generator, if not, the runner will wait until the
22 | condition is met.
23 |
24 | - If the yielded object is an integer, say `x`, then it will [continue][4] the
25 | generator after `x` ms.
26 |
27 | - Otherwise, the `yield` statement will always wait for 10 ms.
28 |
29 | [1]: https://github.com/randy3k/UnitTesting/blob/dc810ee334bb031710b859478faaf50293880995/unittesting/core/st3/runner.py#L49
30 | [2]: https://github.com/randy3k/UnitTesting/blob/dc810ee334bb031710b859478faaf50293880995/unittesting/core/st3/runner.py#L7
31 | [3]: https://github.com/randy3k/UnitTesting/blob/dc810ee334bb031710b859478faaf50293880995/unittesting/core/st3/runner.py#L49
32 | [4]: https://github.com/randy3k/UnitTesting/blob/dc810ee334bb031710b859478faaf50293880995/unittesting/core/st3/runner.py#L57
33 |
--------------------------------------------------------------------------------
/git_savvy.py:
--------------------------------------------------------------------------------
1 | import sublime
2 |
3 | from .common.commands import *
4 | from .common.ui import *
5 | from .common.global_events import *
6 | from .core.commands import *
7 | from .core.settings import *
8 | from .core.interfaces import *
9 | from .core.runtime import *
10 | from .github.commands import *
11 | from .gitlab.commands import *
12 |
13 |
14 | def plugin_loaded():
15 |
16 | try:
17 | import package_control.events
18 | except ImportError:
19 | pass
20 | else:
21 | if (
22 | package_control.events.install('GitSavvy') or
23 | package_control.events.post_upgrade('GitSavvy')
24 | ):
25 | # The "event" (flag) is set for 5 seconds. To not get into a
26 | # reloader excess we wait for that time, so that the next time
27 | # this exact `plugin_loaded` handler runs, the flag is already
28 | # unset.
29 | sublime.set_timeout_async(reload_plugin, 5000)
30 | return
31 |
32 | prepare_gitsavvy()
33 |
34 |
35 | def reload_plugin():
36 | from .common import util
37 | print("GitSavvy: Reloading plugin after install.")
38 | util.reload.reload_plugin(verbose=False, then=prepare_gitsavvy)
39 |
40 |
41 | def prepare_gitsavvy():
42 | from .common import util
43 | from .core import runtime
44 | runtime.determine_thread_names()
45 |
46 | # Ensure all interfaces are ready.
47 | sublime.set_timeout_async(
48 | lambda: util.view.refresh_gitsavvy(sublime.active_window().active_view()))
49 |
50 | savvy_settings = sublime.load_settings("GitSavvy.sublime-settings")
51 | if savvy_settings.get("load_additional_codecs"):
52 | sublime.set_timeout_async(reload_codecs)
53 |
54 |
55 | def reload_codecs():
56 | savvy_settings = sublime.load_settings("GitSavvy.sublime-settings")
57 | fallback_encoding = savvy_settings.get("fallback_encoding")
58 | try:
59 | import imp, codecs, encodings
60 | imp.reload(encodings)
61 | imp.reload(codecs)
62 | codecs.getencoder(fallback_encoding)
63 | except (ImportError, LookupError):
64 | sublime.error_message(
65 | "You have enabled `load_additional_codecs` mode, but the "
66 | "`fallback_encoding` codec cannot load. This probably means "
67 | "you don't have the Codecs33 package installed, or you've "
68 | "entered an unsupported encoding.")
69 |
--------------------------------------------------------------------------------
/github/__init__.py:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/timbrel/GitSavvy/f0c9067eb061498ba7a07960e5cbaefb414b4994/github/__init__.py
--------------------------------------------------------------------------------
/github/commands/__init__.py:
--------------------------------------------------------------------------------
1 | from .open_on_remote import *
2 | from .commit import *
3 | from .configure import *
4 | from .create_fork import *
5 | from .create_repo import *
6 | from .add_fork_as_remote import *
7 | from .pull_request import *
8 | from .open_issue import *
9 |
--------------------------------------------------------------------------------
/github/commands/add_fork_as_remote.py:
--------------------------------------------------------------------------------
1 | from itertools import chain
2 |
3 | from ...core.ui_mixins.quick_panel import show_paginated_panel
4 | from .. import github
5 | from .. import git_mixins
6 | from GitSavvy.core.base_commands import GsWindowCommand
7 | from GitSavvy.core.runtime import on_worker
8 |
9 |
10 | __all__ = (
11 | "gs_github_add_fork_as_remote",
12 | )
13 |
14 |
15 | class gs_github_add_fork_as_remote(git_mixins.GithubRemotesMixin, GsWindowCommand):
16 |
17 | """
18 | Get list of repos on GitHub associated with the active repo. Display, and when
19 | selected, add selection as git remote.
20 | """
21 |
22 | @on_worker
23 | def run(self):
24 | base_remote = github.parse_remote(self.get_integrated_remote_url())
25 | base_repo_data = github.get_repo_data(base_remote)
26 | parent = None
27 |
28 | forks = []
29 | if "parent" in base_repo_data:
30 | parent = base_repo_data["parent"]
31 | forks.append(parent)
32 |
33 | if "source" in base_repo_data:
34 | source = base_repo_data["source"]
35 | if parent and parent["clone_url"] != source["clone_url"]:
36 | forks.append(source)
37 |
38 | forks_ = chain(forks, github.get_forks(base_remote))
39 | show_paginated_panel(
40 | forks_,
41 | self.on_select_fork,
42 | limit=self.savvy_settings.get("github_per_page_max", 100),
43 | format_item=lambda fork: (fork["full_name"], fork),
44 | status_message="Getting forks...")
45 |
46 | def on_select_fork(self, fork):
47 | if not fork:
48 | return
49 | self.fork = fork
50 | self.window.show_quick_panel([fork["clone_url"], fork["ssh_url"]], self.on_select_url)
51 |
52 | def on_select_url(self, index):
53 | if index < 0:
54 | return
55 | elif index == 0:
56 | url = self.fork["clone_url"]
57 | elif index == 1:
58 | url = self.fork["ssh_url"]
59 |
60 | self.window.run_command("gs_remote_add", {"url": url})
61 |
--------------------------------------------------------------------------------
/github/commands/create_fork.py:
--------------------------------------------------------------------------------
1 | import sublime
2 |
3 | from ...common import util
4 | from .. import github, git_mixins
5 | from GitSavvy.core.base_commands import GsWindowCommand
6 | from GitSavvy.core.runtime import on_worker
7 |
8 |
9 | START_CREATE_MESSAGE = "Forking {repo} ..."
10 | END_CREATE_MESSAGE = "Fork created successfully."
11 |
12 |
13 | __all__ = ['gs_github_create_fork']
14 |
15 |
16 | class gs_github_create_fork(GsWindowCommand, git_mixins.GithubRemotesMixin):
17 |
18 | @on_worker
19 | def run(self, default_branch_only=None):
20 | remotes = self.get_remotes()
21 | base_remote_name = self.get_integrated_remote_name(remotes)
22 | base_remote_url = remotes[base_remote_name]
23 | base_remote = github.parse_remote(base_remote_url)
24 |
25 | if default_branch_only is None:
26 | default_branch_only = self.savvy_settings.get("sparse_fork", True)
27 | self.window.status_message(START_CREATE_MESSAGE.format(repo=base_remote.url))
28 | result = github.create_fork(base_remote, default_branch_only=default_branch_only)
29 | util.debug.add_to_log({"github: fork result": result})
30 |
31 | url = (
32 | result["ssh_url"]
33 | if base_remote_url.startswith("git@")
34 | else result["clone_url"]
35 | )
36 | for remote_name, remote_url in remotes.items():
37 | if remote_url == url:
38 | sublime.ok_cancel_dialog(
39 | "You forked previously! "
40 | "The fork is available under the name '{}'."
41 | .format(remote_name)
42 | )
43 | break
44 | else:
45 | self.window.status_message(END_CREATE_MESSAGE)
46 | self.window.run_command("gs_remote_add", {
47 | "url": url,
48 | "set_as_push_default": True
49 | })
50 |
--------------------------------------------------------------------------------
/github/commands/create_repo.py:
--------------------------------------------------------------------------------
1 | from functools import partial
2 | import os
3 |
4 | from GitSavvy.common import util
5 | from GitSavvy.core.base_commands import GsWindowCommand
6 | from GitSavvy.core.ui_mixins.input_panel import show_single_line_input_panel
7 | from GitSavvy.core.utils import show_panel
8 | from GitSavvy.core.runtime import on_worker
9 | from GitSavvy.github import github
10 |
11 | from GitSavvy.core.base_commands import Args, GsCommand, Kont
12 |
13 |
14 | __all__ = (
15 | "gs_github_create_repo",
16 | )
17 |
18 |
19 | def ask_for_repo_name(cmd: GsCommand, args: Args, done: Kont) -> None:
20 | suggestion = (
21 | os.path.basename(folders[0])
22 | if (folders := cmd.window.folders())
23 | else ""
24 | )
25 |
26 | def on_done(name: str) -> None:
27 | if name:
28 | done(name)
29 |
30 | show_single_line_input_panel("New Repo Name:", suggestion, on_done)
31 |
32 |
33 | def get_github_user_token(cmd: GsCommand, args: Args, done: Kont) -> None:
34 | fqdn = "github.com"
35 | token = cmd.savvy_settings.get("api_tokens", {}).get(fqdn)
36 | if not token:
37 | cmd.window.status_message(f"Abort, no API token found in the settings for {fqdn}.")
38 | return
39 | done(token)
40 |
41 |
42 | class gs_github_create_repo(GsWindowCommand):
43 | defaults = {
44 | "token": get_github_user_token,
45 | "name": ask_for_repo_name
46 | }
47 |
48 | @on_worker
49 | def run(self, token: str, name: str) -> None:
50 | payload = github.create_user_repo(token, name)
51 | self.window.status_message("The repo was created successfully.")
52 | urls = [payload["clone_url"], payload["ssh_url"]]
53 |
54 | def on_remote_name(name: str) -> None:
55 | show_panel(self.window, urls, partial(on_url, name))
56 |
57 | def on_url(name: str, idx: int) -> None:
58 | url = urls[idx]
59 | self.git("remote", "add", name, url)
60 | self.window.status_message("The new remote was added successfully.")
61 | util.view.refresh_gitsavvy_interfaces(self.window)
62 |
63 | show_single_line_input_panel("Add repo as", "origin", on_remote_name)
64 |
--------------------------------------------------------------------------------
/github/commands/open_issue.py:
--------------------------------------------------------------------------------
1 | from webbrowser import open as open_in_browser
2 |
3 | import sublime
4 | from sublime_plugin import EventListener, TextCommand
5 |
6 | from GitSavvy.core.utils import flash
7 | from GitSavvy.core.git_command import GitCommand
8 | from .. import github, git_mixins
9 |
10 |
11 | __all__ = (
12 | "gs_github_open_issue_at_cursor",
13 | "gs_github_hover_on_issues_controller",
14 | )
15 |
16 |
17 | ISSUE_SCOPES = "meta.git-savvy.issue-reference"
18 |
19 |
20 | class gs_github_open_issue_at_cursor(TextCommand, git_mixins.GithubRemotesMixin, GitCommand):
21 | def run(self, edit, point=None, open_popup=False):
22 | view = self.view
23 | if point is None:
24 | point = view.sel()[0].begin()
25 |
26 | if not view.match_selector(point, ISSUE_SCOPES):
27 | flash(view, "Not on an issue or pr name.")
28 | return
29 |
30 | def on_navigate(href: str):
31 | open_in_browser(href)
32 |
33 | issue_str = view.substr(view.extract_scope(point))
34 | url = self.url_for_issue(issue_str)
35 |
36 | if open_popup:
37 | view.show_popup(
38 | '{url}'.format(url=url),
39 | flags=sublime.HIDE_ON_MOUSE_MOVE_AWAY,
40 | location=point,
41 | max_width=1000,
42 | on_navigate=on_navigate
43 | )
44 | else:
45 | open_in_browser(url)
46 |
47 | def url_for_issue(self, issue_str: str) -> str:
48 | remotes = self.get_remotes()
49 | base_remote_name = self.get_integrated_remote_name(remotes)
50 | base_remote_url = remotes[base_remote_name]
51 | base_remote = github.parse_remote(base_remote_url)
52 |
53 | prefix, issue_nr = issue_str.split('#')
54 | url = f"{base_remote.url}/issues/{issue_nr}"
55 | if prefix:
56 | return url.replace(
57 | f"/{base_remote.owner}/{base_remote.repo}/",
58 | f"/{prefix}/"
59 | )
60 | return url
61 |
62 |
63 | class gs_github_hover_on_issues_controller(EventListener):
64 | def on_hover(self, view, point, hover_zone):
65 | # type: (sublime.View, int, int) -> None
66 | if (
67 | hover_zone == sublime.HOVER_TEXT
68 | and view.match_selector(point, ISSUE_SCOPES)
69 | ):
70 | view.run_command("gs_github_open_issue_at_cursor", {
71 | "point": point,
72 | "open_popup": True
73 | })
74 |
--------------------------------------------------------------------------------
/github/git_mixins/__init__.py:
--------------------------------------------------------------------------------
1 | from .remotes import *
2 |
--------------------------------------------------------------------------------
/github/git_mixins/remotes.py:
--------------------------------------------------------------------------------
1 | from GitSavvy.core.git_mixins.branches import Upstream
2 |
3 | from typing import Dict, Optional, TYPE_CHECKING
4 | name = str
5 | url = str
6 |
7 | if TYPE_CHECKING:
8 | from GitSavvy.core.git_command import GitCommand
9 | base = GitCommand
10 | else:
11 | base = object
12 |
13 |
14 | NOTSET = ""
15 | UPSTREAM_NOT_SET = Upstream("", "", "", "")
16 |
17 |
18 | class GithubRemotesMixin(base):
19 | def read_gitsavvy_config(self):
20 | # type: () -> Dict[str, str]
21 | return dict(
22 | line[9:].split()
23 | for line in self.git(
24 | "config",
25 | "--get-regex",
26 | r"^gitsavvy\..*",
27 | throw_on_error=False
28 | ).splitlines()
29 | )
30 |
31 | def get_integrated_branch_name(self):
32 | # type: () -> Optional[str]
33 | return self.read_gitsavvy_config().get("ghbranch")
34 |
35 | def get_integrated_remote_name(
36 | self,
37 | remotes,
38 | current_upstream=UPSTREAM_NOT_SET,
39 | configured_remote_name=NOTSET
40 | ):
41 | # type: (Dict[name, url], Optional[Upstream], Optional[str]) -> name
42 | if len(remotes) == 0:
43 | raise ValueError("GitHub integration will not function when no remotes defined.")
44 |
45 | if len(remotes) == 1:
46 | return list(remotes.keys())[0]
47 |
48 | if configured_remote_name is NOTSET:
49 | configured_remote_name = self.read_gitsavvy_config().get("ghremote")
50 | if configured_remote_name in remotes:
51 | return configured_remote_name
52 |
53 | for name in ("upstream", "origin"):
54 | if name in remotes:
55 | return name
56 |
57 | if current_upstream is UPSTREAM_NOT_SET:
58 | current_upstream = self.get_upstream_for_active_branch()
59 | if current_upstream:
60 | return current_upstream.remote
61 |
62 | raise ValueError("Cannot determine GitHub integrated remote.")
63 |
64 | def get_integrated_remote_url(self):
65 | # type: () -> url
66 | remotes = self.get_remotes()
67 | configured_remote_name = self.get_integrated_remote_name(remotes)
68 | return remotes[configured_remote_name]
69 |
70 | def guess_github_remote(self, remotes):
71 | # type: (Dict[name, url]) -> Optional[name]
72 | if len(remotes) == 1:
73 | return list(remotes.keys())[0]
74 |
75 | upstream = self.get_upstream_for_active_branch()
76 | integrated_remote = self.get_integrated_remote_name(remotes, current_upstream=upstream)
77 | if upstream:
78 | tracked_remote = upstream.remote
79 | if tracked_remote != integrated_remote:
80 | return None
81 |
82 | return integrated_remote
83 |
--------------------------------------------------------------------------------
/gitlab/__init__.py:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/timbrel/GitSavvy/f0c9067eb061498ba7a07960e5cbaefb414b4994/gitlab/__init__.py
--------------------------------------------------------------------------------
/gitlab/commands/__init__.py:
--------------------------------------------------------------------------------
1 | from .open_on_remote import *
2 | # from .commit import *
3 | from .configure import *
4 | # from .create_fork import *
5 | # from .add_fork_as_remote import *
6 | from .merge_request import *
7 |
--------------------------------------------------------------------------------
/gitlab/commands/configure.py:
--------------------------------------------------------------------------------
1 | import sublime
2 | from sublime_plugin import WindowCommand
3 |
4 | from ..git_mixins import GitLabRemotesMixin
5 | from ...core.git_command import GitCommand
6 | from ...core.ui_mixins.quick_panel import show_branch_panel
7 |
8 |
9 | __all__ = (
10 | "gs_gitlab_configure_remote",
11 | )
12 |
13 |
14 | class gs_gitlab_configure_remote(WindowCommand, GitLabRemotesMixin, GitCommand):
15 |
16 | def run(self):
17 | sublime.set_timeout_async(self.run_async)
18 |
19 | def run_async(self):
20 | show_branch_panel(
21 | self.on_branch_selection,
22 | ask_remote_first=True,
23 | selected_branch=self.get_integrated_branch_name()
24 | )
25 |
26 | def on_branch_selection(self, branch):
27 | """
28 | After the user selects a branch, configure integrated remote branch.
29 | """
30 | remote, remote_branch = branch.split("/", 1)
31 |
32 | self.git("config", "--local", "--unset-all", "GitSavvy.glRemote", throw_on_error=False)
33 | self.git("config", "--local", "--add", "GitSavvy.glRemote", remote)
34 |
35 | self.git("config", "--local", "--unset-all", "GitSavvy.glBranch", throw_on_error=False)
36 | self.git("config", "--local", "--add", "GitSavvy.glBranch", remote_branch)
37 |
38 | sublime.status_message("Successfully configured GitLab integration.")
39 |
--------------------------------------------------------------------------------
/gitlab/git_mixins/__init__.py:
--------------------------------------------------------------------------------
1 | from .remotes import *
2 |
--------------------------------------------------------------------------------
/gitlab/git_mixins/remotes.py:
--------------------------------------------------------------------------------
1 | from GitSavvy.core.git_mixins.branches import Upstream
2 |
3 |
4 | from typing import Dict, Optional, TYPE_CHECKING
5 | name = str
6 | url = str
7 |
8 | if TYPE_CHECKING:
9 | from GitSavvy.core.git_command import GitCommand
10 | base = GitCommand
11 | else:
12 | base = object
13 |
14 |
15 | NOTSET = ""
16 | UPSTREAM_NOT_SET = Upstream("", "", "", "")
17 |
18 |
19 | class GitLabRemotesMixin(base):
20 | def read_gitsavvy_config(self):
21 | # type: () -> Dict[str, str]
22 | return dict(
23 | line[9:].split()
24 | for line in self.git(
25 | "config",
26 | "--get-regex",
27 | r"^gitsavvy\..*",
28 | throw_on_error=False
29 | ).splitlines()
30 | )
31 |
32 | def get_integrated_branch_name(self):
33 | # type: () -> Optional[str]
34 | return self.read_gitsavvy_config().get("glbranch")
35 |
36 | def get_integrated_remote_name(
37 | self,
38 | remotes,
39 | current_upstream=UPSTREAM_NOT_SET,
40 | configured_remote_name=NOTSET
41 | ):
42 | # type: (Dict[name, url], Optional[Upstream], Optional[str]) -> name
43 | if len(remotes) == 0:
44 | raise ValueError("GitLab integration will not function when no remotes defined.")
45 |
46 | if len(remotes) == 1:
47 | return list(remotes.keys())[0]
48 |
49 | if configured_remote_name is NOTSET:
50 | configured_remote_name = self.read_gitsavvy_config().get("glremote")
51 | if configured_remote_name in remotes:
52 | return configured_remote_name
53 |
54 | for name in ("upstream", "origin"):
55 | if name in remotes:
56 | return name
57 |
58 | if current_upstream is UPSTREAM_NOT_SET:
59 | current_upstream = self.get_upstream_for_active_branch()
60 | if current_upstream:
61 | return current_upstream.remote
62 |
63 | raise ValueError("Cannot determine GitLab integrated remote.")
64 |
65 | def get_integrated_remote_url(self):
66 | # type: () -> url
67 | remotes = self.get_remotes()
68 | configured_remote_name = self.get_integrated_remote_name(remotes)
69 | return remotes[configured_remote_name]
70 |
71 | def guess_gitlab_remote(self, remotes):
72 | # type: (Dict[name, url]) -> Optional[name]
73 | if len(remotes) == 1:
74 | return list(remotes.keys())[0]
75 |
76 | upstream = self.get_upstream_for_active_branch()
77 | integrated_remote = self.get_integrated_remote_name(remotes, current_upstream=upstream)
78 | if upstream:
79 | tracked_remote = upstream.remote
80 | if tracked_remote != integrated_remote:
81 | return None
82 |
83 | return integrated_remote
84 |
--------------------------------------------------------------------------------
/messages.json:
--------------------------------------------------------------------------------
1 | {
2 | "install": "messages/install.txt",
3 | "1.1.0": "messages/1.1.0.txt",
4 | "1.2.0": "messages/1.2.0.txt",
5 | "1.3.1": "messages/1.3.1.txt",
6 | "1.4.1": "messages/1.4.0.txt",
7 | "2.0.0": "messages/2.0.0.txt",
8 | "2.1.0": "messages/2.1.0.txt",
9 | "2.2.0": "messages/2.2.0.txt",
10 | "2.3.0": "messages/2.3.0.txt",
11 | "2.4.0": "messages/2.4.0.txt",
12 | "2.5.0": "messages/2.5.0.txt",
13 | "2.6.0": "messages/2.6.0.txt",
14 | "2.7.0": "messages/2.7.0.txt",
15 | "2.8.0": "messages/2.8.0.txt",
16 | "2.9.0": "messages/2.9.0.txt",
17 | "2.10.0": "messages/2.10.0.txt",
18 | "2.11.0": "messages/2.11.0.txt",
19 | "2.12.0": "messages/2.12.0.txt",
20 | "2.12.1": "messages/2.12.1.txt",
21 | "2.13.0": "messages/2.13.0.txt",
22 | "2.14.0": "messages/2.14.0.txt",
23 | "2.14.1": "messages/2.14.1.txt",
24 | "2.14.2": "messages/2.14.2.txt",
25 | "2.16.2": "messages/2.16.2.txt",
26 | "2.16.4": "messages/2.16.4.txt",
27 | "2.16.5": "messages/2.16.5.txt",
28 | "2.16.6": "messages/2.16.6.txt",
29 | "2.16.7": "messages/2.16.7.txt",
30 | "2.17.0": "messages/2.17.0.txt",
31 | "2.17.1": "messages/2.17.1.txt",
32 | "2.17.3": "messages/2.17.3.txt",
33 | "2.17.4": "messages/2.17.4.txt",
34 | "2.18.0": "messages/2.18.0.txt",
35 | "2.19.0": "messages/2.19.0.txt",
36 | "2.20.0": "messages/2.20.0.txt",
37 | "2.21.0": "messages/2.21.0.txt",
38 | "2.22.0": "messages/2.22.0.txt",
39 | "2.23.0": "messages/2.23.0.txt",
40 | "2.25.0": "messages/2.25.0.txt",
41 | "2.26.0": "messages/2.26.0.txt",
42 | "2.27.0": "messages/2.27.0.txt",
43 | "2.28.0": "messages/2.28.0.txt",
44 | "2.30.0": "messages/2.30.0.txt",
45 | "2.31.0": "messages/2.31.0.txt",
46 | "2.34.0": "messages/2.34.0.txt",
47 | "2.36.0": "messages/2.36.0.txt",
48 | "2.38.0": "messages/2.38.0.txt",
49 | "2.39.0": "messages/2.39.0.txt",
50 | "2.41.0": "messages/2.41.0.txt",
51 | "2.42.0": "messages/2.42.0.txt"
52 | }
53 |
--------------------------------------------------------------------------------
/messages/1.1.0.txt:
--------------------------------------------------------------------------------
1 | Changes since 1.0.0:
2 |
3 | Features:
4 | - Always enable panel output for specified commands with `show_panel_for`.
5 | - Record input/output of git commands and make available as JSON.
6 | - `git: generate changelog` based on commit history since ref.
7 | - Add configurable colors for inline-diff view.
8 | - Add an option to show a diff in the commit view.
9 | - Add a keybinding to the commit view to easily sign off commits.
10 |
11 | UX:
12 | - Prompt user when making destructive changes (e.g. discarding).
13 |
14 | Bugs:
15 | - Avoid empty sublime.Region for removed newline.
16 | - Fix forward slash ignoring on branch names.
17 | - Correct GitHub URL for users who copy/paste address out of browser (without `.git`)
18 |
19 | Other:
20 | - README updates.
21 |
22 | Contributors:
23 | - Oliver Hoffmann
24 | - Dale Bustad
25 | - Ethan Bustad
26 | - Philipp Klose
27 | - Harel
28 | - Adrian L Lange
29 |
--------------------------------------------------------------------------------
/messages/1.2.0.txt:
--------------------------------------------------------------------------------
1 | Changes since 1.1.0:
2 |
3 | Feature:
4 | - Show Git status in ST3 status bar (can be disabled in settings file).
5 | - Add `git: push to remote branch name` command to the palette.
6 |
7 | Enhancement:
8 | - Correct branch pattern matching when generating status dashboard.
9 | - Add Undo feature to inline-diff view. Useful if you mistakenly blow away a hunk.
10 | - Disable Vintageous in status view.
11 | - Add HEAD commit hash to status view.
12 | - Add an option to suppress the command line args when outputting to a panel.
13 |
14 | Fix:
15 | - Inline-diff would not display/behave correctly for files not ending in newline.
16 | - Git blame failed for files with boundary commits.
17 | - `git: push to branch` would fail when remote branch doesn't exist.
18 | - Fetching would fail when more than one remote.
19 | - Correct protection for destructive actions.
20 |
21 | Contributors:
22 | - Ethan Bustad
23 | - Dale Bustad
24 | - Adrian L Lange
25 | - Jeff Langston
26 |
--------------------------------------------------------------------------------
/messages/1.3.1.txt:
--------------------------------------------------------------------------------
1 | Changes since 1.2.0:
2 |
3 | Features:
4 | - New `git: branch` dashboard.
5 | - New `git: tags` dashboard.
6 | - New `git: checkout current file` palette command.
7 | - New `git: push (force)` command palette option.
8 |
9 | Under the hood:
10 | - Resumable UI interfaces with easy listener registration.
11 |
12 | Enhancements:
13 | - Customized Git arguments for `git: graph` palette command.
14 | - `git: graph` view shows remote branchs, has syntax highlighting, and can checkout and view commit.
15 | - Enable definition of global flags for specific Git commands.
16 |
17 | Fix:
18 | - Inline-diffs would fail to apply in certain cases in Windows.
19 | - Syntax-highlighting for branch names in status and branch dashboard views.
20 | - Parse branch output properly if local branch tracks remote but not ahead/behind.
21 | - Allow numbers in names for remote.
22 | - Display `git: log` quick panel before keypress in Windows.
23 | - Create cursor at pos 0 in stash view, not in status view.
24 | - Annoying error when opening new window, due to status bar changes.
25 |
26 | Contributors:
27 | - Adrian L Lange
28 | - Nicolás Santángelo
29 | - Dale Bustad
30 | - Laas Toom
31 |
--------------------------------------------------------------------------------
/messages/1.4.0.txt:
--------------------------------------------------------------------------------
1 | Lots of changes recently, thanks to eveyone who has contributed and to those who have reported and discussed issues!
2 |
3 | Changes since 1.3.0:
4 |
5 | Enhancement:
6 | - Last-used remote for push, pull, and fetch palette commands will be pre-selected.
7 | - User can now select which remote to use for GitHub integration.
8 | - Inline-diff view will highlight words that have changed.
9 | - GitSavvy will offer to set tracking branch on `git: push` when unconfigured.
10 | - Status view can now discard untracked files.
11 | - Re-use existing interface if present.
12 | - Remote refs will be pruned on fetch.
13 | - Fetch added to branch dashboard.
14 | - Optionally scroll to first change in inline-diff view.
15 | - Now possible to commit from quick stage panel.
16 |
17 | Refactor:
18 | - GitSavvy syntax-files no longer show in command palette.
19 | - When commiting including unstaged files, use `git commit -a`.
20 | - Port status dashboard to new UI Interface paradigm.
21 | - Minutia.
22 |
23 | Fix:
24 | - Only offer init once for view with missing `.git` directory.
25 | - Cursor position was inconsistent when interfaces would re-render.
26 | - Fragile handling of repo_path in edge conditions.
27 | - Ensure interfaces are ready when plugins finish loading.
28 | - Error would display when file opened at non-real path.
29 | - Incorrect behavior when deleting remote branches from branch dashboard.
30 | - RegEx for detecting sections in blame view worked but too permissive.
31 | - GitHub issue integration would not work in some environments.
32 | - Debug reload would break interface refresh.
33 |
34 | Documentation:
35 | - Add Codacy badge to README.
36 | - Add branch/tag dashboard to README.
37 | - Show correct contextual help for diff view.
38 | - Update README with new highlights.
39 |
40 | Contributors:
41 | - Nicolás Santángelo
42 | - Josh Goebel
43 | - Dale Bustad
44 |
--------------------------------------------------------------------------------
/messages/2.0.0.txt:
--------------------------------------------------------------------------------
1 | # GitSavvy 2.0
2 |
3 | Things have been moving a bit more slowly with GitSavvy lately, but 2.0 brings
4 | a significant new feature: the **rebase dashboard**.
5 |
6 | The dashboard will show all commits made since the last common ancestor. You
7 | can take action on those commits, including the ability to re-order, edit
8 | commit messages, and squash. Once you've started an actual rebase (this is
9 | distinguished from the other actions in the dashboard), any conflicts will
10 | be displayed and you'll have options for resolving.
11 |
12 | If you've used `git rebase --interactive` from the terminal, there may be one surprise in that all actions take _immediate_ effect. However, the dashboard
13 | also supports unlimited Undo/Redo. The goal is to make rebase accessible for
14 | users that aren't familiar - if you have any UX feedback, please open an issue.
15 |
16 | Changes since 1.4.1:
17 |
18 | Features:
19 | - Rebase dashboard, including re-ordering, squashing, message editing, conflict resolution, and undo/redo.
20 |
21 | Enhancement:
22 | - Add option to append customized message to the default commit help.
23 |
24 | UX:
25 | - Move unstaged and untracked sections to top of status dashboard.
26 | - Don't include `--no-columns` flag on `git branch`.
27 | - Add space in `git: merge` palette between branch name and tracking info.
28 |
29 | Bug:
30 | - Native line-ending was used on Windows when autocrlf is false.
31 | - When staging directory, ignored files were also staged.
32 | - Status dashboard would not display after `git init`.
33 | - Update key-bindings on Linux to use CTRL-* instead of SUPER-*.
34 | - Status dashboard failed to render; stash list didn't include "WIP on branchname".
35 |
36 | Contributors:
37 | - Dale Bustad
38 | - old9
39 |
--------------------------------------------------------------------------------
/messages/2.1.0.txt:
--------------------------------------------------------------------------------
1 | Changes since 2.0.0:
2 |
3 | Feature:
4 | - Easily add GitHub fork as local remote.
5 |
6 | Enhancement:
7 | - Checkout remote branch as local in branch dashboard.
8 | - Support ignoring EOL whitespace in inline diff view.
9 |
10 | Bug:
11 | - Rebase edit would fail when content contained format key.
12 | - Branch names with dots would not always be recognized.
13 |
14 | Contributors:
15 | - Dale Bustad
16 | - David Devlin
17 | - Pavel Savchenko
18 |
--------------------------------------------------------------------------------
/messages/2.10.0.txt:
--------------------------------------------------------------------------------
1 | Changes since 2.9.1:
2 |
3 | Feature:
4 | - Log by author prompt with a list of committers
5 | - Use `Goto Symbol` to navigate in all views
6 | - Add `git add --edit` equivalent.
7 | - Add and remove remotes
8 | - resolve conflict (stage merged file) on successful merge
9 | - allow prompt to specify custom command argument
10 | - Use sublime new syntax file
11 |
12 | Enhancement:
13 | - Squash in rebase dashboard now behaves like `git rebase -i`.
14 | - Move cursor in rebase dashboard when moving commits up/down.
15 | - Rebase dashboard actions only effect selected commit and those that follow.
16 | - Drop commit from rebase dashboard.
17 |
18 | Fix:
19 | - Launching merge tool would fail for non-ASCII files.
20 | - Could not squash into first commit after squash direction change.
21 | - plugin_host would crash when navigating past end of graph view
22 | - When amending, prepopulated commit message would include two extra spaces.
23 | - When amending with show_commit_diff enabled, unstaged changes were displayed.
24 | - Update language definition for non-trailing spaces
25 | - Set tab size for dashboards to enable code folding for sections.
26 | - Allow user to disable display of branch descriptions.
27 |
28 | Improve:
29 | - Blame syntax
30 | - Graph syntax
31 | - Diff syntax
32 | - Inline diff syntax
33 | - Update blame syntax
34 | - Make_commit syntax
35 | - Diff syntax
36 | - Show_commit syntax
37 | - Graph syntax
38 | - Tags syntax
39 | - Rebase syntax
40 | - Branch syntax
41 | - Status syntax
42 |
43 | Contributors:
44 | - David Devlin
45 | - Felix
46 | - Pavel Savchenko
47 | - Dave Nicolson
48 | - gwenzek
49 | - Simon
50 | - Randy Lai
51 | - Dale Bustad
52 |
--------------------------------------------------------------------------------
/messages/2.11.0.txt:
--------------------------------------------------------------------------------
1 | Hey everybody,
2 |
3 | There are a lot of changes and refinements in this release. Remember to reach out to us on Gitter[0] or open an issue[1] if you run into any problems, and thanks for using GitSavvy!
4 |
5 | [0]: https://gitter.im/divmain/GitSavvy
6 | [1]: https://github.com/divmain/GitSavvy/issues
7 |
8 |
9 | ### Changes since 2.10.0 ###
10 |
11 | Feature:
12 | - Cherry-pick from Branch Commit Comparison view.
13 | - New commands to add and remove remotes.
14 |
15 | Enhancement:
16 | - Inline-diff and diff views are now re-used for the same file.
17 | - GitSavvy color schemes no longer appear in Sublime's color scheme menu.
18 | - Help menus can now be hidden in dashboards.
19 | - After fetching, user is now prompted to fetch the remote.
20 | - Branch view now support simultaneous merging from multiple branches.
21 | - Lots of improvements to GitSavvy internal syntaxes and dashboard UIs.
22 | - Tags in tag dashboard are now sorted with semver.
23 | - Improve experience when using Sublime as editor for terminal-based interactive rebase.
24 | - `git: blame` and `git: log` quick panels now remember previously selected option.
25 | - Show keyboard shortcuts for graph view in a popup.
26 | - Users can now augment the execution environment of custom Git commands.
27 | - Add easy access to GitSavvy settings.
28 | - Navigate with . and , in the Rebase dashboard, plus
29 | - Navigate with . and , in the Tag dashboard.
30 | - Dashboards also include Vintageous-friendly navigation key-bindings.
31 | - Index syntax files asynchronously, to avoid blocking Sublime startup.
32 | - Default to selecting the active remove in quick panels.
33 | - Prompt for remote tracking branch when opening a GitHub pull request.
34 |
35 | Fix:
36 | - Rebase dashboard actions would be allowed with working directory in unclean state.
37 | - Ignoring files would result in "# added by GitSavvy" added to `.gitignore` file.
38 | - Log view commands were not functioning correctly.
39 | - Status dashboard key-bindings did not work for files starting with `.`
40 | - User was unable to view tag commit when remotes were not displayed in tags dashboard.
41 | - Syntax highlighting failed in dashboard for SHA1 refs longer than 7 characters.
42 | - GitSavvy would fail to load on some platforms due to `yaml` missing from standard library.
43 |
44 | Internal:
45 | - Revamped debug reload using import hooks.
46 |
47 |
48 | ### Contributors ###
49 |
50 | - David Nicolson
51 | - Dale Bustad
52 | - Petr Marek
53 | - Eldar Abusalimov
54 | - laggingreflex
55 | - Simon
56 | - Shadab Zafar
57 | - Allen Bargi
58 | - Sindri Guðmundsson
59 | - Pavel Savchenko
60 | - Randy Lai
61 | - MJ
62 |
--------------------------------------------------------------------------------
/messages/2.12.0.txt:
--------------------------------------------------------------------------------
1 | Changes since 2.11.0:
2 |
3 | Enhancement:
4 | - Add a smart-tag key-binding to the Tags dashboard.
5 | - Don't prompt for a remote when there is only one.
6 |
7 | Fix:
8 | - Clean up refresh and output in status-bar for custom Git commands.
9 | - Caching of pre-rebase state was broken.
10 | - Tag dashboard commands would fail due to command scope context mismatch.
11 |
12 | Internal:
13 | - Reorganize active-branch related code.
14 | - Update contribution guidelines for commit subject structure.
15 | - Add debug tracing and fancy output for GitSavvy debug reloads.
16 |
17 | Contributors:
18 | - Randy Lai
19 | - Dale Bustad
20 | - Eldar Abusalimov
21 |
--------------------------------------------------------------------------------
/messages/2.14.0.txt:
--------------------------------------------------------------------------------
1 | I want to give a big thank-you to Pavel, Randy, and Simon for all of their work on GitSavvy. I've been busy on other projects, and they've been managing PRs and moving things forward significantly.
2 |
3 | Here are the changes since 2.13.0:
4 |
5 | New feature:
6 | - `git: show current file at commit`
7 | - Proper `git: clone` support.
8 |
9 | Enhancement:
10 | - Improved keyboard navigation in dashboards.
11 | - Improved git-log functionality.
12 | - Enable preservation of merges while rebasing.
13 | - New shortcuts in the Bransh dashboard.
14 | - Add pagination to various palette commands.
15 | - Better status information when rebasing.
16 | - Include merge hash in changelog generation.
17 | - `git: push` asynchronously.
18 | - Status updates when pulling/pushing.
19 |
20 | Bug fixes:
21 | - Sidebar refresh tweaks.
22 |
23 | And several small tweaks, bug fixes, and internal refactors!
24 |
25 | Contributors:
26 | - Simon
27 | - Petr Marek
28 | - Randy Lai
29 | - Pavel Savchenko
30 |
--------------------------------------------------------------------------------
/messages/2.14.1.txt:
--------------------------------------------------------------------------------
1 | Changes since 2.14.0:
2 |
3 | Add:
4 | - Frequency limit on update status bar
5 | - Docs for `Signing your commits with GPG`
6 | - Support emoji in branch name
7 | - Allow user to stash only changes that have been staged.
8 |
9 | Enhancement:
10 | - Add setting to custom command to open in new buffer
11 | - Add setting to custom command to open with specific syntax
12 |
13 | Fix:
14 | - Encoding problems in inline diff
15 | - Clone doesn't need to be executed from a git repo
16 | - Trigger stash command outside of stash section
17 | - Dropping a stash is destructive, and will prompt before executed
18 | - support parsing "git://" remote URI to Github URL
19 |
20 | Contributors:
21 | - Simon
22 | - Randy Lai
23 | - Dale Bustad
24 | - Pavel Savchenko
25 |
--------------------------------------------------------------------------------
/messages/2.14.2.txt:
--------------------------------------------------------------------------------
1 | Changes since 2.14.1:
2 |
3 | Fix:
4 | - Show open inline diff if it already open form status dashboard
5 | - Push tags command is not blocking
6 | - added self.get_short_hash to honor core.abbrev settings (#642)
7 |
8 | Other:
9 | - Sort branches by recent commited (#632)
10 | - Check that file exist before opening (#648)
11 |
12 | Improvement:
13 | - Remove some clutter from debug.log (#635)
14 | - Warn the user when we have permission error (#636)
15 | - it is not necessary to check if HEAD is rebased
16 | - use message_dislog for show the messages
17 | - do not allow squashing merges
18 |
19 | Contributors:
20 | - Simon
21 | - Juan Pumarino
22 | - Pavel Savchenko
23 | - Vlad Tsepelev
24 | - Randy Lai
25 |
--------------------------------------------------------------------------------
/messages/2.16.4.txt:
--------------------------------------------------------------------------------
1 | Changes since 2.16.2:
2 |
3 | Enhancement:
4 | - don't show "following output" where stderr is empty
5 | - select the branch name while creating a new branch
6 |
7 | Internal:
8 | - add UnitTesting build system
9 | - maintainerd - don't enforce empty line
10 | - add ISSUE_TEMPLATE.md and PULL_REQUEST_TEMPLATE.md
11 |
12 | Fix:
13 | - typo in some keymaps: control -> ctrl
14 |
15 | Feature:
16 | - `github: create fork` to create fork on github
17 | - git stash in command panel
18 | - better selection of base ref branch
19 |
20 | Contributors:
21 | - Randy Lai
22 | - Simon
23 | - Pavel Savchenko
24 |
--------------------------------------------------------------------------------
/messages/2.16.5.txt:
--------------------------------------------------------------------------------
1 | Changes since 2.16.4:
2 |
3 | Fix:
4 | - various small bug fixes
5 |
6 | Enhancement:
7 | - Add some default syntax specific settings
8 | - Cache settings object for multi get/set operations
9 | - Super+, open settings for each of the different syntaxes
10 | - refactor blame command
11 | - Improvements to fetch quick panel
12 |
13 | Internal:
14 | - Add unittest for JSON resources
15 |
16 | Contributors:
17 | - DeathAxe
18 | - Randy Lai
19 | - Simon
20 | - David Devlin
21 |
--------------------------------------------------------------------------------
/messages/2.16.6.txt:
--------------------------------------------------------------------------------
1 | Changes since 2.16.5:
2 |
3 | New Feature:
4 | - Add mv command.
5 |
6 | Fix:
7 | - various small fixes
8 | - Use correct argument for blame all commits
9 | - fix ignoring file functionality
10 | - don't show "OS error" in rebase view
11 | - Commit view respect the include_unstaged
12 |
13 | Enhancement:
14 | - set the default for max_items_in_tags_dashboard to -1
15 | - select commit as base in rebase dashboard
16 |
17 | Contributors:
18 | - Randy Lai
19 | - David Arnold
20 | - Eric Huss
21 | - David Devlin
22 | - Simon
23 |
--------------------------------------------------------------------------------
/messages/2.16.7.txt:
--------------------------------------------------------------------------------
1 | Changes since 2.16.6:
2 |
3 | Feature:
4 | - quick stage and amend
5 | - git remote rename
6 |
7 | Enhancement:
8 | - show diff stat when `show_commit_diff` is "full".
9 | - show url when removing remote
10 | - manipulate commits with untracked files
11 | - reset to original commit after failure
12 | - fixup should be safe for untracked files
13 | - use ssh url instead of url when adding fork
14 | - support .sublime-color-scheme in inline diff view
15 | - git pull from remote tracking branch directly
16 | - refactor pull and pull with rebase
17 |
18 | Fix:
19 | - only show diff patch when `show_commit_diff` is "full"
20 |
21 | Contributors:
22 | - Randy Lai
23 |
--------------------------------------------------------------------------------
/messages/2.17.0.txt:
--------------------------------------------------------------------------------
1 | Changes since 2.16.6:
2 |
3 | Requirement:
4 | - bump git requirement, git v1.19.0 or above is required
5 |
6 | Feature:
7 | - quick stage and amend
8 | - git remote rename
9 | - implement GitLab merge request review
10 | - Pedantic commit messages
11 | - add helpers to handle merge conflicts in status dashboard
12 | - Live output: Show STDIN when present in live log
13 |
14 | Enhancement:
15 | - refreash UI when merge failed
16 | - add `abort rebase` command
17 | - Add a refresh_gitsavvy_interfaces PoC for bug #835
18 | - show diff stat when `show_commit_diff` is "full".
19 | - manipulate commits with untracked files
20 | - reset to original commit after failure
21 | - use ssh url instead of url when adding fork
22 | - support .sublime-color-scheme in inline diff view
23 | - git pull from remote tracking branch directly
24 | - use GsPullBase mixin
25 | - add pull with rebase
26 | - do commit synchronously when commit_on_close is true
27 | - make following file renames optional
28 | - rename `git: add (edit)` command
29 |
30 | Fix:
31 | - only show diff patch when `show_commit_diff` is "full"
32 | - use unicode to write .gitignore
33 | - hash tag sign is a valid char for branch name
34 | - load user specfic theme first
35 |
36 | Internal:
37 | - Use window.status_message instead of sublime.status_message
38 |
39 | Docs:
40 | - Add doc for setting PATH environment
41 |
42 | Contributors:
43 | - Guillaume Wenzek
44 | - Simon
45 | - Pavel Savchenko
46 | - Tom van Ommeren
47 | - Randy Lai
48 |
--------------------------------------------------------------------------------
/messages/2.17.1.txt:
--------------------------------------------------------------------------------
1 | Changes since 2.17.0:
2 |
3 | Enhancement:
4 | - use a more meanful branch name when reviewing PRs
5 |
6 | Fix:
7 | - fix show file bug on Windows
8 | - fix tag dashboard bug if hash length != 8
9 | - Pass startupinfo to `subprocess.check_output` on Windows
10 |
11 | Contributors:
12 | - herr kaste
13 | - Randy Lai
14 |
--------------------------------------------------------------------------------
/messages/2.17.3.txt:
--------------------------------------------------------------------------------
1 | Changes since 2.17.2:
2 |
3 | Enhancement:
4 | - support prefix in prerelease when using smart tag
5 | - support project-wise settings
6 | - make `rebase_default_base_ref` more consistant with project-wise settings
7 | - allow to use "git: blame current file" at blame view
8 | - Opening commit from commadline respect setting
9 |
10 | Feature:
11 | - git: checkout current file at commit
12 |
13 | Fix:
14 | - Pedantic commit checks allows comment on 2. line
15 | - On startup in-memory `instances` cache can be empty
16 | - fix set status on cherry-pick done
17 |
18 | Other:
19 | - Emphasize in docs when to use run_in_thread
20 | - Fix subprocess command crashing with OSError
21 | - Include A traceback when an exception happens and we don't handle it
22 |
23 |
24 | Contributors:
25 | - herr kaste
26 | - Simon
27 | - Randy Lai
28 | - Pavel Savchenko
29 | - joan
30 | - Maarten Nieber
31 |
--------------------------------------------------------------------------------
/messages/2.17.4.txt:
--------------------------------------------------------------------------------
1 | Changes since 2.17.3:
2 |
3 | Feature:
4 | - git push --force-with-lease
5 |
6 | Internal:
7 | - Refactor away show_commit_info from LogPanel (Merge 4dd2091)
8 | - LogPanel, disable highlight if on_highlight is't callable (Merge 4dd2091)
9 |
10 | Enhancement:
11 | - Move the project GitSavvy key into "settings"
12 | - Show reverse diff from commit to workspace for checking out files
13 | - expand home dir when cloning a project
14 | - refactor show_input_panel and disable modifier+enter keys in single line input panel
15 | - expand home dir when cloning a project
16 |
17 | Fix:
18 | - expose on_highlight to LogMixin
19 | - do not continue when the window is not a project
20 | - use fallback encoding to decode stderr
21 | - push selected non-tracking branch
22 |
23 | Contributors:
24 | - Pavel Savchenko
25 | - herr kaste
26 | - Simon
27 | - Randy Lai
28 |
--------------------------------------------------------------------------------
/messages/2.18.0.txt:
--------------------------------------------------------------------------------
1 | Changes since 2.17.6:
2 |
3 | Fix:
4 | - update status bar when the view is a widget
5 | - make sure project settings are loaded properly
6 | - fix a bug related to prompt_on_abort_commit
7 | - 'checkout file at commit' shows commit panel
8 | - sanitize ansi sequence
9 | - Fix theme generator for sublime-color-schemes
10 | - avoid splitlines in blame
11 |
12 | Enhancement:
13 | - Optimize status interface
14 | - Optimize log graph interface
15 | - improve diff view
16 | - rename `git: tags` to `git: tag`
17 | - honor prepare_commit_msg and pre_commit hooks
18 | - offer initialization for repo_path
19 | - Add more complex git output scopes to diff syntax
20 | - Add support for "env" settings and GIT_OPTIONAL_LOCKS
21 |
22 | Other:
23 | - Show toggle remotes help message only if there are any remotes (#1047)
24 | - Include flake8 config for convenience
25 | - Tag the line containing HEAD for styling purpopses (#1051)
26 | - Add test cases for log graph view not showing the panel initially (#1068)
27 | - Refresh graph view after checkout
28 |
29 | Feature:
30 | - Add GPG support via a wrapper
31 |
32 |
33 | Contributors:
34 | - Randy Lai
35 | - Simon
36 | - DeathAxe
37 | - herr kaste
38 | - luv
39 | - Pavel Savchenko
40 |
--------------------------------------------------------------------------------
/messages/2.19.0.txt:
--------------------------------------------------------------------------------
1 | Changes since 2.18.0:
2 |
3 | Features:
4 | Colorize the git graph
5 | Show references to commit in log panel
6 | Diff support increasing and reducing context lines, open a diff, click `+` or `-`, or `?` to get help
7 | Use tab to flip base and target in a diff view
8 | Improve the jumping from diff to file accuracy
9 | Diffing the same file twice only open one view
10 |
11 | Improvements
12 | Add `git: [graph|log] current branch` to command panel
13 | Remember last checked out branch so it can suggest that branch next time to checkout
14 | Speedup inline diff refreshing
15 | Don't block inline diff on huge files
16 | Always focus the interface when you open it
17 | When navigating ensure scroll is all the way left
18 | Don't propose to merge with self
19 | Fix checkout multiple files
20 | Stop leaking log
21 | Opening inline diff takes an argument to open inline diff on the same location, for more info look at #1137
22 |
23 | Internal
24 | Use flake8
25 | Simplify log commands
26 | When logging is enabled, log to console too
27 | Use safe_load to parse yaml
28 | Update reloader
29 | MyPy setup
30 |
31 | Contributors:
32 | - herr kaste
33 | - Simon
34 | - Pavel Savchenko
35 | - Luis Puerto
36 | - DeathAxe
37 |
--------------------------------------------------------------------------------
/messages/2.2.0.txt:
--------------------------------------------------------------------------------
1 | Changes since 2.1.0:
2 |
3 | Feature:
4 | - After selecting a commit from the `git: log` panel, you can now show the commit, compare that commit against your working directory, or compare that commit against the git index.
5 |
6 | Enhancement:
7 | - Navigation inside `git: graph` view.
8 | - Quick panel inside `git: graph` view, displaying extra commit info.
9 | - Add `git: graph all branches` command.
10 | - Make default comparison configurable in Rebase dashboard.
11 | - Validate branch name when creating.
12 |
13 | Bug:
14 | - `git push --force` would fail when no upstream set but upstream exists.
15 | - `super_key` was not set to `CTRL` on Linux
16 | - Branch status would not display correctly when remote tracking branch disappeared.
17 | - The inclusion of global Git flags would cause exclusion of dynamic args.
18 |
19 | Contributors:
20 | - Simon
21 | - Dale Bustad
22 | - Max Mykhailenko
23 | - David Devlin
24 |
--------------------------------------------------------------------------------
/messages/2.20.0.txt:
--------------------------------------------------------------------------------
1 | GitSavvy 2.20.0
2 | ===============
3 |
4 | - GitSavvy moved to https://github.com/timbrel/GitSavvy
5 |
6 | - Improve parsing and colorization of diffs in "word-diff" mode. Use
7 | `` to enter that mode as usual.
8 |
9 | - Improve the stash view.
10 | Enter the stash view e.g. from the status dashboard via ``. While
11 | looking at the stash try `>` for help, or just `` to see the
12 | available, typical actions.
13 |
14 | - Renovate the standard status view to fix a lot of small edge cases. Esp.
15 | improve the cursor jumping while staging/unstaging etc.
16 |
17 | - Fix newline handling on Windows when .gitignoring files. (@joreiff)
18 |
19 | We now ship code to reload the plugin after updates automatically and silently.
20 | This will be in full effect for the very next update you see.
21 |
22 |
23 | For more info:
24 | https://github.com/timbrel/GitSavvy/compare/2.19.1...2.20.0
25 |
--------------------------------------------------------------------------------
/messages/2.21.0.txt:
--------------------------------------------------------------------------------
1 | GitSavvy 2.21.0
2 | ===============
3 |
4 | - We now highlight intra-line differences when we show git-diffs.
5 | https://github.com/timbrel/GitSavvy/pull/1220
6 |
7 | For the annonations we use the scopes "diff.inserted.char.git-savvy.diff"
8 | and "diff.deleted.char.git-savvy.diff". These are the same scopes
9 | Sublime uses for their "Incremental Diff" feature (but namespaced with
10 | ".git-savvy.diff") so every user should see proper colors right
11 | away.
12 |
13 |
14 | For more info:
15 | https://github.com/timbrel/GitSavvy/compare/2.20.0...2.21.0
16 |
--------------------------------------------------------------------------------
/messages/2.22.0.txt:
--------------------------------------------------------------------------------
1 | GitSavvy 2.22.0
2 | ===============
3 |
4 | - Greatly improved graph view (`git: Repo History` or `git: File History` via
5 | the Command Palette)
6 |
7 | [ctrl+R] Goto symbols, tags, branches
8 | [h] Goto HEAD commit
9 | [enter] Open a menu with additonal actions, for example to checkout or
10 | remove a branch, reset HEAD, or to create or delete a tag.
11 | [o] To open the commit in a new view
12 | [m] Open or close a panel to always see the current commit details
13 |
14 | further experimental bindings
15 | [a] to toggle `--all`
16 | [f] to enter additional filter verbatim
17 | E.g. try `--reflog` or `-Ssearch_term`
18 |
19 | - Improved navigation with [oOg] throughout the application
20 |
21 | When viewing a commit:
22 | [o] To open the file revision at hunk position
23 | [O] To open the same file but currently checked out on disk
24 | [g] To open the graph showing the context of the commit
25 |
26 | When viewing a file revision:
27 | [o] To open the commit this revision belongs to
28 | [O] To open the same file but currently checked out on disk
29 | [g] To open the graph showing the context of said commit
30 |
31 | From the status dashboard
32 | [g] To open the graph showing HEAD
33 |
34 | From the branches dashboard
35 | [g] To open the graph showing the selected branch
36 |
37 |
38 | For more info:
39 | https://github.com/timbrel/GitSavvy/compare/2.21.0...2.22.0
40 |
--------------------------------------------------------------------------------
/messages/2.23.0.txt:
--------------------------------------------------------------------------------
1 | GitSavvy 2.23.0
2 | ===============
3 |
4 | - Improved "inline diff" experience (`git: diff current file inline`) (#1306)
5 |
6 | It is recommended to bind `gs_inline_diff` to a key combo so it becomes a main
7 | entry point into the GitSavvy world. E.g.
8 |
9 | ```
10 | {
11 | "keys": ["ctrl+shift+["],
12 | "command": "gs_inline_diff",
13 | },
14 | ```
15 |
16 | Now, this key acts like a toggle. You press it to switch to the inline view.
17 | Press it again to close it. This should give you a experience very close to
18 | Sublime Text's built in `toggle_inline_diff` ("Show Diff Hunk") feature.
19 |
20 | However, being in that view, you can of course stage, undo staging, or discard
21 | changes.
22 |
23 | Use `[TAB]` to switch between the staged and unstaged area.
24 |
25 | Use `[c]` (commit stage), `[C]` (commit -a) or `[m]` (amend commit from stage)
26 | to enter the commit message view. Tip: These commands are also available for
27 | the "normal" diff view `git: diff` (command name: `gs_diff`).
28 |
29 | Notable: We now use the builtin color scopes (just like the intra line
30 | colorization for the normal diff views does). The Sublime Text scopes (e.g.
31 | "diff.inserted.char") are suffixed with ".git-savvy.inline-diff".
32 |
33 | A lot of bugs have been fixed for this view as well.
34 |
35 |
36 | - GitSavvy learned a new command `gs_stage_hunk` (#1305)
37 |
38 | The command works from normal views t.i. while editing your files. Note that
39 | we don't ship any bindings. If you want to use this feature, it is expected you
40 | bind it to a key combo, the Command Palette, or maybe the context menu on your
41 | own. E.g.
42 |
43 | ```
44 | { "keys": ["ctrl+alt+s"], "command": "gs_stage_hunk"},
45 | ```
46 |
47 | Now having this binding, you can stage "hunks" directly from the file.
48 | This works best with the default Sublime Text settings:
49 |
50 | ```
51 | "mini_diff": true, // or "auto"
52 | "show_git_status": true,
53 | "git_diff_target": "index", // !
54 | ```
55 |
56 | With these settings, the Sublime gutter will show you the modified lines.
57 |
58 | Just try it! Edit some lines, hit the key combo, and the gutter will reflect
59 | that immediately. Btw, the commands supports single and multiple cursors, and
60 | single or multiple selections.
61 |
62 | If that's your next quick workflow, maybe consider the following binding
63 |
64 | ```
65 | {
66 | "keys": ["ctrl+shift+["],
67 | "command": "gs_inline_diff",
68 | "args": { "cached": true }
69 | },
70 | ```
71 |
72 | so you can quickly see the staged hunks, maybe to unstage, but of course to
73 | enter the commit process using `[cCm]`.
74 |
75 |
76 | For more info:
77 | https://github.com/timbrel/GitSavvy/compare/2.22.0...2.23.0
78 |
79 |
--------------------------------------------------------------------------------
/messages/2.25.0.txt:
--------------------------------------------------------------------------------
1 | GitSavvy 2.25.0
2 | ===============
3 |
4 | - Improve historical "file view"
5 |
6 | When you look at a specific revision of a file (for example via
7 | `git: show current file at commit`) we now show diff markers in the gutter
8 | area.
9 |
10 | Use `[p]`/`[n]` to switch to a newer or older version of that file. You
11 | can also open an "inline diff" from here, using the Command Palette or
12 | preferable a key binding.
13 |
14 | A more typical work-flow to such a file revision is from a "graph view",
15 | either the `git: Repo History` or `git: File History`: press `[o]` to show
16 | the full commit, and then on a specific hunk `[o]` again to show the
17 | complete file at that revision.
18 |
19 | - You can now generally switch from the "normal" diff view to the
20 | "inline diff". This is useful if you want to see more of the context of a
21 | hunk. Esp. it enables you to stage single lines of a hunk which is still
22 | not implemented for the "normal" diff.
23 |
24 |
25 |
26 | For more info:
27 | https://github.com/timbrel/GitSavvy/compare/2.24.0...2.25.0
28 |
--------------------------------------------------------------------------------
/messages/2.26.0.txt:
--------------------------------------------------------------------------------
1 | GitSavvy 2.26.0
2 | ===============
3 |
4 | - Implement `git: Line History`
5 |
6 | A "Line History" (aka "log wtf" or "log why") basically calls
7 | "git log -Lx,y:". This is a supereasy to use tool in
8 | the editor. It is usually the faster (in terms of you get the info
9 | you're looking for faster) "blame" and also the faster "File History"
10 | because often you're only interested in some part of a file. Really
11 | answering "Why is this line or section of code here?".
12 |
13 | The command can be called from normal views only. Just put your cursor
14 | somewhere, or drag a selection, and call the command from the Command Palette.
15 | The command is called `gs_line_history` if you want to bind it to a key.
16 |
17 | Comes with:
18 | `[o]` to open the complete commit under the cursor
19 | `[O]` to open the file at that revision
20 | `[g]` to open the graph context
21 |
22 |
23 | - Improvements to the Repo History
24 |
25 | We already showed the path down while navigating through the history. Now
26 | we also follow and colorize the path upwards. (For customization: the scopes
27 | we use here are `git_savvy.graph.dot.above`, `git_savvy.graph.path_char.above`)
28 |
29 | This is not just fancy but allows easier and faster navigation:
30 |
31 | Use the arrow keys `[up]` and `[down]` to get to the previous or next commit.
32 | Use `[alt+up]` or `[alt+down]` for "wide" jumps usually following the first parent.
33 | After such a wide jump, you can use the built-in `jump_back`/`jump_forward`
34 | commands (for example `[ctrl+-]` on Windows/Linux by default) to jump back
35 | to the previous location.
36 |
37 |
38 | There is also a new smart copy function. Just invoke the builtin "copy"
39 | command (for example `[ctrl+c]`) to directly copy the commit hash, or commit
40 | message, or a combination of both to the clipboard (if nothing is selected).
41 |
42 |
43 | Minor: If on a HEAD commit we offer "pull", "push", and "fetch" in the
44 | actions menu (`[enter]`), and the diff action opens the normal diff for staging,
45 | unstaging etc.
46 |
47 | Finally, we now clearly mark fixup/squash commits. (The scope here is:
48 | `string.other.rebase-hint.git-savvy`.)
49 |
50 |
51 | - Improvements to the Commit Message View
52 |
53 | Being in the diff area, you can now use `[o]` on a hunk to open that location
54 | for editing. Also `[,.]` for navigation per hunk. But unstaging etc. is not
55 | supported yet.
56 |
57 |
58 | - Noteable
59 |
60 | Removed "word-diff" switch from the Diff view. This has been superseeded
61 | by the intraline diffing feature. There is still the switch to ignore white-
62 | space changes though, but the keybinding for that moved (from `[s]`) to `[w]`.
63 |
64 | The setting "show_commit_diff" now defaults to "full" (was: "stat").
65 | The setting "show_full_commit_info" now defaults to "true" (was: "false").
66 |
67 |
68 | For more info:
69 | https://github.com/timbrel/GitSavvy/compare/2.25.0...2.26.0
70 |
--------------------------------------------------------------------------------
/messages/2.28.0.txt:
--------------------------------------------------------------------------------
1 | GitSavvy 2.28.0
2 | ===============
3 |
4 | - Improvements to the Diff View
5 |
6 | The standard diff view now supports staging, unstaging, or discarding
7 | selections, for example single lines, and whole files.
8 |
9 | In consistency with the other views we bind `[sud]` to stage, unstage,
10 | or discard one hunk or the concrete selection. This works with multiple
11 | cursors and selections as well.
12 |
13 | Use the uppercase keys `[SUD]` to operate on whole files.
14 |
15 | "Zooming", t.i. changing how many context lines are shown, via `[+-]` has
16 | been greatly improved. It's actually useable and useful now.
17 |
18 | **Tip** If you want to stage several single lines from the same chunk,
19 | it is recommended to make use of multiple selections. We take that as a
20 | hint on which lines actually belong together and form symmetrical
21 | modifications.
22 |
23 |
24 | With this release we start to ship a series of refactorings as well. As a
25 | result, a few settings have been removed:
26 |
27 | - `live_panel_output` and `live_panel_output_timeout` as the feature has
28 | been reimplemented. We now always update the panel "live" if possible.
29 |
30 | - `close_panel_for` as this feature was poorly implemented.
31 |
32 | - `show_input_in_output`, `show_stdin_in_output`, `show_time_elapsed_in_output`
33 |
34 | You should not use them anymore and remove them from your user settings file.
35 |
36 |
37 |
38 | For more info:
39 | https://github.com/timbrel/GitSavvy/compare/2.27.7...2.28.0
40 |
--------------------------------------------------------------------------------
/messages/2.3.0.txt:
--------------------------------------------------------------------------------
1 | Changes since 2.2.1:
2 |
3 | Feature:
4 | - Git-Flow commands now supported (but disabled by default).
5 | - `git reset`, using either commit log or branch reflog.
6 | - Custom git commands now supported (see docs in README).
7 | - New branch history comparison in the Branch dashboard.
8 |
9 | Enhancement:
10 | - Rebase dashboard now handles case where master doesn't exist.
11 | - Add option to prompt before discarding and closing commit message window.
12 |
13 | Fix:
14 | - Several issues with inline-diff view behavior. BIG THANKS to @stoivo!
15 | - Branch matching regex did not match dots in remote branch name.
16 | - Branch dashboard failed to show branch when commit includes "..".
17 | - Rebase conflict shortcuts did not execute anywhere on line.
18 | - Stash shortcuts did not execute when cursor was at end of line.
19 | - Git fetch did not retrieve all data when no remote specified.
20 | - `global_flags` were not always placed correctly in Git command.
21 |
22 | Other:
23 | - Update contributor guidelines.
24 |
25 | Contributors:
26 | - Simon (@stoivo)
27 | - David Devlin
28 | - Pavel Savchenko
29 | - Dale Bustad
30 |
--------------------------------------------------------------------------------
/messages/2.30.0.txt:
--------------------------------------------------------------------------------
1 | GitSavvy 2.30.0
2 | ===============
3 |
4 | Two simple, quality-of-life improvements:
5 |
6 | - Open an GitHub issue or PR in the browser
7 |
8 | Whenever you see a link to an issue, for example looking at the Repo
9 | History or an individual commit, either hover over it to open a popup,
10 | or place the cursor on it and hit `[o]` to open the issue/PR page in
11 | your browser. (#1483)
12 |
13 |
14 | - Simplify wizard when pushing to a remote
15 |
16 | When pushing a branch to a remote the first time, for example prior
17 | to creating a PR on GitHub, we now guess a good remote and assume you
18 | don't want to have a different branch name than the local one on the
19 | remote. (#1475)
20 |
21 |
22 | Notable
23 |
24 | - For compatibility with the new Sublime Text 4, introduce syntax and
25 | settings for the basic output panel. And while we're at it, add some
26 | color touch. (#1484)
27 | - Correctly find and resolve `git_dir` for *workspaces*. (#1477)
28 | - Refactor how we update the workdir status and update the status dashboard
29 | in the background. Basically introducing a *reactive* framework. (#1478)
30 |
31 |
32 | Tip: Subscribe to the GitSavvy "releases" on GitHub to get a notification
33 | about a new version, and not be surprised on the next Sublime restart.
34 |
35 | :love:
36 |
--------------------------------------------------------------------------------
/messages/2.31.0.txt:
--------------------------------------------------------------------------------
1 | GitSavvy 2.31.0
2 | ===============
3 |
4 | - Revamped `git: clone` and `git: init`
5 |
6 | Both commands now find sane root folders for the ".git" repository.
7 |
8 | For `git: clone`, we suggest a sibling folder of the current open folder in
9 | the side-bar, and if there is none we fallback to `~`.
10 |
11 | Try it! Copy a URL from your browser, or for example
12 |
13 | `https://github.com/timbrel/GitSavvy/blob/master/README.md`
14 |
15 | Open a new window (`ctrl+shift+n`), open the Command Palette (`ctrl+p`),
16 | `git: clone`. And just leave the defaults.
17 |
18 | The idea is: Whenever you read code on GitHub, and it's getting complicated,
19 | grab it and read it in Sublime instead. You can "Go To Definition"s back and
20 | forth way faster.
21 |
22 |
23 | Want to contribute back?
24 |
25 | It's actually easy. Here's the workflow: `checkout new branch` (`cnb`), edit,
26 | then commit as usual. `create fork`, `create pull request` (`cpr`). Done.
27 |
28 |
29 |
30 |
31 |
--------------------------------------------------------------------------------
/messages/2.34.0.txt:
--------------------------------------------------------------------------------
1 | GitSavvy 2.34.0
2 | ===============
3 |
4 | Small things matter!
5 |
6 | - Add fixup helpers (bound to `[f]`) to the `diff`, `inline-diff`, and
7 | `Line History`. (#1567)
8 |
9 | - In the `Commit View` and `Line History` bind `[h]` to open the commit on
10 | GitHub in the browser. Also add a clickable annotation in the top right
11 | corner. (#1570)
12 |
13 | - For `github: open file on remote`, usually open the last-modified revision
14 | of the file. (#1571)
15 |
16 | - Automatically treat spaces as `-` (dashes) when asking for a new branch
17 | name. (#1557)
18 |
19 | - Add command to Command Palette (`git: rename current branch`) to rename
20 | the current, active branch. (#1558)
21 |
22 | - Add command `git: unset tracking branch` to remove the tracking information
23 | of the current branch (#1559)
24 |
25 | - Allow deletion of the currently checked out ("active") branch. (#1560)
26 |
27 | - Smooth(er), incidental drawing of the log graph view. (#1569)
28 |
29 | Indicate visually that we wait for a response from `git log graph` if it
30 | takes too long, or that we await and expect a complete re-draw (typical
31 | because a filter setting changed).
32 |
33 | - Make filenames clickable in views where we show patches. (#1556)
34 |
35 | - Mark the commit message view as lintable by SublimeLinter. (#1566)
36 |
37 |
38 |
39 | Fixes:
40 |
41 | - Fix validating branch name (#1554)
42 | - Fix diffstat colorization (#1555)
43 | - Ensure we checkout on the UI thread ("blocking") (#1561)
44 | - Fix highlighting of github usernames (#1562)
45 | - Fix commit message subject scopes and highlighting (#1563)
46 | - Fix intra line colorization of merge conflicted files (#1564)
47 | - Allow rebasing the initial (root) commit. (#1574)
48 |
--------------------------------------------------------------------------------
/messages/2.36.0.txt:
--------------------------------------------------------------------------------
1 | GitSavvy 2.36.0
2 | ===============
3 |
4 | Insane refactorings went into this one. And you don't even see them.
5 | Well, 🤞, at least I hope so.
6 |
7 | Still some user facing things of course:
8 |
9 | - Re-designed the "git: tag" dashboard
10 |
11 | - In the "Repo History" it is now possible to fast-forward a branch.
12 |
13 | Say you're on a feature branch checked out, and you know that e.g.
14 | your "main" branch moved.
15 |
16 | You can now just select the main branch, hit `[enter]` for the menu,
17 | and select `Fast forward 'main' to 'origin/main'` if you already
18 | fetched a new tip. Otherwise it says `Update 'main' from 'origin/main'`
19 | and fetches first before moving the branch.
20 |
21 | You stay on the feature branch during that process, and can rebase
22 | immediately after that.
23 |
24 | Very useful.
25 |
26 |
27 | Some of you might love and even rely on this little package GitSavvy,
28 | and I do drink coffee just like others. If that's a match consider
29 | donating at https://paypal.me/herrkaste 😉
30 |
31 |
32 | 🍁🍂
33 |
34 | Full release notes are on https://github.com/timbrel/GitSavvy/releases
35 | Just because I see I forgot to send any for 2.35.0
36 |
--------------------------------------------------------------------------------
/messages/2.38.0.txt:
--------------------------------------------------------------------------------
1 | GitSavvy 2.38.0
2 | ===============
3 |
4 |
5 | - The status dashboard has a slightly different design and better cursor
6 | management. Generally switching between the dashboards should be snappier.
7 |
8 | - `Repo History`s rebase menu (`[r]`) learned `--rebase-merges` and
9 | `--update-refs` tricks. Note that the latter requires git v2.38.0[*].
10 |
11 | With that we have sad news: the stand-alone "rebase" dashboard has been
12 | deprecated. Yep.
13 |
14 | The standard menu (`[enter]`) though has learned "Create branch " and
15 | "Move active branch to ".
16 |
17 | - In the commit message view, you can directly unstage or discard hunks or
18 | lines from the diff shown there. The former is very needed when amending
19 | or splitting commits while rebasing. You just start a "commit --amend" and
20 | deselect what you don't want to commit yet. Discarding is useful if you have
21 | these "oh, there's still a console.log in there"; just reset those lines
22 | quickly.
23 |
24 | - You can now open the `Line History` from basically everywhere you see a
25 | patch/diff and it will read the commit and correct line numbers from it.
26 |
27 | E.g. you're in the normal diff view with a small fixup. `[S]`tage that, the
28 | diff will switch to the staged mode automatically after the last hunk. Now
29 | initiate `Line History` from the command palette to bring up a new view
30 | showing the history of the hunk. Search for the right commit and hit `[f]`
31 | to make a fixup commit.
32 |
33 | - Hunk-to-hunk navigation has been improved in all views showing diffs/patches.
34 |
35 | - Staging deletion-only hunks has been made easier for the `gs_stage_hunk`
36 | command.
37 |
38 |
39 | 🎄🧑🎄
40 |
41 |
42 | Quick workflow reminders. As GitSavvy generally does not come with *global*
43 | key-bindings, you have to make your own ones in your `Key Bindings` file.
44 |
45 | Just start a commit from everywhere. If nothing is staged yet, "commit --all"
46 | is assumed:
47 |
48 | ```
49 | { "keys": ["ctrl+shift+c"], "command": "gs_commit"},
50 | ```
51 |
52 | Stage something quickly, directly in the edited buffer:
53 |
54 | ```
55 | { "keys": ["alt+s"], "command": "gs_stage_hunk"},
56 | ```
57 |
58 | Set `"git_diff_target": "index",` in your Sublime Text's preferences too, so
59 | that the gutter shows the correct information, namely changed unstaged lines.
60 |
61 | Navigate from hunk to hunk in your normal view:
62 |
63 | ```
64 | { "keys": ["ctrl+."], "command": "gs_next_hunk" },
65 | { "keys": ["ctrl+,"], "command": "gs_prev_hunk" },
66 | ```
67 |
68 | To open a diff for the current file is still very useful:
69 |
70 | ```
71 | {
72 | "keys": ["ctrl+shift+."], "command": "gs_diff",
73 | "args": { "current_file": true }
74 | },
75 | ```
76 |
77 | Acts btw as a toggle, t.i. when viewing a diff closes the diff, otherwise opens
78 | it. Opens a "diff all files" when used from e.g. the `Repo History`!
79 |
80 | Quickly open a Line History:
81 |
82 | ```
83 | { "keys": ["ctrl+shift+l"], "command": "gs_line_history"},
84 | ```
85 |
86 |
87 |
88 | [*] Yeah GitSavvy and git have the same version number currently
89 |
--------------------------------------------------------------------------------
/messages/2.39.0.txt:
--------------------------------------------------------------------------------
1 | GitSavvy 2.39.0
2 | ===============
3 |
4 |
5 | | Likely the last version working with Sublime Text 3. If you're still using that |
6 | | freeze your GitSavvy install. |
7 |
8 |
9 | - This version implements `[n]`ext/`[p]`revious navigation for the inline diff and
10 | the commit views including the commit panel at the bottom of the graph views.
11 |
12 | E.g., you could open the inline diff for a given file, then `[p][O]` to see
13 | the last revision of that exact file.
14 |
15 | - @zebyja implemented variable expansion especially for the custom env/PATH setting.
16 | E.g. in your GitSavvy settings:
17 |
18 | ```
19 | {
20 | "env": {
21 | "PATH":"venv/bin:${PATH}"
22 | },
23 | }
24 | ```
25 |
26 | to *prepend* `venv/bin`. (#1724)
27 |
28 |
29 |
--------------------------------------------------------------------------------
/messages/2.4.0.txt:
--------------------------------------------------------------------------------
1 | This is a smaller release, but includes fixes some folks have been waiting on.
2 |
3 | Changes since 2.3.0:
4 |
5 | Enhancement:
6 | - Additional `git: blame` display options.options.
7 | - Debug/logging commands have been renamed.
8 | - `git_path` can now be customized on a per-platform basis.
9 | - Add `merge_log` setting to toggle `--log` inclusion in `git merge`.
10 |
11 | Bug:
12 | - Provide fallcack for when Git command decoding fails.
13 | - `GitSavvy: help` no longer fails in Inline-Diff mode.
14 | - Custom commands would not always be invoked properly.
15 | - Github integration would not work for remotes with underscore characters.
16 | - GitSavvy now fails more gracefully when previously existing repo is deleted.
17 |
18 | Contributors:
19 | - Pavel Savchenko
20 | - John Burnett
21 | - Simon
22 | - Dale Bustad
23 | - David Devlin
24 |
--------------------------------------------------------------------------------
/messages/2.41.0.txt:
--------------------------------------------------------------------------------
1 | GitSavvy 2.41.0
2 | ===============
3 |
4 | Minor, quality-of-life improvements
5 |
6 | - Improved cursor placement after staging, unstaging, etc., in the diff view for better orientation.
7 | - When transitioning from a normal view (buffer) to the diff view, the just edited hunk is now
8 | placed and shown automatically (if applicable). We had this for the inline diff view like
9 | forever and now also for the standard diff view. This is even more interesting if you added a
10 | key binding
11 |
12 | ```
13 | {
14 | "keys": ["ctrl+shift+."],
15 | "command": "gs_diff",
16 | "args": { "current_file": true }
17 | },
18 | ```
19 |
20 |
21 |
22 | Less minor
23 |
24 | In the commit message view, you can now unstage directly even in the `-a` (all) mode, completing this feature set.
25 |
26 | In the Repo History (graph) views,
27 |
28 | - an overview mode has been added, triggered by pressing `[s]`. This mode hides all commits and
29 | only displays branch tips and reachable tags. (In this mode, pressing `[a]` will also hide the
30 | tags!)
31 | - an asterisk (`*`) after `HEAD` now indicates that the repository is currently dirty. For example,
32 | it will print `(HEAD* -> master)` now. 😐😏
33 | - Special branches in a repository are now marked with a special syntax scope, allowing you to
34 | assign a different color to them. The branch names that are considered special are:
35 | `(master|main|dev|trunk)\b`, and the scope is named
36 | `constant.other.git.branch.special.git-savvy`.
37 | Note that you need to adjust your color scheme to see any change; GitSavvy will not modify it
38 | automatically.
39 |
40 |
41 | Sincerely,
42 | 😘
43 |
44 | You can send some virtual coffee too: https://paypal.me/herrkaste
45 |
46 |
--------------------------------------------------------------------------------
/messages/2.42.0.txt:
--------------------------------------------------------------------------------
1 | GitSavvy 2.42.0
2 | ===============
3 |
4 | This release mostly consists of bug- and glitch-fixes you might not even noticed.
5 |
6 | Few notable changes:
7 |
8 | - GitSavvy's output panel now supports progress information. This was trickier than I thought it
9 | would get, and especially makes "cloning" or "rebasing" much nicer to look at.
10 |
11 | - In the commit view, "select all" (e.g. `ctrl+a`) now selects just your commit message and not the
12 | help text and diff below anymore. That only applies when the cursor is within the message of
13 | course. `ctrl+a` twice will still select the whole buffer.
14 |
15 | - Forking a GitHub repository will now by default only copy the default branch. This is
16 | explained on their blog (https://github.blog/changelog/2022-07-27-you-can-now-fork-a-repo-and-copy-only-the-default-branch/).
17 | However, this is also pluggable, please refer to GitSavvy's settings (https://github.com/timbrel/GitSavvy/commit/aa555a22#diff-96ea80b9a1df2392ccf6a341d0375dd230076a620a236c127f7980c15c2ab5f8).
18 |
19 |
20 | 💕ly greetings
21 |
22 |
23 |
24 |
25 |
--------------------------------------------------------------------------------
/messages/2.5.0.txt:
--------------------------------------------------------------------------------
1 | Changes since 2.4.0:
2 |
3 | Enhancement:
4 | - Pre-select first file in status dashboard on initial creation.
5 | - Add navigation to files in status dashboard.
6 |
7 | Documentation:
8 | - Add note about Git path in Windows 64-bit.
9 |
10 | Contributors:
11 | - Dale Bustad
12 |
--------------------------------------------------------------------------------
/messages/2.6.0.txt:
--------------------------------------------------------------------------------
1 | Changes since 2.5.0:
2 |
3 | Fix:
4 | - Update status dashboard syntax to highlight , and .
5 | - Status dashboard , and . can navigate to stashes.
6 |
7 | Enhancement:
8 | - Display message to user if fallback decoding fails.
9 | - Add option to confirm `git push --force`.
10 |
11 | Contributors:
12 | - David Mohl
13 | - Pavel Savchenko
14 | - Dale Bustad
15 |
--------------------------------------------------------------------------------
/messages/2.7.0.txt:
--------------------------------------------------------------------------------
1 | Changes since 2.6.0:
2 |
3 | Enhancement:
4 | - Pressing `o` from the inline-diff will open the file at the same cursor position.
5 | - `git: graph` view can now be refreshed.
6 | - `commit_on_close` configuration option added more Git-like commit view experience.
7 |
8 | Bug:
9 | - Branch dashboard would not display branches ending in hyphen char.
10 |
11 | Contributors:
12 | - Dale Bustad
13 | - Simon
14 |
--------------------------------------------------------------------------------
/messages/2.8.0.txt:
--------------------------------------------------------------------------------
1 | Changes since 2.7.1:
2 |
3 | Feature:
4 | - Press Tab to transition between dashboards in a single view (or Shift-Tab for reverse) (configurable).
5 | - Add a simple stand-alone cherry-pick command.
6 | - Diff view can toggle `ignore_all_space` and `word_diff` options.
7 | - Show and edit branch descriptions in branch dashboard.
8 | - Add international codec support including GBK, BIG5, EUC-KR, EUC-JP, etc.
9 | - Open issues and repo page on GitHub remote through command palette.
10 |
11 | Enhancement:
12 | - Rebase dashboard supports non-branch base.
13 | - Add syntax highlighting for `git: graph` view.
14 | - Add option to auto-close panel for specified Git operations.
15 | - Add key-binding to push from status dashboard.
16 | - Fork UX in rebase-conflict scenario when one side is deleted.
17 | - Add syntax highlighting for comments and tracking info in branch dashboard.
18 |
19 | Fix:
20 | - Add empty line to beginning of tags inferface.
21 | - Always pass the branch name on git flow * finish (fixes issues with certain git-flow releases).
22 | - Attempting to discard staged file needn't trigger destructive-action warning.
23 | - Potential issue with interfaces sharing region keys.
24 | - Remote duplicate branch names when determining remote branches.
25 | - `git:pull` would fail if ORIGIN/HEAD known.
26 | - All types of unmerged conflicts were not shown correctly.
27 | - Unintentional default settings for show_panel_for and close_panel_for.
28 | - Dashboard syntax did not support multi-character key name.
29 |
30 | Documentation:
31 | - Define lowest-supported Git version.
32 |
33 | Housekeeping:
34 | - Port tags dashboard to interface pattern.
35 |
36 |
37 | Contributors:
38 | - Pavel Savchenko
39 | - Dale Bustad
40 | - Simon
41 | - marcinruszkiewicz
42 |
--------------------------------------------------------------------------------
/messages/2.9.0.txt:
--------------------------------------------------------------------------------
1 | Changes since 2.8.1:
2 |
3 | Feature:
4 | - `git: log current file` now has an option to view file at chosen commit.commit
5 | - Add `git: push all tags` command.
6 | - New `git: smart tag` commands for easy semantic versioning.
7 | - Directly checkout or view diff of GitHub pull requests with `github: review pull request`.
8 | - Basic support for opening new GitHub pull request from GitSavvy.
9 |
10 | Enhancement:
11 | - User is prompted for reset type (with hints) after running `git: reset`.
12 |
13 | Fix:
14 | - Editing commit message would fail if previous content deleted before new content entered.
15 | - Dashboards would not refresh after commit if commit_on_close enabled.
16 | - GitSavvy would attempt to open untracked file on remote.
17 | - Pushing a single tag would not work in tag dashboard.
18 | - `git: fetch` could not fetch commit directly.
19 | - Unclear destructive-action prompt for status-dashboard `D`.
20 | - Endless loop when some poor soul tries to diff a binary file as text.
21 | - Rebase dashboard failed if no directories added to active window.
22 | - Incorrect syntax highlighting in docs/README.md
23 | - Inline-diff view would sometimes jump to the right after staging hunks.
24 | - Refresh command in status dashboard was incorrectly wired-up.
25 |
26 | Other:
27 | - Add a GitSavvy diff syntax witch supports word diffs.
28 |
29 | Contributors:
30 | - Pavel Savchenko
31 | - Steve Bennett
32 | - Dale Bustad
33 | - Craig Campbell
34 | - Nicolás Santángelo
35 | - Randy Lai
36 | - David Devlin
37 |
--------------------------------------------------------------------------------
/messages/install.txt:
--------------------------------------------------------------------------------
1 | # Welcome to GitSavvy
2 |
3 | GitSavvy provides integration between Sublime Text 3 and Git.
4 |
5 | If you're a new user and you find yourself asking, _"Can GitSavvy do X?"_, there are two places to look. First, open your command palette and type `GitSavvy: help`. This will take you to the offline wiki-style documentation.
6 |
7 | You can also check for configurability options by opening `Preferences > Package Settings > GitSavvy > Settings - Default` in the ST3 menu. Any optional or configurable behavior will be documented here, along with the default values.
8 |
9 | Finally, if at any time you encounter a bug, or if you wish that GitSavvy included some missing functionality, please open an issue:
10 | https://github.com/timbrel/GitSavvy/issues
11 |
--------------------------------------------------------------------------------
/pyproject.toml:
--------------------------------------------------------------------------------
1 | [project]
2 | name = "GitSavvy"
3 | readme = "README.md"
4 | requires-python = ">= 3.12"
5 |
6 | [tool.rye]
7 | managed = true
8 | virtual = true
9 | dev-dependencies = [
10 | "flake8==5.*",
11 | ]
12 |
--------------------------------------------------------------------------------
/requirements-dev.lock:
--------------------------------------------------------------------------------
1 | # generated by rye
2 | # use `rye lock` or `rye sync` to update this lockfile
3 | #
4 | # last locked with the following flags:
5 | # pre: false
6 | # features: []
7 | # all-features: false
8 | # with-sources: false
9 | # generate-hashes: false
10 | # universal: false
11 |
12 | flake8==5.0.4
13 | mccabe==0.7.0
14 | # via flake8
15 | pycodestyle==2.9.1
16 | # via flake8
17 | pyflakes==2.5.0
18 | # via flake8
19 |
--------------------------------------------------------------------------------
/requirements.lock:
--------------------------------------------------------------------------------
1 | # generated by rye
2 | # use `rye lock` or `rye sync` to update this lockfile
3 | #
4 | # last locked with the following flags:
5 | # pre: false
6 | # features: []
7 | # all-features: false
8 | # with-sources: false
9 | # generate-hashes: false
10 | # universal: false
11 |
12 |
--------------------------------------------------------------------------------
/syntax/blame.sublime-settings:
--------------------------------------------------------------------------------
1 | {
2 | // same on all syntaxes
3 | "auto_indent": false,
4 | "detect_indentation": false,
5 | "draw_indent_guides": false,
6 | "draw_white_space": "None",
7 | "gutter": false,
8 | "line_numbers": false,
9 | "margin": 20,
10 | "rulers": [],
11 | "translate_tabs_to_spaces": false,
12 | "word_wrap": false,
13 | // syntax specific
14 | "match_brackets": false,
15 | "match_tags": false
16 | }
17 |
--------------------------------------------------------------------------------
/syntax/blame.sublime-syntax:
--------------------------------------------------------------------------------
1 | %YAML 1.2
2 | ---
3 | # http://www.sublimetext.com/docs/3/syntax.html
4 | name: GitSavvy Blame
5 | hidden: true
6 | scope: git-savvy.blame
7 | contexts:
8 | main:
9 | - match: ^(\-+ )(\|)( \-+)$
10 | comment: separator
11 | scope: comment.block.git-savvy.splitter
12 | captures:
13 | 1: comment.block.git-savvy.splitter.horizontal.commit-info
14 | 2: comment.block.git-savvy.splitter.vertical
15 | 3: comment.block.git-savvy.splitter.horizontal.source
16 |
17 | - match: ^Not committed yet.+?\s+
18 | scope: meta.not-committed.blame.git-savvy
19 | push: right-column
20 |
21 | - match: ^([0-9a-f]{6,40})\s+ (\(CURRENT COMMIT\))?
22 | comment: SHA
23 | scope: meta.blame-line.git-savvy
24 | captures:
25 | 1: constant.numeric.commit-hash.git-savvy
26 | 2: meta.current-commit.blame.git-savvy
27 | push: right-column
28 |
29 | - match: ^([^|]+) (<)(\S*?)(>|\.{3})\s+
30 | comment: name + email
31 | scope: meta.blame-line.git-savvy
32 | captures:
33 | 1: entity.name.tag.git-savvy
34 | 2: punctuation.definition.other.begin.git-savvy
35 | 3: string.other.mail.git-savvy
36 | 4: punctuation.definition.other.end.git-savvy
37 | push: right-column
38 |
39 | - match: ^.+?(?=\s\|\s)
40 | scope: comment.block.git-savvy.commit-info
41 | push: right-column
42 |
43 | right-column:
44 | - match: (\|)\s+(\d*).*$
45 | captures:
46 | 1: comment.block.git-savvy.splitter.vertical
47 | 2: constant.numeric.line-number.blame.git-savvy
48 | - match: $
49 | pop: true
50 |
--------------------------------------------------------------------------------
/syntax/branch.sublime-settings:
--------------------------------------------------------------------------------
1 | {
2 | // same on all syntaxes
3 | "auto_indent": false,
4 | "detect_indentation": false,
5 | "draw_indent_guides": false,
6 | "draw_white_space": "None",
7 | "gutter": false,
8 | "line_numbers": false,
9 | "margin": 20,
10 | "rulers": [],
11 | "translate_tabs_to_spaces": false,
12 | "word_wrap": false,
13 |
14 | // syntax specific
15 | "gutter": true,
16 | "margin": -8,
17 | "highlight_line": true,
18 | "fold_buttons": false,
19 | "fade_fold_buttons": false,
20 | "match_brackets": false,
21 | "match_tags": false
22 | }
23 |
--------------------------------------------------------------------------------
/syntax/branch.sublime-syntax:
--------------------------------------------------------------------------------
1 | %YAML 1.2
2 | ---
3 | # http://www.sublimetext.com/docs/3/syntax.html
4 | name: GitSavvy Branch
5 | hidden: true
6 | scope: git-savvy.branch
7 | contexts:
8 | main:
9 | - include: "Packages/GitSavvy/syntax/dashboard.sublime-syntax"
10 |
11 | - match: '^ LOCAL:$'
12 | scope: keyword.other.git-savvy.section-header.branch.local
13 | push:
14 | - meta_scope: meta.git-savvy.status.section.branch.local
15 | - include: section
16 |
17 | - match: '^ REMOTE (\()([^\)]+)(\)):$'
18 | scope: keyword.other.git-savvy.section-header.branch.remote
19 | captures:
20 | 1: punctuation.definition.git-savvy.section-header.remote
21 | 2: keyword.other.git-savvy.section-header.branch.remote.name
22 | 3: punctuation.definition.git-savvy.section-header.remote
23 | push:
24 | - meta_scope: meta.git-savvy.status.section.branch.remote
25 | - include: section
26 |
27 | section:
28 | - match: ^$
29 | pop: true
30 |
31 | - match: (?=^\s+▸)
32 | push:
33 | - meta_scope: meta.git-savvy.branches.branch.active-branch
34 | - include: row
35 | - match: $
36 | pop: true
37 |
38 | - match: ^
39 | push:
40 | - include: row
41 | - match: $
42 | pop: true
43 |
44 | row:
45 | - match: '^ \s+(\\ )?(checked out at: )(.+)$'
46 | captures:
47 | 0: keyword
48 | 1: keyword
49 | 2: keyword
50 | 3: keyword.other.git-savvy.path
51 |
52 |
53 | - match: '^\s+(<)([0-9a-f]{7,40}) ?(>-?) (.*)$'
54 | captures:
55 | 0: meta.git-savvy.branches.branch.as-worktree
56 | 1: punctuation.symbol.foreign-branch
57 | 2: constant.other.git-savvy.branches.branch.sha1 keyword
58 | 3: punctuation.symbol.foreign-branch
59 | 4: keyword
60 |
61 | - match: '^\s+(<)([0-9a-f]{7,40})(>) (\S+)\s?(.*)$'
62 | captures:
63 |
64 | 0: meta.git-savvy.branches.branch.as-worktree
65 | 1: punctuation.symbol.foreign-branch
66 | 2: constant.other.git-savvy.branches.branch.sha1 keyword
67 | 3: punctuation.symbol.foreign-branch
68 | 4: meta.git-savvy.branches.branch.name gitsavvy.gotosymbol
69 | 5: comment.git-savvy.branches.branch.extra-info
70 |
71 | - match: '^ (▸)?\s+([0-9a-f]{7,40}) ([^\s]+)\s([^(-].+?)?((?:, )?\(.+?(?:, (gone))?\))?( ?\- .+)?$'
72 | captures:
73 | 0: meta.git-savvy.branches.branch
74 | 1: punctuation.symbol.active-branch.git-savvy
75 | 2: constant.other.git-savvy.branches.branch.sha1
76 | 3: meta.git-savvy.branches.branch.name gitsavvy.gotosymbol
77 | 4: comment.git-savvy.branches.branch.date
78 | 5: comment.git-savvy.branches.branch.tracking-info
79 | 6: constant.git-savvy.upstream.gone
80 | 7: comment.git-savvy.branches.branch.description keyword
81 |
--------------------------------------------------------------------------------
/syntax/diff.sublime-settings:
--------------------------------------------------------------------------------
1 | {
2 | // same on all syntaxes
3 | "auto_indent": false,
4 | "detect_indentation": false,
5 | "draw_indent_guides": false,
6 | "draw_white_space": "None",
7 | "gutter": false,
8 | "line_numbers": false,
9 | "margin": 20,
10 | "rulers": [],
11 | "translate_tabs_to_spaces": false,
12 | "word_wrap": false,
13 |
14 | // syntax specific
15 | "gutter": true,
16 | "margin": -8,
17 | "fold_buttons": false,
18 | "fade_fold_buttons": false,
19 | "match_brackets": false,
20 | "match_tags": false
21 | }
22 |
--------------------------------------------------------------------------------
/syntax/diff_view.sublime-settings:
--------------------------------------------------------------------------------
1 | {
2 | // same on all syntaxes
3 | "auto_indent": false,
4 | "detect_indentation": false,
5 | "draw_indent_guides": false,
6 | "draw_white_space": "None",
7 | "gutter": false,
8 | "line_numbers": false,
9 | "margin": 20,
10 | "rulers": [],
11 | "translate_tabs_to_spaces": false,
12 | "word_wrap": false,
13 |
14 | // syntax specific
15 | "gutter": true,
16 | "margin": -8,
17 | "fold_buttons": false,
18 | "fade_fold_buttons": false,
19 | "match_brackets": false,
20 | "match_tags": false
21 | }
22 |
--------------------------------------------------------------------------------
/syntax/diff_view.sublime-syntax:
--------------------------------------------------------------------------------
1 | %YAML 1.2
2 | ---
3 | # http://www.sublimetext.com/docs/3/syntax.html
4 | name: GitSavvy Diff View
5 | hidden: true
6 | scope: git-savvy.diff_view
7 | contexts:
8 | main:
9 | - match: ^
10 | push: header
11 |
12 | header:
13 | - meta_scope: comment.header.git_savvy
14 | - match: ' STAGED CHANGES \(Will commit\)'
15 | scope: markup.deleted.diff
16 | - match: ' UNSTAGED CHANGES'
17 | - match: '^--$\n'
18 | set: 'scope:git-savvy.diff'
19 |
--------------------------------------------------------------------------------
/syntax/graph.sublime-settings:
--------------------------------------------------------------------------------
1 | {
2 | // same on all syntaxes
3 | "auto_indent": false,
4 | "detect_indentation": false,
5 | "draw_indent_guides": false,
6 | "draw_white_space": "None",
7 | "gutter": false,
8 | "line_numbers": false,
9 | "margin": 20,
10 | "rulers": [],
11 | "translate_tabs_to_spaces": false,
12 | "word_wrap": false,
13 | "draw_unicode_white_space": "none",
14 |
15 | // syntax specific
16 | "gutter": true,
17 | "margin": -20,
18 | "highlight_line": true,
19 | "fold_buttons": true,
20 | "fade_fold_buttons": false,
21 | "match_brackets": false,
22 | "match_tags": false
23 | }
24 |
--------------------------------------------------------------------------------
/syntax/help.sublime-settings:
--------------------------------------------------------------------------------
1 | {
2 | // same on all syntaxes
3 | "auto_indent": false,
4 | "detect_indentation": false,
5 | "draw_indent_guides": false,
6 | "draw_white_space": "None",
7 | "gutter": false,
8 | "line_numbers": false,
9 | "margin": 20,
10 | "rulers": [],
11 | "translate_tabs_to_spaces": false,
12 | "word_wrap": false,
13 |
14 | // syntax specific
15 | "gutter": true,
16 | "margin": -8,
17 | "highlight_line": true,
18 | "fold_buttons": false,
19 | "fade_fold_buttons": false,
20 | "match_brackets": false,
21 | "match_tags": false
22 | }
23 |
--------------------------------------------------------------------------------
/syntax/help.sublime-syntax:
--------------------------------------------------------------------------------
1 | %YAML 1.2
2 | ---
3 | name: GitSavvy Help
4 | hidden: true
5 | scope: git-savvy.help
6 | contexts:
7 | main:
8 | - meta_scope: comment.git-savvy.key-bindings-menu
9 | - match: '(##+) ([A-Z ]+)(?: (##+))?'
10 | scope: meta.git-savvy.key-bindings-header
11 | captures:
12 | 1: punctuation.definition.git-savvy.section
13 | 2: support.type.git-savvy.key-bindings-header-text
14 | 3: punctuation.definition.git-savvy.section
15 |
16 | - match: "#{3,}"
17 | scope: punctuation.definition.git-savvy.section
18 |
19 | - match: '(\[)([A-Za-z\,\.\-\+\?]+)(\])'
20 | scope: meta.git-savvy.key-bindings-key-stroke
21 | captures:
22 | 1: punctuation.definition.git-savvy.key-bindings-key-stroke
23 | 2: constant.character.git-savvy-key-binding-key
24 | 3: punctuation.definition.git-savvy.key-bindings-key-stroke
25 | push:
26 | - match: (?=\[|`|$)
27 | pop: true
28 | - match: \s+([\w\s,\(\)]+)
29 | captures:
30 | 1: comment.git-savvy.key-bindings-menu.key-binding-description
31 |
32 | - match: '(`)(.+)(`)'
33 | scope: meta.git-savvy.key-bindings-key-stroke
34 | captures:
35 | 0: constant.character.tag.git-savvy-key-binding-key
36 | 1: punctuation.definition.git-savvy.key-bindings-key-stroke
37 | 2: constant.character.git-savvy-key-binding-key
38 | 3: punctuation.definition.git-savvy.key-bindings-key-stroke
39 |
40 | - match: '(\*\*) ([^\*]+) (\*\*)'
41 | comment: ux note
42 | scope: support.type.git-savvy.ux-note
43 | captures:
44 | 1: punctuation.definition.git-savvy.note
45 | 2: support.type.git-savvy.ux-note.text
46 | 3: punctuation.definition.git-savvy.note
47 |
48 |
49 |
--------------------------------------------------------------------------------
/syntax/make_commit.sublime-settings:
--------------------------------------------------------------------------------
1 | {
2 | // same on all syntaxes
3 | "auto_indent": false,
4 | "detect_indentation": false,
5 | "draw_indent_guides": false,
6 | "draw_white_space": "None",
7 | "gutter": false,
8 | "line_numbers": false,
9 | "margin": 20,
10 | "rulers": [],
11 | "translate_tabs_to_spaces": false,
12 | "word_wrap": false,
13 | // syntax specific
14 | "gutter": true,
15 | "line_numbers": true
16 | }
17 |
--------------------------------------------------------------------------------
/syntax/make_commit.sublime-syntax:
--------------------------------------------------------------------------------
1 | %YAML 1.2
2 | ---
3 | # http://www.sublimetext.com/docs/3/syntax.html
4 | name: GitSavvy Make Commit
5 | hidden: true
6 | scope: git-savvy.make-commit
7 |
8 | contexts:
9 | main:
10 | - match: '(?=^## To make a commit.+)'
11 | set: dropped-content
12 |
13 | - match: ^
14 | set: commit-subject
15 |
16 | references:
17 | - match: (?:\s|^)(\@[\w-]+)
18 | comment: github username
19 | captures:
20 | 1: constant.other.github-username.git-savvy.make-commit
21 |
22 | - match: '([\w-]+/[\w-]+)?#[0-9]+'
23 | comment: issue
24 | scope: constant.other.issue-ref.git-savvy.make-commit meta.git-savvy.issue-reference
25 |
26 | - match: '(?:[\s\[\(@])(\h{7,})\b'
27 | comment: sha reference
28 | captures:
29 | 1: constant.other.commit-sha.git-savvy.make-commit
30 | - match: '(?:")(\h{7,})(?!\B|\")'
31 | comment: sha reference
32 | captures:
33 | 1: constant.other.commit-sha.git-savvy.make-commit
34 |
35 | commit-subject:
36 | - meta_scope: meta.commit.message.subject markup.heading.subject.git.commit
37 | - match: (?=$)\n
38 | set: commit-line-separator
39 | - include: references
40 |
41 | commit-line-separator:
42 | - meta_content_scope: meta.commit.message
43 | - match: '(?=^## To make a commit.+)'
44 | set: dropped-content
45 | - match: \n
46 | set: commit-message
47 |
48 | commit-message:
49 | - meta_content_scope: meta.commit.message.body
50 | - include: references
51 | - match: '(?=^## To make a commit.+)'
52 | set: dropped-content
53 |
54 | dropped-content:
55 | - match: '^## To make a commit.+'
56 | scope: comment.help-text.git-savvy.make-commit
57 | set:
58 | - meta_scope: meta.dropped.git.commit
59 | - match: '(\[)(.+?)(\])'
60 | captures:
61 | 1: punctuation.definition.git-savvy.key-bindings-key-stroke
62 | 2: constant.character.git-savvy-key-binding-key
63 | 3: punctuation.definition.git-savvy.key-bindings-key-stroke
64 | - match: '(<)(.+?)(>)'
65 | - match: ^$
66 | push: [scope:git-savvy.diff]
67 | - match: .
68 | scope: comment.help-text.git-savvy.make-commit
69 |
--------------------------------------------------------------------------------
/syntax/output_panel.sublime-settings:
--------------------------------------------------------------------------------
1 | {
2 | "auto_indent": false,
3 | "detect_indentation": false,
4 | "draw_indent_guides": false,
5 | "draw_white_space": "None",
6 | "gutter": false,
7 | "is_widget": true,
8 | "line_numbers": false,
9 | "rulers": false,
10 | "scroll_past_end": false,
11 | "spell_check": false,
12 | "translate_tabs_to_spaces": false,
13 | "word_wrap": true,
14 | "wrap_width": 0,
15 | "wrap_width_style": "min"
16 | }
17 |
--------------------------------------------------------------------------------
/syntax/output_panel.sublime-syntax:
--------------------------------------------------------------------------------
1 | %YAML 1.2
2 | ---
3 | # http://www.sublimetext.com/docs/3/syntax.html
4 | name: GitSavvy Output Panel
5 | hidden: true
6 | scope: output.git-savvy
7 | variables:
8 | sha: '\h{6,40}'
9 | contexts:
10 | main:
11 | - match: ^(\$)\s
12 | captures:
13 | 1: markup.heading entity.name.section
14 |
15 | - match: ^\[Done.*\]$
16 | scope: string.other
17 |
18 | - match: (\b{{sha}}\^?)
19 | comment: SHA
20 | scope: constant.numeric.graph.commit-hash.git-savvy
21 |
22 | - match: \((\d+)/(\d+)\)
23 | comment: progress counter
24 | captures:
25 | 1: constant.numeric.progress.git-savvy
26 | 2: constant.numeric.progress.git-savvy
27 |
28 | - match: -> ([^ ]*)
29 | captures:
30 | 1: storage
31 |
32 | - match: \s(https?:\S+)
33 | captures:
34 | 1: markup.underline.link
35 |
36 | - match: ^hint:.*
37 | scope: string.other.hint.git-savvy
38 |
39 | - match: ^fatal:.*
40 | scope: markup.deleted.fatal.git-savvy
41 |
--------------------------------------------------------------------------------
/syntax/rebase.sublime-settings:
--------------------------------------------------------------------------------
1 | {
2 | // same on all syntaxes
3 | "auto_indent": false,
4 | "detect_indentation": false,
5 | "draw_indent_guides": false,
6 | "draw_white_space": "None",
7 | "gutter": false,
8 | "line_numbers": false,
9 | "margin": 20,
10 | "rulers": [],
11 | "translate_tabs_to_spaces": false,
12 | "word_wrap": false,
13 |
14 | // syntax specific
15 | "gutter": true,
16 | "margin": -20,
17 | "highlight_line": true,
18 | "fold_buttons": true,
19 | "fade_fold_buttons": false,
20 | "match_brackets": false,
21 | "match_tags": false
22 | }
23 |
--------------------------------------------------------------------------------
/syntax/rebase.sublime-syntax:
--------------------------------------------------------------------------------
1 | %YAML 1.2
2 | ---
3 | # http://www.sublimetext.com/docs/3/syntax.html
4 | name: GitSavvy Rebase
5 | hidden: true
6 | scope: git-savvy.rebase
7 | contexts:
8 | main:
9 | - include: "Packages/GitSavvy/syntax/dashboard.sublime-syntax"
10 | - match: "^ REBASE:"
11 | comment: Rebase summary
12 | scope: comment.git-savvy.summary-header.title.rebase
13 | push:
14 | - meta_scope: meta.git-savvy.rebase-summary
15 | - match: ^$
16 | pop: true
17 | - match: ^ (STATUS:).+
18 | captures:
19 | 1: comment.git-savvy.summary-header.title.status.rebase
20 |
21 | - match: ^( [┃│] )(.+)\n
22 | scope: meta.git-savvy.rebase-graph.conflict
23 | captures:
24 | 1: comment.git-savvy.rebase-graph.separator
25 | 2: keyword.other.name.git-savvy.rebase-conflict
26 | - match: " [┃│]"
27 | scope: comment.git-savvy.rebase-graph.separator
28 | - match: " [┻┴]"
29 | scope: comment.git-savvy.rebase-graph.end
30 | - match: ' [┳┬] (\()([0-9a-f]{7,40})(\))'
31 | scope: comment.git-savvy.rebase-graph.base
32 | captures:
33 | 1: punctuation.definition.git-savvy.rebase-graph.base
34 | 2: support.type.git-savvy.rebase.commit_hash
35 | 3: punctuation.definition.git-savvy.rebase-graph.base
36 |
37 | - match: ' ([▸ ]) ([·●]) ([0-9a-f]{7,40}) (.*)\n'
38 | scope: meta.git-savvy.rebase-graph.entry
39 | captures:
40 | 1: string.other.git-savvy.rebase.caret
41 | 2: comment.git-savvy.rebase-graph.commit-node
42 | 3: support.type.git-savvy.rebase.commit_hash
43 | 4: gitsavvy.gotosymbol
44 | - match: ' ([▸ ]) (✔) ([0-9a-f]{7,40}) (.*)\n'
45 | scope: meta.git-savvy.rebase-graph.entry
46 | captures:
47 | 1: string.other.git-savvy.rebase.caret
48 | 2: entity.name.function.git-savvy.success
49 | 3: support.type.git-savvy.rebase.commit_hash
50 | 4: gitsavvy.gotosymbol
51 | - match: ' ([▸ ]) ([✕✘]) ([0-9a-f]{7,40}) (.*)\n'
52 | scope: meta.git-savvy.rebase-graph.entry
53 | captures:
54 | 1: string.other.git-savvy.rebase.caret
55 | 2: string.other.git-savvy.conflict
56 | 3: support.type.git-savvy.rebase.commit_hash
57 | 4: gitsavvy.gotosymbol
58 |
59 |
--------------------------------------------------------------------------------
/syntax/show_commit.sublime-settings:
--------------------------------------------------------------------------------
1 | {
2 | // same on all syntaxes
3 | "auto_indent": false,
4 | "detect_indentation": false,
5 | "draw_indent_guides": false,
6 | "draw_white_space": "None",
7 | "gutter": false,
8 | "line_numbers": false,
9 | "margin": 20,
10 | "rulers": [],
11 | "translate_tabs_to_spaces": false,
12 | "word_wrap": false,
13 | // syntax specific
14 | "match_brackets": false,
15 | "match_tags": false
16 | }
17 |
--------------------------------------------------------------------------------
/syntax/show_commit.sublime-syntax:
--------------------------------------------------------------------------------
1 | %YAML 1.2
2 | ---
3 | # http://www.sublimetext.com/docs/3/syntax.html
4 | name: GitSavvy Commit
5 | hidden: true
6 | scope: git-savvy.commit
7 | contexts:
8 | main:
9 | - match: (?=^(commit|tag|From))
10 | push: commit-header
11 | - match: (?=^diff\s)
12 | embed: "scope:git-savvy.diff"
13 | escape: (?=^commit \h{7,})
14 | # Merge commits "just" start the diffstat without the "---" line
15 | - match: (?=^ \S)
16 | embed: "scope:git-savvy.diff"
17 | escape: (?=^(commit|From) \h{7,})
18 | - match: ^---$\n?
19 | scope: meta.commit-header-and-stat-splitter
20 | embed: "scope:git-savvy.diff"
21 | escape: (?=^(commit|From) \h{7,})
22 | - match: ^-- .* --$
23 | scope: markup.deleted
24 |
25 | commit-header:
26 | - meta_scope: meta.commit-info.header
27 | - match: ^(commit|tag|From) (.+)$\n?
28 | comment: commit header
29 | scope: meta.commit-info.header.key-value
30 | captures:
31 | 1: string.other.commit-info.header.key.git-savvy
32 | 2: meta.commit-info.header.value.git-savvy meta.commit-info.header.sha.git-savvy
33 |
34 | - match: ^(Author|AuthorDate|Commit|CommitDate|Date|From|Merge|Tagger|TaggerDate)(:)(.+)$\n?
35 | comment: author and date info
36 | scope: meta.commit-info.header.key-value
37 | captures:
38 | 1: string.other.commit-info.header.key.git-savvy
39 | 2: string.other.commit-info.header.key.punctuation.git-savvy
40 | 3: meta.commit-info.header.value.git-savvy
41 |
42 | - match: ^(Subject)(:)\s(.+)$\n?
43 | comment: subject (in a patch)
44 | scope: meta.commit-info.header.key-value
45 | captures:
46 | 1: string.other.commit-info.header.key.git-savvy
47 | 2: string.other.commit-info.header.key.punctuation.git-savvy
48 | 3: meta.commit-info.header.value.git-savvy gitsavvy.gotosymbol meta.commit_message meta.subject.git.commit
49 | set: commit-subject
50 |
51 | - match: ^$
52 | set: commit-message
53 |
54 | commit-message:
55 | - meta_scope: meta.commit_message
56 | - match: ^\s*(?=\S+)
57 | set: commit-subject
58 |
59 | commit-subject:
60 | - meta_content_scope: gitsavvy.gotosymbol meta.commit_message meta.subject.git.commit markup.heading.subject.git.commit
61 | - match: $
62 | set: commit-message-body
63 | - include: make_commit.sublime-syntax#references
64 |
65 | commit-message-body:
66 | - meta_scope: meta.commit_message
67 | - match: (?=^commit \h{7,})
68 | set: main
69 | - match: (?=^---$\n?)
70 | set: main
71 | - match: (?=^diff\s)
72 | set: main
73 | - match: (?=^ \S)
74 | set: main
75 | - include: make_commit.sublime-syntax#references
76 |
--------------------------------------------------------------------------------
/syntax/show_commit_diffstat.sublime-syntax:
--------------------------------------------------------------------------------
1 | %YAML 1.2
2 | ---
3 | # http://www.sublimetext.com/docs/3/syntax.html
4 | name: GitSavvy Diffstat
5 | hidden: true
6 | scope: git-savvy.commit-diffstat
7 | contexts:
8 | main:
9 | - match: ^ (\S.+?) +\| +(\d+ |0)(\+*)(-*)$\n?
10 | comment: author and date info
11 | scope: meta.commit-info.diffstat.line
12 | captures:
13 | 1: meta.filename.diff
14 | 2: constant.numeric.lines-count.git-savvy
15 | 3: markup.inserted.git-savvy.add-block.content
16 | 4: markup.deleted.git-savvy.delete-block.content
17 |
18 | - match: (\d+) files? changed
19 | comment: Count files changed
20 | scope: meta.commit-info.files.changes
21 | captures:
22 | 1: constant.numeric.lines-count.git-savvy
23 |
24 | - match: (\d+) insertions?\(\+\)
25 | comment: Count of lines insertions
26 | scope: markup.inserted.git-savvy.add-block.content
27 | captures:
28 | 1: constant.numeric.lines-count.git-savvy
29 |
30 | - match: (\d+) deletions?\(-\)
31 | comment: Count of lines deletions
32 | scope: markup.deleted.git-savvy.delete-block.content
33 | captures:
34 | 1: constant.numeric.lines-count.git-savvy
35 |
--------------------------------------------------------------------------------
/syntax/status.sublime-settings:
--------------------------------------------------------------------------------
1 | {
2 | // same on all syntaxes
3 | "auto_indent": false,
4 | "detect_indentation": false,
5 | "draw_indent_guides": false,
6 | "draw_white_space": "None",
7 | "gutter": false,
8 | "line_numbers": false,
9 | "margin": 20,
10 | "rulers": [],
11 | "translate_tabs_to_spaces": false,
12 | "word_wrap": false,
13 | "draw_unicode_white_space": "none",
14 |
15 | // syntax specific
16 | "gutter": true,
17 | "margin": -20,
18 | "highlight_line": true,
19 | "fold_buttons": true,
20 | "fade_fold_buttons": false,
21 | "match_brackets": false,
22 | "match_tags": false
23 | }
24 |
--------------------------------------------------------------------------------
/syntax/tags.sublime-settings:
--------------------------------------------------------------------------------
1 | {
2 | // same on all syntaxes
3 | "auto_indent": false,
4 | "detect_indentation": false,
5 | "draw_indent_guides": false,
6 | "draw_white_space": "None",
7 | "gutter": false,
8 | "line_numbers": false,
9 | "margin": 20,
10 | "rulers": [],
11 | "translate_tabs_to_spaces": false,
12 | "word_wrap": false,
13 |
14 | // syntax specific
15 | "gutter": true,
16 | "margin": -20,
17 | "highlight_line": true,
18 | "fold_buttons": true,
19 | "fade_fold_buttons": false,
20 | "match_brackets": false,
21 | "match_tags": false
22 | }
23 |
--------------------------------------------------------------------------------
/syntax/tags.sublime-syntax:
--------------------------------------------------------------------------------
1 | %YAML 1.2
2 | ---
3 | # http://www.sublimetext.com/docs/3/syntax.html
4 | name: GitSavvy Tags
5 | hidden: true
6 | scope: git-savvy.tags
7 | contexts:
8 | main:
9 | - include: "Packages/GitSavvy/syntax/dashboard.sublime-syntax"
10 |
11 | - match: ^ LOCAL:$
12 | comment: local section
13 | scope: keyword.other.git-savvy.section-header.tags.local
14 | push:
15 | - meta_scope: meta.git-savvy.section.tags.local
16 | - include: section
17 |
18 | - match: ^ REMOTE (\()(.+)(\)):$
19 | comment: remote section
20 | scope: keyword.other.git-savvy.section-header.tags.remote
21 | captures:
22 | 1: punctuation.definition.git-savvy.section-header.remote
23 | 2: constant.other.git-savvy.tags.remote-name
24 | 3: punctuation.definition.git-savvy.section-header.remote
25 | push:
26 | - meta_scope: meta.git-savvy.section.tags.remote
27 | - include: section
28 |
29 | section:
30 | - match: ^$
31 | pop: true
32 | - match: '^ (?:(\*)|(!)| )([0-9a-f]{7,40}) (.+?)(?: +(.+))?\n$'
33 | scope: meta.git-savvy.tags.tag
34 | captures:
35 | 1: punctuation.tag-tag.new-tag.git-savvy
36 | 2: punctuation.tag-tag.changed-tag.git-savvy
37 | 3: constant.other.git-savvy.tags.sha1
38 | 4: meta.git-savvy.tag.name gitsavvy.gotosymbol
39 | 5: comment.git-savvy.tag.age
40 |
--------------------------------------------------------------------------------
/syntax/test/syntax_test_blame.txt:
--------------------------------------------------------------------------------
1 | # SYNTAX TEST "Packages/GitSavvy/syntax/blame.sublime-syntax"
2 |
3 | update blame syntax format | 1 %YAML 1.2
4 | # ^ comment.block
5 | # ^ comment.block
6 | # ^ comment.block.git-savvy.splitter.vertical
7 | # ^ constant.numeric.line-number
8 |
9 | f483ab7eb511 | 2 ---
10 | # ^ comment.block.git-savvy.splitter.vertical
11 | # ^ constant.numeric.commit-hash
12 |
13 | gwenzek | 3 # http://www.sublimetext.com/docs/3/syntax.html
14 | # ^ comment.block.git-savvy.splitter.vertical
15 | # ^ entity.name.tag.git-savvy
16 | # ^ punctuation.definition.other.begin.git-savvy
17 | # ^^^^^^^^^^^^^^^^^^^^^^^^^^ string.other.mail.git-savvy
18 | # ^ punctuation.definition.other.end.git-savvy
19 |
20 | Jan 29, 2015 |
21 | # ^ comment.block.git-savvy.splitter.vertical
22 | # <- comment.block.git-savvy.commit-info
23 | # ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ comment.block.git-savvy.commit-info
24 |
25 | Rename `base_command#BaseCommand` to ... | 4 from ..git_command import GitCommand
26 | # ^ comment.block.git-savvy.splitter.vertical
27 | # <- comment.block.git-savvy.commit-info
28 | # ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ comment.block.git-savvy.commit-info
29 | # ^ constant.numeric.line-number
30 | # ^ git-savvy.blame
31 |
32 | -------------------------------------------- | ------------------------------------------
33 | # ^ comment.block.git-savvy.splitter.horizontal.commit-info
34 | # ^ comment.block.git-savvy.splitter.vertical
35 | # ^ comment.block.git-savvy.splitter.horizontal.source
36 |
--------------------------------------------------------------------------------
/syntax/test/syntax_test_branch.txt:
--------------------------------------------------------------------------------
1 | # SYNTAX TEST "Packages/GitSavvy/syntax/branch.sublime-syntax"
2 |
3 | LOCAL:
4 | # <- meta.git-savvy.status -meta.git-savvy.status-summary
5 | # ^ keyword.other
6 | ▸ aaf90ba develop
7 | # ^ punctuation.symbol.active-branch.git-savvy
8 | # ^^^^^^^ constant.other.git-savvy.branches.branch.sha1
9 | # ^^^^^^^ meta.git-savvy.branches.branch.name
10 | # ^^^^^^^ gitsavvy.gotosymbol
11 | ▸ aaf90ba develop (origin/develop)
12 | #^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ meta.git-savvy.branches.branch.active-branch
13 | # <- meta.git-savvy.branches.branch.active-branch
14 | f21e6a8 old (origin/develop, ahead 13, behind 40)
15 | # ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - meta.git-savvy.branches.branch.active-branch
16 | # ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ comment.git-savvy.branches.branch.tracking-info
17 | b20264b iter-branches-dashboard-code 12 minutes ago
18 | # ^^^^^^^ constant.other.git-savvy.branches.branch.sha1
19 | # ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ meta.git-savvy.branches.branch.name gitsavvy.gotosymbol
20 | # ^^^^^^^^^^^^^^ comment.git-savvy.branches.branch.date
21 | fb8240d status-bar-updater (fork/status-bar-updater, gone)
22 | # ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ comment.git-savvy.branches.branch.tracking-info
23 | # ^^^^ constant.git-savvy.upstream.gone
24 | fb8240d status-bar-updater (fork/status-bar-updater)
25 | # ^^^^^^^^^^^^^^^^^^^^^^^^^ comment.git-savvy.branches.branch.tracking-info
26 | 369ff34 fix-environment 6 years ago, (origin/fix-environment)
27 | # ^^^^^^^^^^^ comment.git-savvy.branches.branch.date
28 | # ^^^^^^^^^^^^^^^^^^^^^^^^ comment.git-savvy.branches.branch.tracking-info
29 | ▸ 7f561b6 master Wed 20:04 -0700, (origin/master) - desc
30 | # ^^^^^^^^^^^^^^^ comment.git-savvy.branches.branch.date
31 | # ^^^^^^^^^^^^^^ comment.git-savvy.branches.branch.tracking-info
32 | # ^^^^^^ comment.git-savvy.branches.branch.description keyword
33 | ▸ 7f561b6 master Wed 20:04 -0700 - desc
34 | # ^^^^^^^^^^^^^^^ comment.git-savvy.branches.branch.date
35 | # ^^^^^^ comment.git-savvy.branches.branch.description keyword
36 | 7f561b6 master (origin/master) - desc
37 | # ^^^^^^^^^^^^^^ comment.git-savvy.branches.branch.tracking-info
38 | # ^^^^^^^ comment.git-savvy.branches.branch.description keyword
39 | 7f561b6 master - desc
40 | # ^^^^^^ comment.git-savvy.branches.branch.description keyword
41 | 67df3f5 better-error-handling 12 months ago - desc
42 | # ^^^^^^^^^^^^^ comment.git-savvy.branches.branch.date
43 | # ^^^^^^ comment.git-savvy.branches.branch.description keyword
44 |
45 |
46 |
47 |
48 |
--------------------------------------------------------------------------------
/syntax/test/syntax_test_graph_pick_axe.txt:
--------------------------------------------------------------------------------
1 | # SYNTAX TEST "Packages/GitSavvy/syntax/graph.sublime-syntax"
2 |
3 | REPO: C:\Users\c-flo\AppData\Roaming\Sublime Text\Packages\GitSavvy
4 | [a]ll: false
5 | -S'''
6 | class gs_revert_commit(LogMixin, WindowCommand, GitCommand):
7 | # ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ git-savvy.graph meta.prelude.git_savvy.graph comment.prelude.git_savvy.graph
8 | @on_worker
9 | # ^^^^^^^^^^^^^^^^ git-savvy.graph meta.prelude.git_savvy.graph comment.prelude.git_savvy.graph
10 | def do_action(self, commit_hash, **kwargs):
11 | # ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ git-savvy.graph meta.prelude.git_savvy.graph comment.prelude.git_savvy.graph
12 | try:
13 | # ^^^^^^^^^^^^^^ git-savvy.graph meta.prelude.git_savvy.graph comment.prelude.git_savvy.graph
14 | self.git("revert", *(commit_hash if isinstance(commit_hash, list) else [commit_hash]))
15 | # ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ git-savvy.graph meta.prelude.git_savvy.graph comment.prelude.git_savvy.graph
16 | finally:
17 | # ^^^^^^^^^^^^^^^^^^ git-savvy.graph meta.prelude.git_savvy.graph comment.prelude.git_savvy.graph
18 | util.view.refresh_gitsavvy(self.window.active_view(), refresh_sidebar=True)
19 | # ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ git-savvy.graph meta.prelude.git_savvy.graph comment.prelude.git_savvy.graph
20 | '''
21 | # ^^^ git-savvy.graph meta.prelude.git_savvy.graph comment.prelude.git_savvy.graph
22 |
23 | #< git-savvy.graph meta.prelude.git_savvy.graph
24 | ...
25 | # ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ git-savvy.graph meta.content.git_savvy.graph
26 | ● 96c5f826 Allow to revert multiple commits in one invocation Thu May 2 21:44, herr kaste
27 | # ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ git-savvy.graph meta.content.git_savvy.graph
28 |
--------------------------------------------------------------------------------
/syntax/test/syntax_test_rebase.txt:
--------------------------------------------------------------------------------
1 | # SYNTAX TEST "Packages/GitSavvy/syntax/rebase.sublime-syntax"
2 |
3 | REBASE: status-syntax-improvements --> master (a3b397c)
4 | # ^ comment.git-savvy.summary-header.title.rebase
5 | # ^ meta.git-savvy.rebase-summary
6 | STATUS: Ready.
7 | # ^ comment.git-savvy.summary-header.title.status.rebase
8 | # ^ meta.git-savvy.rebase-summary
9 |
10 | ┬ (a3b397c)
11 | # ^ comment.git-savvy.rebase-graph.base
12 | # ^ punctuation.definition.git-savvy.rebase-graph.base
13 | # ^ punctuation.definition.git-savvy.rebase-graph.base
14 | # ^ support.type.git-savvy.rebase.commit_hash
15 | │
16 | # ^ comment.git-savvy.rebase-graph.separator
17 | ● 442483b Improved syntax denfinition for status dashboard
18 | # ^ comment.git-savvy.rebase-graph.commit-node
19 | # ^ support.type.git-savvy.rebase.commit_hash
20 | # ^ gitsavvy.gotosymbol
21 | ▸ ● 7c317a7 Tags and rebase use the dashboards base syntax
22 | # ^ string.other.git-savvy.rebase.caret
23 | # ^ comment.git-savvy.rebase-graph.commit-node
24 | # ^ support.type.git-savvy.rebase.commit_hash
25 | # ^ gitsavvy.gotosymbol
26 | ▸ ✔ e0e6c12 Improved tags syntax
27 | # ^ string.other.git-savvy.rebase.caret
28 | # ^ entity.name.function.git-savvy.success
29 | # ^ support.type.git-savvy.rebase.commit_hash
30 | # ^ gitsavvy.gotosymbol
31 | ▸ ✘ 53090ba removed code which is moved to dashboard.sublime-syntax
32 | # ^ string.other.git-savvy.rebase.caret
33 | # ^ string.other.git-savvy.conflict
34 | # ^ support.type.git-savvy.rebase.commit_hash
35 | # ^ gitsavvy.gotosymbol
36 | │ ! stuff.todo
37 | # ^ comment.git-savvy.rebase-graph.separator
38 | # ^ keyword.other.name.git-savvy.rebase-conflict
39 | # ^ keyword.other.name.git-savvy.rebase-conflict
40 | ┴
41 | # ^ comment.git-savvy.rebase-graph.end
42 |
43 |
44 | ┳ (a3b397c)
45 | # ^ comment.git-savvy.rebase-graph.base
46 | # ^ punctuation.definition.git-savvy.rebase-graph.base
47 | # ^ punctuation.definition.git-savvy.rebase-graph.base
48 | # ^ support.type.git-savvy.rebase.commit_hash
49 | ┃
50 | # ^ comment.git-savvy.rebase-graph.separator
51 | · 442483b Improved syntax denfinition for status dashboard
52 | # ^ comment.git-savvy.rebase-graph.commit-node
53 | # ^ support.type.git-savvy.rebase.commit_hash
54 | # ^ gitsavvy.gotosymbol
55 | ▸ · 7c317a7 Tags and rebase use the dashboards base syntax
56 | # ^ string.other.git-savvy.rebase.caret
57 | # ^ comment.git-savvy.rebase-graph.commit-node
58 | # ^ support.type.git-savvy.rebase.commit_hash
59 | # ^ gitsavvy.gotosymbol
60 | ▸ ✕ 53090ba removed code which is moved to dashboard.sublime-syntax
61 | # ^ string.other.git-savvy.rebase.caret
62 | # ^ string.other.git-savvy.conflict
63 | # ^ support.type.git-savvy.rebase.commit_hash
64 | # ^ gitsavvy.gotosymbol
65 | ┻
66 | # ^ comment.git-savvy.rebase-graph.end
67 |
--------------------------------------------------------------------------------
/syntax/test/syntax_test_show_commit.txt:
--------------------------------------------------------------------------------
1 | # SYNTAX TEST "Packages/GitSavvy/syntax/show_commit.sublime-syntax"
2 |
3 | commit 174ef25e0714b5187b4713091be2ea9bfd9d3384
4 | # ^ string.other.commit-info.header.key.git-savvy
5 | # ^ meta.commit-info.header.value.git-savvy
6 | # ^ meta.commit-info.header.sha.git-savvy
7 | # <- meta.commit-info.header.key-value
8 | Author: Simon
9 | # ^ string.other.commit-info.header.key.git-savvy
10 | # ^ string.other.commit-info.header.key.punctuation.git-savvy
11 | # ^ meta.commit-info.header.value.git-savvy
12 | # <- meta.commit-info.header.key-value
13 | Commit: Simon
14 | # ^ string.other.commit-info.header.key.git-savvy
15 | # ^ string.other.commit-info.header.key.punctuation.git-savvy
16 | # ^ meta.commit-info.header.value.git-savvy
17 | # <- meta.commit-info.header.key-value
18 |
19 | Improve: semver tags sorting when failure
20 | # <- -meta.commit-info.header.key-value
21 |
--------------------------------------------------------------------------------
/syntax/test/syntax_test_tags.txt:
--------------------------------------------------------------------------------
1 | # SYNTAX TEST "Packages/GitSavvy/syntax/tags.sublime-syntax"
2 |
3 | LOCAL:
4 | # ^ keyword.other.git-savvy.section-header.tags.local
5 | 77dec1d 2.10.1
6 | # ^ constant.other.git-savvy.tags.sha1
7 | # ^ meta.git-savvy.tag.name gitsavvy.gotosymbol
8 |
9 | REMOTE (origin):
10 | # ^ keyword.other.git-savvy.section-header.tags.remote
11 | # ^ punctuation.definition.git-savvy.section-header.remote
12 | # ^ constant.other.git-savvy.tags.remote-name
13 | # ^ punctuation.definition.git-savvy.section-header.remote
14 | 77dec1d 2.10.1
15 | # ^ constant.other.git-savvy.tags.sha1
16 | # ^ meta.git-savvy.tag.name gitsavvy.gotosymbol
17 |
--------------------------------------------------------------------------------