anon-iclr-submission/benchname-bug-localization huggingface dataset:
Repository: timbrel/gitsavvy
Issue: Branch names with '/' don't display correctly

For instance, displaying the status of a branch named `bug/1234` will output a branch name of `bug`.


Changed files:
core/git_mixins/active_branch.py

diff --git a/core/git_mixins/active_branch.py b/core/git_mixins/active_branch.py
index f044f5d9..0cf3c8bb 100644
--- a/core/git_mixins/active_branch.py
+++ b/core/git_mixins/active_branch.py
@@ -34,7 +34,7 @@ class ActiveBranchMixin():
         if first_line.startswith("## Initial commit on "):
             return "Initial commit on `{}`.".format(first_line[21:])
 
-        short_status_pattern = r"## ([A-Za-z0-9\\-_]+)(\\.\\.\\.([A-Za-z0-9\\-_\\/]+)( \\[((ahead (\\d+))(, )?)?(behind (\\d+))?\\])?)?"
+        short_status_pattern = r"## ([A-Za-z0-9\\-_\\/]+)(\\.\\.\\.([A-Za-z0-9\\-_\\/]+)( \\[((ahead (\\d+))(, )?)?(behind (\\d+))?\\])?)?"
         status_match = re.match(short_status_pattern, first_line)
 
         if not status_match:
Repository: timbrel/gitsavvy
Issue: git_command.py utf-8 error

I've started getting this error on Sublime Text 3176 (Portable Edition) with git 2.17.1 on Windows 7.

```
'utf-8' codec can't decode byte 0x8a in position 16: invalid start byte

Traceback (most recent call last):
  File "[...]Sublime\\Data\\Installed Packages\\GitSavvy.sublime-package\\core/git_command.py", line 215, in git
    stdout, stderr = self.decode_stdout(stdout), stderr.decode()
UnicodeDecodeError: 'utf-8' codec can't decode byte 0x8a in position 16: invalid start byte
```

The error appears on loading Sublime and prevents using GitSavvy. It was running until recently with no notable changes and updates.


Changed files:
core/git_command.py

