nebius/SWE-bench-extra huggingface dataset:
Repository: akolar/ogn-lib

Issue:
Implement parser for Spot messages (OGSPOT)

Comments:

Patch:
diff --git a/ogn_lib/parser.py b/ogn_lib/parser.py
index f43f6cb..a2ca7ea 100644
--- a/ogn_lib/parser.py
+++ b/ogn_lib/parser.py
@@ -627,3 +627,33 @@ class ServerParser(Parser):
         """
 
         return {'comment': comment}
+
+
+class Spot(Parser):
+    """
+    Parser for Spot-formatted APRS messages.
+    """
+
+    __destto__ = ['OGSPOT', 'OGSPOT-1']
+
+    @staticmethod
+    def _parse_protocol_specific(comment):
+        """
+        Parses the comment string from Spot's APRS messages.
+
+        :param str comment: comment string
+        :return: parsed comment
+        :rtype: dict
+        """
+
+        fields = comment.split(' ', maxsplit=2)
+
+        if len(fields) < 3:
+            raise exceptions.ParseError('SPOT comment incorrectly formatted: '
+                                        'received {}'.format(comment))
+
+        return {
+            'id': fields[0],
+            'model': fields[1],
+            'status': fields[2]
+        }


Test patch:
diff --git a/tests/test_parser.py b/tests/test_parser.py
index cb9b05c..bcd3247 100644
--- a/tests/test_parser.py
+++ b/tests/test_parser.py
@@ -440,6 +440,18 @@ class TestNaviter:
         assert data['address_type'] is constants.AddressType.naviter
 
 
+class TestSpot:
+    def test_parse_protocol_specific(self):
+        data = parser.Spot._parse_protocol_specific('id0-2860357 SPOT3 GOOD')
+        assert data['id'] == 'id0-2860357'
+        assert data['model'] == 'SPOT3'
+        assert data['status'] == 'GOOD'
+
+    def test_parse_protocol_specific_fail(self):
+        with pytest.raises(exceptions.ParseError):
+            parser.Spot._parse_protocol_specific('id0-2860357 SPOT3')
+
+
 class TestServerParser:
 
     def test_parse_message_beacon(self, mocker):
Repository: akolar/ogn-lib

Issue:
Implement parser for Spider messages (OGSPID)

Comments:

Patch:
diff --git a/ogn_lib/parser.py b/ogn_lib/parser.py
index a2ca7ea..00093ea 100644
--- a/ogn_lib/parser.py
+++ b/ogn_lib/parser.py
@@ -629,31 +629,32 @@ class ServerParser(Parser):
         return {'comment': comment}
 
 
-class Spot(Parser):
+class Spider(Parser):
     """
-    Parser for Spot-formatted APRS messages.
+    Parser for Spider-formatted APRS messages.
     """
 
-    __destto__ = ['OGSPOT', 'OGSPOT-1']
+    __destto__ = ['OGSPID', 'OGSPID-1']
 
     @staticmethod
     def _parse_protocol_specific(comment):
         """
-        Parses the comment string from Spot's APRS messages.
+        Parses the comment string from Spider's APRS messages.
 
         :param str comment: comment string
         :return: parsed comment
         :rtype: dict
         """
 
-        fields = comment.split(' ', maxsplit=2)
+        fields = comment.split(' ', maxsplit=3)
 
-        if len(fields) < 3:
-            raise exceptions.ParseError('SPOT comment incorrectly formatted: '
-                                        'received {}'.format(comment))
+        if len(fields) < 4:
+            raise exceptions.ParseError('Spider comment incorrectly formatted:'
+                                        ' received {}'.format(comment))
 
         return {
             'id': fields[0],
-            'model': fields[1],
-            'status': fields[2]
+            'signal_strength': fields[1],
+            'spider_id': fields[2],
+            'gps_status': fields[3]
         }


Test patch:
diff --git a/tests/test_parser.py b/tests/test_parser.py
index bcd3247..f179511 100644
--- a/tests/test_parser.py
+++ b/tests/test_parser.py
@@ -442,14 +442,16 @@ class TestNaviter:
 
 class TestSpot:
     def test_parse_protocol_specific(self):
-        data = parser.Spot._parse_protocol_specific('id0-2860357 SPOT3 GOOD')
-        assert data['id'] == 'id0-2860357'
-        assert data['model'] == 'SPOT3'
-        assert data['status'] == 'GOOD'
+        data = parser.Spider._parse_protocol_specific('id300234010617040 +19dB'
+                                                      ' LWE 3D')
+        assert data['id'] == 'id300234010617040'
+        assert data['signal_strength'] == '+19dB'
+        assert data['spider_id'] == 'LWE'
+        assert data['gps_status'] == '3D'
 
     def test_parse_protocol_specific_fail(self):
         with pytest.raises(exceptions.ParseError):
-            parser.Spot._parse_protocol_specific('id0-2860357 SPOT3')
+            parser.Spider._parse_protocol_specific('id300234010617040 +19dB')
 
 
 class TestServerParser:
Repository: akolar/ogn-lib

Issue:
 Implement parser for Skylines messages (OGSKYL)

Comments:

Patch:
diff --git a/ogn_lib/parser.py b/ogn_lib/parser.py
index abbe761..4df961f 100644
--- a/ogn_lib/parser.py
+++ b/ogn_lib/parser.py
@@ -686,3 +686,31 @@ class Spider(Parser):
             'spider_id': fields[2],
             'gps_status': fields[3]
         }
+
+
+class Skylines(Parser):
+    """
+    Parser for Spider-formatted APRS messages.
+    """
+
+    __destto__ = ['OGSKYL', 'OGSKYL-1']
+
+    @staticmethod
+    def _parse_protocol_specific(comment):
+        """
+        Parses the comment string from Spider's APRS messages.
+        :param str comment: comment string
+        :return: parsed comment
+        :rtype: dict
+        """
+
+        fields = comment.split(' ', maxsplit=1)
+
+        if len(fields) < 2:
+            raise exceptions.ParseError('Skylines comment incorrectly formatted:'
+                                        ' received {}'.format(comment))
+
+        return {
+            'id': fields[0],
+            'vertical_speed': int(fields[1][:3]) * FEET_TO_METERS
+        }


Test patch:
diff --git a/tests/test_parser.py b/tests/test_parser.py
index 8fd96a5..fa7c7cd 100644
--- a/tests/test_parser.py
+++ b/tests/test_parser.py
@@ -466,6 +466,21 @@ class TestSpider:
             parser.Spider._parse_protocol_specific('id300234010617040 +19dB')
 
 
+class TestSkylines:
+    def test_parse_protocol_specific(self):
+        data = parser.Skylines._parse_protocol_specific('id2816 +000fpm')
+        assert data['id'] == 'id2816'
+        assert data['vertical_speed'] == 0
+
+        data = parser.Skylines._parse_protocol_specific('id2816 +159fpm')
+        assert data['id'] == 'id2816'
+        assert abs(data['vertical_speed'] - 4.57) < 0.1
+
+    def test_parse_protocol_specific_fail(self):
+        with pytest.raises(exceptions.ParseError):
+            parser.Skylines._parse_protocol_specific('id1111')
+
+
 class TestServerParser:
 
     def test_parse_message_beacon(self, mocker):
Repository: akolar/ogn-lib

Issue:
Implement parser for LiveTrack24 messages (OGLT24)

Comments:

Patch:
diff --git a/ogn_lib/parser.py b/ogn_lib/parser.py
index 4df961f..e50eb80 100644
--- a/ogn_lib/parser.py
+++ b/ogn_lib/parser.py
@@ -714,3 +714,32 @@ class Skylines(Parser):
             'id': fields[0],
             'vertical_speed': int(fields[1][:3]) * FEET_TO_METERS
         }
+
+
+class LiveTrack24(Parser):
+    """
+    Parser for LiveTrack24-formatted APRS messages.
+    """
+
+    __destto__ = ['OGLT24', 'OGLT24-1']
+
+    @staticmethod
+    def _parse_protocol_specific(comment):
+        """
+        Parses the comment string from LiveTrack24's APRS messages.
+        :param str comment: comment string
+        :return: parsed comment
+        :rtype: dict
+        """
+
+        fields = comment.split(' ', maxsplit=2)
+
+        if len(fields) < 3:
+            raise exceptions.ParseError('LT24 comment incorrectly formatted:'
+                                        ' received {}'.format(comment))
+
+        return {
+            'id': fields[0],
+            'vertical_speed': int(fields[1][:3]) * FEET_TO_METERS,
+            'source': fields[2]
+        }


Test patch:
diff --git a/tests/test_parser.py b/tests/test_parser.py
index fa7c7cd..fb5ec8d 100644
--- a/tests/test_parser.py
+++ b/tests/test_parser.py
@@ -481,6 +481,23 @@ class TestSkylines:
             parser.Skylines._parse_protocol_specific('id1111')
 
 
+class TestLT24:
+    def test_parse_protocol_specific(self):
+        data = parser.LiveTrack24._parse_protocol_specific('id25387 +000fpm GPS')
+        assert data['id'] == 'id25387'
+        assert data['vertical_speed'] == 0
+        assert data['source'] == 'GPS'
+
+        data = parser.LiveTrack24._parse_protocol_specific('id25387 +159fpm GPS')
+        assert data['id'] == 'id25387'
+        assert abs(data['vertical_speed'] - 4.57) < 0.1
+        assert data['source'] == 'GPS'
+
+    def test_parse_protocol_specific_fail(self):
+        with pytest.raises(exceptions.ParseError):
+            parser.LiveTrack24._parse_protocol_specific('id11111 GPS')
+
+
 class TestServerParser:
 
     def test_parse_message_beacon(self, mocker):
Repository: alanmcruickshank/sqlfluff

Issue:
PRS Error: Found unparsable segment @L001P008: 'a.b.*...'
SQL query to reproduce:
```sql
SELECT a.b.* FROM t
```

Comments:

Patch:
diff --git a/src/sqlfluff/dialects/dialect_ansi.py b/src/sqlfluff/dialects/dialect_ansi.py
index cea93c05..addb10f1 100644
--- a/src/sqlfluff/dialects/dialect_ansi.py
+++ b/src/sqlfluff/dialects/dialect_ansi.py
@@ -491,8 +491,15 @@ class SelectTargetElementSegment(BaseSegment):
     parse_grammar = OneOf(
         # *
         Ref('StarSegment'),
-        # blah.*
-        Sequence(Ref('SingleIdentifierGrammar'), Ref('DotSegment'), Ref('StarSegment'), code_only=False),
+        # blah.* + blah.blah.*
+        Sequence(
+            Ref('SingleIdentifierGrammar'), Ref('DotSegment'),
+            Sequence(
+                Ref('SingleIdentifierGrammar'), Ref('DotSegment'),
+                optional=True
+            ),
+            Ref('StarSegment'), code_only=False
+        ),
         Sequence(
             OneOf(
                 Ref('LiteralGrammar'),


Test patch:
diff --git a/test/dialects_ansi_test.py b/test/dialects_ansi_test.py
index 91f29dc5..149b5e88 100644
--- a/test/dialects_ansi_test.py
+++ b/test/dialects_ansi_test.py
@@ -81,7 +81,10 @@ def test__dialect__ansi__file_from_raw(raw, res, caplog):
          "CAST(num AS INT64)"),
         # Casting as datatype with arguments
         ("SelectTargetElementSegment",
-         "CAST(num AS numeric(8,4))")
+         "CAST(num AS numeric(8,4))"),
+        # Wildcard field selection
+        ("SelectTargetElementSegment", "a.*"),
+        ("SelectTargetElementSegment", "a.b.*")
     ]
 )
 def test__dialect__ansi_specific_segment_parses(segmentref, raw, caplog):
Repository: alanmcruickshank/sqlfluff

Issue:
Bogus capitalization warning involving SAFE_CAST, NULL, and AS
Input #1 :
```
SELECT
    SAFE_CAST(NULL AS STRING) AS age_label
FROM
    `table`
```

Input #2:
```
SELECT
    NULL AS age_label
FROM
    `table`
```

Either of these files results in a similar warning:
```
$ sqlfluff lint --exclude-rules L001 --dialect bigquery test2.sql
== [test2.sql] FAIL
L:   2 | P:  34 | L014 | Inconsistent capitalisation of unquoted identifiers.
```

I'm not sure if the `SAFE_CAST` is important or not, but am including it in case it's a different parsing pattern, etc.

@alanmcruickshank: I'd be happy to work on some tickets if you'd like to suggest any (this one or others)! February was busy for me, but I'm starting to have some discretionary time again.

Comments:

Patch:
diff --git a/src/sqlfluff/dialects/dialect_ansi.py b/src/sqlfluff/dialects/dialect_ansi.py
index 5834c196..4432b171 100644
--- a/src/sqlfluff/dialects/dialect_ansi.py
+++ b/src/sqlfluff/dialects/dialect_ansi.py
@@ -89,7 +89,7 @@ ansi_dialect.add(
     # also use a regex to explicitly exclude disallowed keywords.
     NakedIdentifierSegment=ReSegment.make(
         r"[A-Z0-9_]*[A-Z][A-Z0-9_]*", name='identifier', type='naked_identifier',
-        _anti_template=r"^(SELECT|JOIN|ON|USING|CROSS|INNER|LEFT|RIGHT|OUTER|INTERVAL|CASE|FULL)$"),
+        _anti_template=r"^(SELECT|JOIN|ON|USING|CROSS|INNER|LEFT|RIGHT|OUTER|INTERVAL|CASE|FULL|NULL)$"),
     FunctionNameSegment=ReSegment.make(r"[A-Z][A-Z0-9_]*", name='function_name', type='function_name'),
     # Maybe data types should be more restrictive?
     DatatypeIdentifierSegment=ReSegment.make(r"[A-Z][A-Z0-9_]*", name='data_type_identifier', type='data_type_identifier'),
@@ -206,7 +206,10 @@ ansi_dialect.add(
     LiteralGrammar=OneOf(
         Ref('QuotedLiteralSegment'), Ref('NumericLiteralSegment'),
         Ref('BooleanLiteralGrammar'), Ref('QualifiedNumericLiteralSegment'),
-        Ref('IntervalLiteralSegment')
+        Ref('IntervalLiteralSegment'),
+        # NB: Null is included in the literals, because it is a keyword which
+        # can otherwise be easily mistaken for an identifier.
+        Ref('NullKeywordSegment')
     ),
 )
 


Test patch:
diff --git a/test/rules_std_test.py b/test/rules_std_test.py
index 8acee7a1..c5ef40b0 100644
--- a/test/rules_std_test.py
+++ b/test/rules_std_test.py
@@ -84,6 +84,9 @@ def assert_rule_pass_in_sql(code, sql, configs=None):
     # Test that fixes are consistent
     ('L014', 'fail', 'SELECT a,   B', 'SELECT a,   b', None),
     ('L014', 'fail', 'SELECT B,   a', 'SELECT B,   A', None),
+    # Test that NULL is classed as a keyword and not an identifier
+    ('L014', 'pass', 'SELECT NULL,   a', None, None),
+    ('L010', 'fail', 'SELECT null,   a', 'SELECT NULL,   a', None),
     # Test that we don't fail * operators in brackets
     ('L006', 'pass', 'SELECT COUNT(*) FROM tbl\n', None, None),
     # Long lines (with config override)
Repository: alanmcruickshank/sqlfluff

Issue:
FileSegment error raised when using tabs
Hey,
I got the following error:

TypeError: In constructing <class 'sqlfluff.parser.segments_file.FileSegment'>, found an element of the segments tuple which isn't contigious with previous: <whitespace_RawSegment: ([4](1, 2, 2)) '\t'> > <newline_RawSegment: ([4](1, 2, 2)) '\n'>. End pos: [5](1, 2, 3). Prev String: '\t'

By using this input file 
/*
	
*/

Please note that in the comment is an invisible tab in the otherwise empty line.


Comments:

Patch:
diff --git a/src/sqlfluff/parser/lexer.py b/src/sqlfluff/parser/lexer.py
index 1eb4da37..ebbcb859 100644
--- a/src/sqlfluff/parser/lexer.py
+++ b/src/sqlfluff/parser/lexer.py
@@ -69,6 +69,10 @@ class SingletonMatcher:
                     )
                     idx = trim_span[1]
                     cont_pos_buff = cont_pos_buff.advance_by(matched[:trim_span[1]])
+                    # Have we consumed the whole string? This avoids us having
+                    # an empty string on the end.
+                    if idx == len(matched):
+                        break
                 # Is it at the end?
                 if trim_span[1] == len(matched):
                     seg_buff += (


Test patch:
diff --git a/test/parser_lexer_test.py b/test/parser_lexer_test.py
index 6b8ba2a9..8fbd5301 100644
--- a/test/parser_lexer_test.py
+++ b/test/parser_lexer_test.py
@@ -46,8 +46,9 @@ def assert_matches(instring, matcher, matchstring):
         ("abc -- comment \nblah", ['abc', ' ', "-- comment ", "\n", "blah"]),
         ("abc # comment \nblah", ['abc', ' ', "# comment ", "\n", "blah"]),
         # Note the more complicated parsing of block comments.
-        # This tests subdivision and trimming
+        # This tests subdivision and trimming (incl the empty case)
         ("abc /* comment \nblah*/", ['abc', ' ', "/* comment", " ", "\n", "blah*/"]),
+        ("abc /*\n\t\n*/", ['abc', ' ', "/*", "\n", "\t", "\n", "*/"]),
         # Test Singletons
         ("*-+bd/", ['*', '-', '+', 'bd', '/']),
         # Test Negatives and Minus
Repository: alanmcruickshank/sqlfluff

Issue:
Are functions not treated as keywords ?
Not an issue, more like a question. With
```
[sqlfluff:rules:L010]
capitalisation_policy = lower
```
using sqlfluff fix --rules L010 on
```sql
SELECT MAX(id) from table
```
becomes
```sql
select MAX(id) from table
```
Shouldn't `MAX` be also lower cased ?

Comments:

Patch:
diff --git a/src/sqlfluff/rules/std.py b/src/sqlfluff/rules/std.py
index a11d1cd1..135be2a4 100644
--- a/src/sqlfluff/rules/std.py
+++ b/src/sqlfluff/rules/std.py
@@ -2101,3 +2101,18 @@ class Rule_L029(BaseCrawler):
             # Actually lint
             if segment.raw.upper() in dialect.sets('unreserved_keywords'):
                 return LintResult(anchor=segment)
+
+
+@std_rule_set.register
+class Rule_L030(Rule_L010):
+    """Inconsistent capitalisation of function names.
+
+    The functionality for this rule is inherited from :obj:`Rule_L010`.
+
+    Args:
+        capitalisation_policy (:obj:`str`): The capitalisation policy to
+            enforce. One of 'consistent', 'upper', 'lower', 'capitalise'.
+
+    """
+
+    _target_elems = (('name', 'function_name'),)


Test patch:
diff --git a/test/rules_std_test.py b/test/rules_std_test.py
index b4c81976..f3b66520 100644
--- a/test/rules_std_test.py
+++ b/test/rules_std_test.py
@@ -174,6 +174,10 @@ def assert_rule_pass_in_sql(code, sql, configs=None):
     ('L029', 'fail', 'SELECT 1 as parameter', None, None),
     ('L029', 'pass', 'SELECT parameter', None, None),  # should pass on default config as not alias
     ('L029', 'fail', 'SELECT parameter', None, {'rules': {'L029': {'only_aliases': False}}}),
+    # Inconsistent capitalisation of functions
+    ('L030', 'fail', 'SELECT MAX(id), min(id) from table', 'SELECT MAX(id), MIN(id) from table', None),
+    ('L030', 'fail', 'SELECT MAX(id), min(id) from table', 'SELECT max(id), min(id) from table',
+     {'rules': {'L030': {'capitalisation_policy': 'lower'}}})
 ])
 def test__rules__std_string(rule, pass_fail, qry, fixed, configs):
     """Test that a rule passes/fails on a given string.