diff --git a/core/git_command.py b/core/git_command.py
index 6d941341..dff3579c 100755
--- a/core/git_command.py
+++ b/core/git_command.py
@@ -212,7 +212,7 @@ class GitCommand(StatusMixin,
                 stdout, stderr = p.communicate(stdin)
 
             if decode:
-                stdout, stderr = self.decode_stdout(stdout), stderr.decode()
+                stdout, stderr = self.decode_stdout(stdout), self.decode_stdout(stderr)
 
             if show_panel and not live_panel_output:
                 initialize_panel()
@@ -236,7 +236,7 @@ class GitCommand(StatusMixin,
                     args,
                     stdin,
                     self.decode_stdout(stdout),
-                    stderr.decode(),
+                    self.decode_stdout(stderr),
                     end - start
                 )
 
@@ -266,7 +266,7 @@ class GitCommand(StatusMixin,
         silent_fallback = self.savvy_settings.get("silent_fallback")
         try:
             return stdout.decode()
-        except UnicodeDecodeError as unicode_err:
+        except UnicodeDecodeError:
             try:
                 return stdout.decode("latin-1")
             except UnicodeDecodeError as unicode_err:
Repository: timbrel/gitsavvy
Issue: Tracking active branch when i push selected( not active) branch

- Sublime Text version 3175
- Git version 2.18.0.windows.1
- OS Win10 x64

In branch-tab when i push selected nontracked branch , system asked me which remote branch to match it , but set tracking active branch, not selected


Changed files:
core/commands/push.py

diff --git a/core/commands/push.py b/core/commands/push.py
index 6ff91084..70d57acb 100644
--- a/core/commands/push.py
+++ b/core/commands/push.py
@@ -74,6 +74,7 @@ class GsPushCommand(WindowCommand, PushBase):
         elif self.savvy_settings.get("prompt_for_tracking_branch"):
             if sublime.ok_cancel_dialog(SET_UPSTREAM_PROMPT):
                 self.window.run_command("gs_push_to_branch_name", {
+                    "local_branch_name": self.local_branch_name,
                     "set_upstream": True,
                     "force": self.force,
                     "force_with_lease": self.force_with_lease
@@ -82,6 +83,7 @@ class GsPushCommand(WindowCommand, PushBase):
             # if `prompt_for_tracking_branch` is false, ask for a remote and perform
             # push current branch to a remote branch with the same name
             self.window.run_command("gs_push_to_branch_name", {
+                "local_branch_name": self.local_branch_name,
                 "branch_name": self.local_branch_name,
                 "set_upstream": False,
                 "force": self.force,
@@ -117,7 +119,18 @@ class GsPushToBranchNameCommand(WindowCommand, PushBase):
     Prompt for remote and remote branch name, then push.
     """
 
-    def run(self, branch_name=None, set_upstream=False, force=False, force_with_lease=False):
+    def run(
+            self,
+            local_branch_name=None,
+            branch_name=None,
+            set_upstream=False,
+            force=False,
+            force_with_lease=False):
+        if local_branch_name:
+            self.local_branch_name = local_branch_name
+        else:
+            self.local_branch_name = self.get_current_branch_name()
+
         self.branch_name = branch_name
         self.set_upstream = set_upstream
         self.force = force
@@ -140,10 +153,9 @@ class GsPushToBranchNameCommand(WindowCommand, PushBase):
         if self.branch_name:
             self.on_entered_branch_name(self.branch_name)
         else:
-            current_local_branch = self.get_current_branch_name()
             show_single_line_input_panel(
                 PUSH_TO_BRANCH_NAME_PROMPT,
-                current_local_branch,
+                self.local_branch_name,
                 self.on_entered_branch_name
             )
 
@@ -154,7 +166,7 @@ class GsPushToBranchNameCommand(WindowCommand, PushBase):
         """
         sublime.set_timeout_async(lambda: self.do_push(
             self.selected_remote,
-            self.get_current_branch_name(),
+            self.local_branch_name,
             force=self.force,
             force_with_lease=self.force_with_lease,
             remote_branch=branch))
Repository: timbrel/gitsavvy
Issue: Files incorrectly flagged as merge conflicts during inline diff

For some files, when I try to start an inline diff it is flagged as containing a merge conflict and the diff does not open.

I tracked down the source of this and it was introduced in https://github.com/timbrel/GitSavvy/commit/8df9b46a4d34014949286aaecad3a6398fa1ee7b, specifically in `safely_parse_metadata`

The issue seems to be that the regex is picking up extra results based on the content of the diff, in addition to the metadata. As an example, for the input:

```
@@ -7,0 +8 @@ RCall = "6f49c342-dc21-5d91-9882-a32aef131414"
```

the output is `[(7, 0), (8, 1), (5, 1), (9882, 1)]`

Another example is 

```
@@ -295 +313 @@ docs-main:iai-2.0.0:
```

giving `[(295, 1), (313, 1), (2, 1)]`

It seems like the previous version was limiting the search to inside the `@@ ... @@` whereas now it is not, and it is flagging the diff a merge conflict because there are more than two elements in the returned metadata.

Changed files:
core/parse_diff.py, tests/test_hunk_counting.py

diff --git a/core/parse_diff.py b/core/parse_diff.py
index d3331be6..e635cb6f 100644
--- a/core/parse_diff.py
+++ b/core/parse_diff.py
@@ -219,7 +219,9 @@ class HunkHeader(TextRange):
         """
         return [
             (int(start), int(length or "1"))
-            for start, length in SAFE_PARSE_HUNK_HEADER.findall(self.text)
+            for start, length in SAFE_PARSE_HUNK_HEADER.findall(
+                self.text.lstrip("@").split("@", 1)[0]
+            )
         ]
 
 
diff --git a/tests/test_hunk_counting.py b/tests/test_hunk_counting.py
index 519ea8b5..2a7b9dab 100644
--- a/tests/test_hunk_counting.py
+++ b/tests/test_hunk_counting.py
@@ -6,6 +6,7 @@ from GitSavvy.tests.parameterized import parameterized as p
 from GitSavvy.core.fns import accumulate, unzip
 
 import GitSavvy.core.commands.diff as module
+from GitSavvy.core.parse_diff import HunkHeader
 
 
 f1 = """\\
@@ -275,3 +276,15 @@ class TestDiffPatchGeneration(DeferrableTestCase):
                 raise _ExpectedFailure(sys.exc_info())
 
         self.assertEqual(expected, actual)
+
+
+class HunkHeaderNumberExtraction(DeferrableTestCase):
+    @p.expand([
+        ("@@ -685,8 +686,14 @@ ...", [(685, 8), (686, 14)]),
+        ("@@@ -685,8 -644 +686,14 @@@ ...", [(685, 8), (644, 1), (686, 14)]),
+        ('@@ -7,0 +8 @@ RCall = "6f49c342-dc21-5d91-9882-a32aef131414"', [(7, 0), (8, 1)]),
+        ("@@ -295 +313 @@ docs-main:iai-2.0.0:", [(295, 1), (313, 1)]),
+    ])
+    def test_safely_parse_metadata(self, input, expected):
+        actual = HunkHeader(input).safely_parse_metadata()
+        self.assertEqual(expected, actual)
Repository: timbrel/gitsavvy
Issue: gs_show_commit with `HEAD` opens up the wrong commit

It used to show the last commit in current branch (i.e HEAD), and now it seems stuck to some commit down the tree... perhaps there's some caching magic that was added that identifies HEAD as a unique commit :/ .. not sure if there's a use case here for typical GitSavvy usage; but, for me, it can be nice to see a `skip_cache` sort of argument to avoid this.

Changed files:
core/git_mixins/history.py, core/commands/show_commit.py

diff --git a/core/commands/show_commit.py b/core/commands/show_commit.py
index 9e2142f0..b738f0fc 100644
--- a/core/commands/show_commit.py
+++ b/core/commands/show_commit.py
@@ -41,6 +41,9 @@ class gs_show_commit(WindowCommand, GitCommand):
     def run(self, commit_hash):
         # need to get repo_path before the new view is created.
         repo_path = self.repo_path
+        if commit_hash in {"", "HEAD"}:
+            commit_hash = self.git("rev-parse", "--short", "HEAD").strip()
+
         this_id = (
             self.repo_path,
             commit_hash
diff --git a/core/git_mixins/history.py b/core/git_mixins/history.py
index 9453a1df..3007b273 100644
--- a/core/git_mixins/history.py
+++ b/core/git_mixins/history.py
@@ -306,6 +306,15 @@ class HistoryMixin():
         ignore_whitespace=False
     ):
         # type: (str, Optional[str], bool, bool, bool) -> str
+        if not commit_hash or commit_hash == "HEAD":
+            return self._read_commit(
+                commit_hash,
+                file_path,
+                show_diffstat,
+                show_patch,
+                ignore_whitespace
+            )
+
         key = (
             "read_commit",
             self.repo_path,
Repository: timbrel/gitsavvy
Issue: inline-diff newline change ambiguity

This code

```
Line 1 content
// comment
Line 3 content
```

and this code

```
Line 1 content

// comment
Line 3 content
```

generate the same inline diff:

```
Line 1 content

// comment  <--- (green text)
Line 3 content
```

There's no indication of whether I've added a newline or not.

If I simply add or remove a newline, the diff acts as expected. It's only when I add text to a previously blank line that this ambiguity shows up.

Obviously this isn't a huge deal, as I know where I've added newlines and where I haven't, and these comments aren't generally things I'll be committing; it's just a little bit unexpected behavior.


Changed files:
core/commands/inline_diff.py

diff --git a/core/commands/inline_diff.py b/core/commands/inline_diff.py
index 1a5662c3..3146161a 100644
--- a/core/commands/inline_diff.py
+++ b/core/commands/inline_diff.py
@@ -264,8 +264,7 @@ class GsInlineDiffRefreshCommand(TextCommand, GitCommand):
                     region_type = line_type
                     region_start = line.begin()
                 elif region_type != line_type:
-                    # End region with final character of previous line.
-                    region_end = line.begin() - 1
+                    region_end = line.begin()
                     l = add_regions if region_type == "+" else remove_regions
                     l.append(sublime.Region(region_start, region_end))
Repository: timbrel/gitsavvy
Issue: Diff view does not switch when staged

A recent changes seems to make it so that gitsavvy doesn't know the difference between the "diff view" and the "diff view (staged)".  Steps:

1. Change a file.
2. In the "Git Status" view, press `f` (lowercase) to open a view to show the changes.
3. Go back to the status view (without closing the diff view), and stage the change.
4. Press `Shift-F` to open a view to show the staged changes.

What happens: Pressing `Shift-F` brings focus to the diff view opened in step 2, which refreshes and is empty.

Expected: Pressing `Shift-F` should open a new view with the staged changes.

This used to work, but something changed recently so that it doesn't seem to work right. A workaround is to close the diff view before step 4.

Using  2.22.2.


Changed files:
core/commands/diff.py

diff --git a/core/commands/diff.py b/core/commands/diff.py
index cdf75652..75e2b924 100644
--- a/core/commands/diff.py
+++ b/core/commands/diff.py
@@ -143,6 +143,7 @@ class gs_diff(WindowCommand, GitCommand):
         for view in self.window.views():
             if compute_identifier_for_view(view) == this_id:
                 settings = view.settings()
+                settings.set("git_savvy.diff_view.in_cached_mode", in_cached_mode)
                 focus_view(view)
                 break
Repository: timbrel/gitsavvy
Issue: Bug: branch interface doesn't open graph for selected branch

When in branch interface, hit `[g]` to open graph under for the branch under the cursor. Instead, the graph view opens with the checked out branch, not the branch under cursor.

- Sublime Text 3 3184
- Git 2.19.1
- OS type and version 10.14.1 (18B75)
- Console error output -nothing

Git bisect points at 6a6c612 as the culprit, and we can see the `LogGraphMixin` command no longer uses `get_graph_args`, and users of the mixin need to use `prepare_target_view` to set additional graph arguments as view settings.

Changed files:
core/interfaces/branch.py

diff --git a/core/interfaces/branch.py b/core/interfaces/branch.py
index 95210137..b7efabd2 100644
--- a/core/interfaces/branch.py
+++ b/core/interfaces/branch.py
@@ -658,7 +658,5 @@ class GsBranchesLogGraphCommand(LogGraphMixin, TextCommand, GitCommand):
         self._file_path = None
         super().run_async()
 
-    def get_graph_args(self):
-        args = super().get_graph_args()
-        args.append(self._branch)
-        return args
+    def prepare_target_view(self, view):
+        view.settings().set("git_savvy.log_graph_view.filter_by_branch", self._branch)
Repository: timbrel/gitsavvy
Issue: Git push after deleting remote branch does nothing.

1. Checkout a remote branch as local.
2. Delete the remote branch (ie, `git push --delete origin blah`)
3. Status page correctly shows "Remote branch is gone"
4. Now do "git: push". Nothing happens at all.

What I think should happen:

Same as doing "git: push to branch name" (ie, prompting for remote and branch name), which worked just fine.

Changed files:
core/commands/push.py

diff --git a/core/commands/push.py b/core/commands/push.py
index 70d57acb..5fadf154 100644
--- a/core/commands/push.py
+++ b/core/commands/push.py
@@ -57,11 +57,10 @@ class GsPushCommand(WindowCommand, PushBase):
         sublime.set_timeout_async(self.run_async)
 
     def run_async(self):
-        if self.local_branch_name:
-            upstream = self.get_local_branch(self.local_branch_name).tracking
-        else:
+        if not self.local_branch_name:
             self.local_branch_name = self.get_current_branch_name()
-            upstream = self.get_upstream_for_active_branch()
+
+        upstream = self.get_local_branch(self.local_branch_name).tracking
 
         if upstream:
             remote, remote_branch = upstream.split("/", 1)
Repository: timbrel/gitsavvy
Issue: cherry-pick: 'GsCherryPickCommand' object has no attribute 'view'

- Sublime Text version number 3176
- Git version number 2.15.1 (Apple Git-101)
- OS type and version macOS 10.13.4
- Console error output 

```
Traceback (most recent call last):
  File "/Users/koenlageveen/Library/Application Support/Sublime Text 3/Installed Packages/GitSavvy.sublime-package/core/ui_mixins/quick_panel.py", line 526, in <lambda>
  File "/Users/koenlageveen/Library/Application Support/Sublime Text 3/Installed Packages/GitSavvy.sublime-package/core/ui_mixins/quick_panel.py", line 530, in on_selection_async
  File "/Users/koenlageveen/Library/Application Support/Sublime Text 3/Installed Packages/GitSavvy.sublime-package/core/commands/log.py", line 32, in <lambda>
  File "/Users/koenlageveen/Library/Application Support/Sublime Text 3/Installed Packages/GitSavvy.sublime-package/core/commands/log.py", line 37, in on_done
  File "/Users/koenlageveen/Library/Application Support/Sublime Text 3/Installed Packages/GitSavvy.sublime-package/core/commands/cherry_pick.py", line 17, in do_action
AttributeError: 'GsCherryPickCommand' object has no attribute 'view'
```

- A description of the problem: When a cherry-pick is successful it seems to try and log something, which fails.


[debug.txt](https://github.com/divmain/GitSavvy/files/2016309/debug.txt)



Changed files:
core/commands/cherry_pick.py

diff --git a/core/commands/cherry_pick.py b/core/commands/cherry_pick.py
index ce83e4fa..adf0ec18 100644
--- a/core/commands/cherry_pick.py
+++ b/core/commands/cherry_pick.py
@@ -14,5 +14,5 @@ class GsCherryPickCommand(GsLogByBranchCommand):
 
     def do_action(self, commit_hash, **kwargs):
         self.git("cherry-pick", commit_hash)
-        self.view.window().status_message("Commit %s cherry-picked successfully." % commit_hash)
+        sublime.active_window().status_message("Commit %s cherry-picked successfully." % commit_hash)
         util.view.refresh_gitsavvy(self.window.active_view())
Repository: timbrel/gitsavvy
Issue: GitSavvy's tab moving

When GitSavvy's tab is first tab and when we change content of tab to GRAPH using TAB key or Shift+TAB key it became second tab.

Changed files:
core/interfaces/__init__.py

diff --git a/core/interfaces/__init__.py b/core/interfaces/__init__.py
index af936327..7d708258 100644
--- a/core/interfaces/__init__.py
+++ b/core/interfaces/__init__.py
@@ -25,6 +25,9 @@ class GsTabCycleCommand(TextCommand, GitCommand):
     }
 
     def run(self, edit, source=None, target=None, reverse=False):
+        sublime.set_timeout_async(lambda: self.run_async(source, target, reverse))
+
+    def run_async(self, source, target, reverse):
         to_load = target or self.get_next(source, reverse)
         view_signature = self.view_signatures[to_load]
 
@@ -32,7 +35,7 @@ class GsTabCycleCommand(TextCommand, GitCommand):
 
         self.view.window().run_command(self.commands[to_load])
         if not self.view.settings().get(view_signature):
-            self.view.close()
+            sublime.set_timeout_async(self.view.close)
 
     def get_next(self, source, reverse=False):
         savvy_settings = sublime.load_settings("GitSavvy.sublime-settings")
Repository: timbrel/gitsavvy
Issue: Undo broken on Rebase dashboard

After performing an action on the Rebase dashboard, hitting Super-Z doesn’t undo the action. It outputs the following error to the console:

```
Traceback (most recent call last):
  File "/Users/kyank/Library/Application Support/Sublime Text 3/Packages/GitSavvy/core/interfaces/rebase.py", line 353, in run_async
    branch_name, ref = self.interface.get_branch_state()
ValueError: too many values to unpack (expected 2)
```

Reproduced on latest release and master.


Changed files:
core/interfaces/rebase.py

diff --git a/core/interfaces/rebase.py b/core/interfaces/rebase.py
index 9b7da80e..25b74d30 100644
--- a/core/interfaces/rebase.py
+++ b/core/interfaces/rebase.py
@@ -350,7 +350,7 @@ class GsRebaseUndoCommand(TextCommand, GitCommand):
         if log is None or cursor is None or cursor == -1:
             return
 
-        branch_name, ref = self.interface.get_branch_state()
+        branch_name, ref, _ = self.interface.get_branch_state()
 
         current = log[cursor]
         if current["branch_name"] != branch_name:
@@ -388,7 +388,7 @@ class GsRebaseRedoCommand(TextCommand, GitCommand):
         if log is None or cursor is None or cursor == len(log) - 1:
             return
 
-        branch_name, ref = self.interface.get_branch_state()
+        branch_name, ref, _ = self.interface.get_branch_state()
 
         undone_action = log[cursor+1]
         if undone_action["branch_name"] != branch_name:
Repository: timbrel/gitsavvy
Issue: Not picking up `typechange`

Gitsavvy isn't picking up the type changes in the status dashboard.

Steps to reproduce:
- create a symlink for a file
- commit the file
- delete the symlink and add a file (not a symlink) with the same name back in

After these steps, Gitsavvy reports that the directory is clean, whereas running `git status` reports that there is a `typechange` (as opposed to `modified` and others).


Changed files:
core/git_mixins/status.py

diff --git a/core/git_mixins/status.py b/core/git_mixins/status.py
index 34899496..f6c738f7 100644
--- a/core/git_mixins/status.py
+++ b/core/git_mixins/status.py
@@ -105,7 +105,7 @@ class StatusMixin():
             if f.index_status == "?":
                 untracked.append(f)
                 continue
-            elif f.working_status in ("M", "D"):
+            elif f.working_status in ("M", "D", "T"):
                 unstaged.append(f)
             if f.index_status != " ":
                 staged.append(f)
Repository: timbrel/gitsavvy
Issue: GitSavvy makes Sublime unusable when git is not installed

I installed sublime on a new machine. I copied AppData/Roaming/Sublime Text 3. When I try to do anything, GitSavvy absolutely blasts me with messages that git can't be found. It has made sublime utterly unusable. I can't even disable the package, because trying to open the command window triggers another message.

FOR THE LOVE OF GOD, ADD AN OPTION FOR "SHUT THE F*** UP! I KNOW I DON'T HAVE GIT INSTALLED YET!"

Changed files:
core/git_command.py

diff --git a/core/git_command.py b/core/git_command.py
index 4997534c..94834e76 100755
--- a/core/git_command.py
+++ b/core/git_command.py
@@ -29,7 +29,7 @@ from .exceptions import GitSavvyError
 
 
 git_path = None
-
+error_message_displayed = False
 
 UTF8_PARSE_ERROR_MSG = (
     "GitSavvy was unable to parse Git output as UTF-8. Would "
@@ -183,7 +183,7 @@ class GitCommand(StatusMixin,
         Return the path to the available `git` binary.
         """
 
-        global git_path
+        global git_path, error_message_displayed
         if not git_path:
             git_path_setting = sublime.load_settings("GitSavvy.sublime-settings").get("git_path")
             if isinstance(git_path_setting, dict):
@@ -200,7 +200,9 @@ class GitCommand(StatusMixin,
             msg = ("Your Git binary cannot be found.  If it is installed, add it "
                    "to your PATH environment variable, or add a `git_path` setting "
                    "in the `User/GitSavvy.sublime-settings` file.")
-            sublime.error_message(msg)
+            if not error_message_displayed:
+                sublime.error_message(msg)
+                error_message_displayed = True
             raise ValueError("Git binary not found.")
 
         return git_path
Repository: timbrel/gitsavvy
Issue: Branches dashboard: "[o] checkout remote as local" fails when there are no local branches

When there are no local branches, trying to create a branch by hitting `[o]` does nothing. The console shows the error message:

>Traceback (most recent call last):
  File "core.interfaces.branch in /Users/Allen/Library/Application Support/Sublime Text 3/Installed Packages/GitSavvy.sublime-package", line 218, in run_async
IndexError: list index out of range

Changed files:
core/interfaces/branch.py

diff --git a/core/interfaces/branch.py b/core/interfaces/branch.py
index 8d167993..e94ab345 100644
--- a/core/interfaces/branch.py
+++ b/core/interfaces/branch.py
@@ -250,10 +250,13 @@ class GsBranchesCheckoutAsLocalCommand(TextCommand, GitCommand):
         segments = line.strip("▸ ").split(" ")
         branch_name = segments[1]
 
-        local_region = self.view.get_regions("git_savvy_interface.branch_list")[0]
-        if local_region.contains(selection):
-            # No-op if selection is a local branch.
-            return
+        selected_branches = self.view.get_regions("git_savvy_interface.branch_list")
+        if selected_branches:
+            # No-op if there are no branches
+            local_region = selected_branches[0]
+            if local_region.contains(selection):
+                # No-op if selection is a local branch.
+                return
 
         remotes = self.get_remotes()
         for remote_name in remotes:
Repository: timbrel/gitsavvy
Issue: Dashboards don't work well with emoji in branch names

For example, `this-branch-is-da-💥` works fine from the command line, but the Status dashboard shows `None.` as the branch name, the branch dashboard doesn't show the branch at all, and the rebase dashboard doesn't function correctly.  This is likely due to an omission in a regular expression we're using for branch name detection somewhere.

Changed files:
core/git_mixins/branches.py, core/git_mixins/active_branch.py, core/commands/checkout.py

diff --git a/core/commands/checkout.py b/core/commands/checkout.py
index 6d67608b..58d70e19 100644
--- a/core/commands/checkout.py
+++ b/core/commands/checkout.py
@@ -58,7 +58,7 @@ class GsCheckoutNewBranchCommand(WindowCommand, GitCommand):
         self.window.show_input_panel(NEW_BRANCH_PROMPT, name, self.on_done, None, None)
 
     def on_done(self, branch_name):
-        pattern = r"^(?!\\.|.*\\.\\..*|.*@.*|\\/)[a-zA-Z0-9\\-\\_\\/\\.]+(?<!\\.lock)(?<!\\/)(?<!\\.)$"
+        pattern = r"^(?!\\.|.*\\.\\..*|.*@.*|\\/)[a-zA-Z0-9\\-\\_\\/\\.\\u263a-\\U0001f645]+(?<!\\.lock)(?<!\\/)(?<!\\.)$"
         match = re.match(pattern, branch_name)
         if not match:
             sublime.error_message("`{}` is a invalid branch name.\\nRead more on $(man git-check-ref-format)".format(branch_name))
diff --git a/core/git_mixins/active_branch.py b/core/git_mixins/active_branch.py
index 384df8c9..125e160a 100644
--- a/core/git_mixins/active_branch.py
+++ b/core/git_mixins/active_branch.py
@@ -41,7 +41,7 @@ class ActiveBranchMixin():
             return False, True, first_line[21:], clean, None, None, None, False
 
         valid_punctuation = "".join(c for c in string.punctuation if c not in "~^:?*[\\\\")
-        branch_pattern = "[A-Za-z0-9" + re.escape(valid_punctuation) + "]+?"
+        branch_pattern = "[A-Za-z0-9" + re.escape(valid_punctuation) + "\\u263a-\\U0001f645]+?"
         short_status_pattern = "## (" + branch_pattern + ")(\\.\\.\\.(" + branch_pattern + ")( \\[((ahead (\\d+))(, )?)?(behind (\\d+))?(gone)?\\])?)?$"
         status_match = re.match(short_status_pattern, first_line)
 
diff --git a/core/git_mixins/branches.py b/core/git_mixins/branches.py
index bb8e8834..e67f51ad 100644
--- a/core/git_mixins/branches.py
+++ b/core/git_mixins/branches.py
@@ -33,8 +33,7 @@ class BranchesMixin():
         if not line:
             return None
 
-        pattern = r"(\\* )?(remotes/)?([a-zA-Z0-9\\-\\_\\/\\.\\-]+(?<!\\.lock)(?<!\\/)(?<!\\.)) +([0-9a-f]{40}) (\\[([a-zA-Z0-9\\-\\_\\/\\.]+)(: ([^\\]]+))?\\] )?(.*)"
-        r"((: ))?"
+        pattern = r"(\\* )?(remotes/)?([a-zA-Z0-9\\-\\_\\/\\.\\-\\u263a-\\U0001f645]+(?<!\\.lock)(?<!\\/)(?<!\\.)) +([0-9a-f]{40}) (\\[([a-zA-Z0-9\\-\\_\\/\\.]+)(: ([^\\]]+))?\\] )?(.*)"
 
         match = re.match(pattern, line)
         if not match:
Repository: timbrel/gitsavvy
Issue: live_panel_output sometimes is out of sync

the log panel is still buggy

When I do `review pull request`, the output is out of sync

```
> /usr/local/bin/git fetch https://github.com/ydsdsa/AlignTab.git patch-1

[Done in 0.36s]From https://github.com/ydsdsa/AlignTab
 * branch            patch-1    -> FETCH_HEAD

```

Relevant settings
```
    "show_panel_for": [
        "commit",
        "apply",
        "fetch",
        "pull",
        "push"
    ],
    "live_panel_output": true
```

I have concluded that it is due to a synchronization issue between the io threads and the process thread. https://github.com/divmain/GitSavvy/blob/797f79ba9aa64c94efe2722eae49344b6655a66c/core/git_command.py#L106-L107

I don't have more time to further investigate now.

Changed files:
common/util/log.py, core/git_command.py

diff --git a/common/util/log.py b/common/util/log.py
index 6890da9f..4b235006 100644
--- a/common/util/log.py
+++ b/common/util/log.py
@@ -3,9 +3,11 @@ import sublime
 
 def panel(*msgs):
     msg = "\\n".join(str(msg) for msg in msgs)
-    sublime.active_window().active_view().run_command("gs_display_panel", {"msg": msg})
+    sublime.set_timeout_async(
+        lambda: sublime.active_window().active_view().run_command("gs_display_panel", {"msg": msg}))
 
 
 def panel_append(*msgs):
     msg = "\\n".join(str(msg) for msg in msgs)
-    sublime.active_window().active_view().run_command("gs_append_panel", {"msg": msg})
+    sublime.set_timeout_async(
+        lambda: sublime.active_window().active_view().run_command("gs_append_panel", {"msg": msg}))
diff --git a/core/git_command.py b/core/git_command.py
index 67a2c5c6..a04260c1 100755
--- a/core/git_command.py
+++ b/core/git_command.py
@@ -65,7 +65,7 @@ class LoggingProcessWrapper(object):
 
     def read_stdout(self):
         try:
-            for line in self.process.stdout:
+            for line in iter(self.process.stdout.readline, b""):
                 self.stdout = self.stdout + line
                 util.log.panel_append(line.decode())
         except IOError as err:
@@ -73,7 +73,7 @@ class LoggingProcessWrapper(object):
 
     def read_stderr(self):
         try:
-            for line in self.process.stderr:
+            for line in iter(self.process.stderr.readline, b""):
                 self.stderr = self.stderr + line
                 util.log.panel_append(line.decode())
         except IOError as err:
@@ -100,11 +100,9 @@ class LoggingProcessWrapper(object):
 
         savvy_settings = sublime.load_settings("GitSavvy.sublime-settings")
         timeout = savvy_settings.get("live_panel_output_timeout", 10000)
-        # 10s timeout default
-        max_run_time = time.monotonic() - timeout
 
-        stdout_thread.join(self.process._remaining_time(max_run_time))
-        stderr_thread.join(self.process._remaining_time(max_run_time))
+        stdout_thread.join(timeout / 1000)
+        stderr_thread.join(timeout / 1000)
 
         return self.stdout, self.stderr
Repository: timbrel/gitsavvy
Issue: Unable to delete or push tag

- Sublime Text version number: Build 3159 (happens under previous versions also)
- Git version number: 2.14.2
- OS type and version: MacOS 10.13.3
- Console error output:
```
`/usr/local/bin/git tag -d 7 v1.77` failed with following output:

error: tag '7 v1.77' not found.
```
- A description of the problem:
I found the `[d] delete` and `[p] push to remote` commands cannot properly parse the tag. For tags displayed as below in TAGS view:
```
  LOCAL:
    1160e4b17 v1.77
    4a719e149 v1.73
    ... ...
```
`delete` and `push` commands will always grab the last character of the commit id + the tag id (e.g. `7 v1.77`,  `9 v1.73`), but `[l] view commit` command can correct parse and display the tag



Changed files:
core/interfaces/tags.py

diff --git a/core/interfaces/tags.py b/core/interfaces/tags.py
index f06a1530..f23a8508 100644
--- a/core/interfaces/tags.py
+++ b/core/interfaces/tags.py
@@ -20,6 +20,15 @@ START_PUSH_MESSAGE = "Pushing tag..."
 END_PUSH_MESSAGE = "Push complete."
 
 
+def tag_from_lines(lines):
+    tags = []
+    for line in lines:
+        m = line.strip().split(" ", 1)
+        if len(m) == 2:
+            tags.append(m[1].strip())
+    return tags
+
+
 class GsShowTagsCommand(WindowCommand, GitCommand):
 
     """
@@ -227,7 +236,7 @@ class GsTagsDeleteCommand(TextCommand, GitCommand):
 
     def delete_local(self, interface):
         lines = interface.get_selection_lines_in_region("local_tags")
-        tags_to_delete = tuple(line[12:].strip() for line in lines if line)
+        tags_to_delete = tag_from_lines(lines)
 
         if not tags_to_delete:
             return
@@ -244,7 +253,7 @@ class GsTagsDeleteCommand(TextCommand, GitCommand):
 
         for remote_name, remote in interface.remotes.items():
             lines = interface.get_selection_lines_in_region("remote_tags_list_" + remote_name)
-            tags_to_delete = tuple(line[12:].strip() for line in lines if line[:4] == "    ")
+            tags_to_delete = tag_from_lines(lines)
 
             if tags_to_delete:
                 self.git(
@@ -295,7 +304,7 @@ class GsTagsPushCommand(TextCommand, GitCommand):
 
         interface = ui.get_interface(self.view.id())
         lines = interface.get_selection_lines_in_region("local_tags")
-        tags_to_push = tuple(line[12:].strip() for line in lines if line)
+        tags_to_push = tag_from_lines(lines)
 
         self.view.window().status_message(START_PUSH_MESSAGE)
         self.git("push", remote, *("refs/tags/" + tag for tag in tags_to_push))
Repository: timbrel/gitsavvy
Issue: use_syntax_for_commit_editmsg setting to use native syntax doesn't work in some cases

`use_syntax_for_commit_editmsg` setting, to use sublime's built-in syntax for commit messages, doesn't work in case when commit file is opened from external editor (from command line for example using  `git commit`).

I see in the code that there is GitCommit command that switches to native syntax but that command is obviously not trigged in that case (because commit is triggered externally). There is also a load listener which still applies gitsavvy commit syntax, without considering `use_syntax_for_commit_editmsg` setting. That seems to be the bug.

I expect that when `use_syntax_for_commit_editmsg` is enabled, native syntax will be used for git commit files, regardless of how commit file is opened.

Sublime 3 b3161
git version 2.15.1 (Apple Git-101)
macOs 10.13

Changed files:
common/global_events.py

diff --git a/common/global_events.py b/common/global_events.py
index 5886cff6..746bfd2e 100644
--- a/common/global_events.py
+++ b/common/global_events.py
@@ -2,6 +2,7 @@ import sublime
 from sublime_plugin import EventListener, WindowCommand
 
 from . import util
+from ..core.settings import SettingsMixin
 
 
 class GsInterfaceFocusEventListener(EventListener):
@@ -26,12 +27,16 @@ git_view_syntax = {
 }
 
 
-class GitCommandFromTerminal(EventListener):
+class GitCommandFromTerminal(EventListener, SettingsMixin):
     def on_load(self, view):
         if view.file_name():
             name = view.file_name().split("/")[-1]
             if name in git_view_syntax.keys():
-                view.set_syntax_file(git_view_syntax[name])
+                syntax_file = git_view_syntax[name]
+                if "COMMIT_EDITMSG" == name and self.savvy_settings.get("use_syntax_for_commit_editmsg"):
+                    syntax_file = util.file.get_syntax_for_file("COMMIT_EDITMSG")
+
+                view.set_syntax_file(syntax_file)
                 view.settings().set("git_savvy.{}_view".format(name), True)
                 view.set_scratch(True)
Repository: timbrel/gitsavvy
Issue: Graph Current File is showing the branch not jut the file

Perhaps I'm doing something wrong but when I try to get a graph just with the commits of the file I'm working on I'm getting the whole branch. 

Is this the intended behavior or is there a bug? 

Changed files:
core/commands/log_graph.py

diff --git a/core/commands/log_graph.py b/core/commands/log_graph.py
index 11edd168..fc6d2631 100644
--- a/core/commands/log_graph.py
+++ b/core/commands/log_graph.py
@@ -717,20 +717,21 @@ class gs_log_graph_refresh(TextCommand, GitCommand):
         follow = self.savvy_settings.get("log_follow_rename")
         author = settings.get("git_savvy.log_graph_view.filter_by_author")
         all_branches = settings.get("git_savvy.log_graph_view.all_branches")
+        fpath = self.file_path
         args = [
             'log',
             '--graph',
             '--decorate',  # set explicitly for "decorate-refs-exclude" to work
             '--date={}'.format(DATE_FORMAT),
             '--pretty=format:%h%d %<|(80,trunc)%s | %ad, %an',
-            '--follow' if self.file_path and follow else None,
+            '--follow' if fpath and follow else None,
             '--author={}'.format(author) if author else None,
             '--decorate-refs-exclude=refs/remotes/origin/HEAD',  # cosmetics
             '--exclude=refs/stash',
             '--all' if all_branches else None,
         ]
 
-        if settings.get('git_savvy.log_graph_view.decoration') == 'sparse':
+        if not fpath and settings.get('git_savvy.log_graph_view.decoration') == 'sparse':
             args += ['--simplify-by-decoration', '--sparse']
 
         branches = settings.get("git_savvy.log_graph_view.branches")
@@ -741,9 +742,8 @@ class gs_log_graph_refresh(TextCommand, GitCommand):
         if filters:
             args += shlex.split(filters)
 
-        if self.file_path:
-            file_path = self.get_rel_path(self.file_path)
-            args += ["--", file_path]
+        if fpath:
+            args += ["--", self.get_rel_path(fpath)]
 
         return args