Repository: alanmcruickshank/sqlfluff

Issue:
Fix from stdin writes more than the fixed sql to stdout
When it was originally written, fixing from stdin printed the fixed sql to stdout and noting else. That way you could do things like 

```sh
echo ' select * from t' | sqlfluff fix - --rules L003 > fixed.sql
```
At least in 0.3.3, a lint result gets printed out, and the fixed string is printed as a python tuple:

```sh
bash-3.2$ sqlfluff version
0.3.3
bash-3.2$ echo ' select * from t' | sqlfluff fix - --rules L003
== [stdin] FAIL
L:   1 | P:   2 | L003 | First line has unexpected indent
('select * from t\n', True)
```



Comments:

Patch:
diff --git a/src/sqlfluff/cli/commands.py b/src/sqlfluff/cli/commands.py
index 88fa54a9..d16999b7 100644
--- a/src/sqlfluff/cli/commands.py
+++ b/src/sqlfluff/cli/commands.py
@@ -205,7 +205,7 @@ def fix(force, paths, **kwargs):
     be interpreted like passing the current working directory as a path argument.
     """
     c = get_config(**kwargs)
-    lnt = get_linter(c)
+    lnt = get_linter(c, silent=('-',) == paths)
     verbose = c.get('verbose')
 
     config_string = format_config(lnt, verbose=verbose)
@@ -221,7 +221,7 @@ def fix(force, paths, **kwargs):
     if ('-',) == paths:
         stdin = sys.stdin.read()
         result = lnt.lint_string_wrapped(stdin, fname='stdin', verbosity=verbose, fix=True)
-        stdout = result.paths[0].files[0].fix_string(verbosity=verbose)
+        stdout = result.paths[0].files[0].fix_string(verbosity=verbose)[0]
         click.echo(stdout, nl=False)
         sys.exit()
 


Test patch:
diff --git a/test/cli_commands_test.py b/test/cli_commands_test.py
index c9b50a61..15a9126b 100644
--- a/test/cli_commands_test.py
+++ b/test/cli_commands_test.py
@@ -199,17 +199,14 @@ def test__cli__command__fix(rule, fname):
 #         generic_roundtrip_test(test_file, rule, fix_exit_code=1, final_exit_code=65)
 
 
-def test__cli__command_fix_stdin(monkeypatch):
+@pytest.mark.parametrize('stdin,rules,stdout', [
+    ('select * from t', 'L003', 'select * from t'),  # no change
+    (' select * from t', 'L003', 'select * from t'),  # fix preceding whitespace
+])
+def test__cli__command_fix_stdin(stdin, rules, stdout):
     """Check stdin input for fix works."""
-    sql = 'select * from tbl'
-    expected = 'fixed sql!'
-
-    def _patched_fix(self, verbosity=0):
-        return expected
-
-    monkeypatch.setattr("sqlfluff.linter.LintedFile.fix_string", _patched_fix)
-    result = invoke_assert_code(args=[fix, ('-', '--rules', 'L001')], cli_input=sql)
-    assert result.output == expected
+    result = invoke_assert_code(args=[fix, ('-', '--rules', rules)], cli_input=stdin)
+    assert result.output == stdout
 
 
 @pytest.mark.parametrize('rule,fname,prompt,exit_code', [
Repository: albertyw/git-browse

Issue:
Support running with multiple fetch configs
gitconfig allows for multiple fetch configs which breaks configparser: https://stackoverflow.com/questions/15507264/can-i-specify-in-git-config-to-fetch-multiple-refspecs

Comments:

Patch:
diff --git a/git_browse/browse.py b/git_browse/browse.py
index 47ccaeb..451f605 100755
--- a/git_browse/browse.py
+++ b/git_browse/browse.py
@@ -369,7 +369,8 @@ def get_git_config() -> str:
 
 
 def get_git_url(git_config_file: str) -> str:
-    config = configparser.ConfigParser()
+    # strict is removed here because gitconfig allows for multiple "fetch" keys
+    config = configparser.ConfigParser(strict=False)
     config.read(git_config_file)
     try:
         git_url = config['remote "origin"']['url']


Test patch:
diff --git a/git_browse/tests/test.py b/git_browse/tests/test.py
index 9578999..cb3ba05 100644
--- a/git_browse/tests/test.py
+++ b/git_browse/tests/test.py
@@ -2,6 +2,7 @@ import os
 import re
 import shutil
 import sys
+import tempfile
 from typing import List, cast
 import unittest
 from unittest.mock import MagicMock, patch
@@ -248,14 +249,22 @@ class GetGitConfig(unittest.TestCase):
 
 class GetGitURL(unittest.TestCase):
     def setUp(self) -> None:
-        self.git_config_file = os.path.join(
+        git_config_file = os.path.join(
             BASE_DIRECTORY,
             '.git',
             'config'
         )
+        with open(git_config_file, 'rb') as handle:
+            configs = handle.read()
+        self.git_config_file = tempfile.NamedTemporaryFile()
+        self.git_config_file.write(configs)
+        self.git_config_file.seek(0)
+
+    def tearDown(self) -> None:
+        self.git_config_file.close()
 
     def test_url(self) -> None:
-        git_url = browse.get_git_url(self.git_config_file)
+        git_url = browse.get_git_url(self.git_config_file.name)
         expected = 'git@github.com:albertyw/git-browse'
         self.assertEqual(git_url.replace('.git', ''), expected)
 
@@ -263,6 +272,21 @@ class GetGitURL(unittest.TestCase):
         with self.assertRaises(RuntimeError):
             browse.get_git_url(BASE_DIRECTORY)
 
+    def test_multiple_fetch(self) -> None:
+        # For https://github.com/albertyw/git-browse/issues/48
+        config_contents = (
+            '[remote "origin"]\n'
+            '    fetch = refs/heads/my_name/*:refs/remotes/origin/my_name/*\n'
+            '    fetch = refs/heads/master:refs/remotes/origin/master\n'
+            '    url = git@github.com:albertyw/git-browse\n'
+        )
+        config_file = tempfile.NamedTemporaryFile()
+        config_file.write(config_contents.encode('utf-8'))
+        config_file.seek(0)
+        git_url = browse.get_git_url(config_file.name)
+        expected = 'git@github.com:albertyw/git-browse'
+        self.assertEqual(git_url.replace('.git', ''), expected)
+
 
 class ParseGitURL(unittest.TestCase):
     def setUp(self) -> None: