<SYSTEM_TASK:>
Solve the following problem using Python, implementing the functions described below, one line at a time
<END_TASK>
<USER_TASK:>
Description:
 def git_list_branches(repo_dir):
 """Return a list of git branches for the git repo in 'repo_dir'. .. code-block:: python [ {'branch': <branchname>, 'commit': <commit_hash>, 'message': <commit message>}, ] """

    command = ['git', 'branch', '--remotes', '--all',
               '--verbose', '--no-abbrev']
    output = execute_git_command(command, repo_dir=repo_dir).splitlines()
    # remove nullish lines
    lines = [l.strip() for l in output if l.strip()]
    # find the * current branch
    try:
        current_branch = [l for l in lines if l.startswith('* ')][0]
    except IndexError:
        current_branch = None
    item = None
    if current_branch:
        lines.remove(current_branch)
        current_branch = current_branch.replace('* ', '', 1)
        if re.match('\(.*detached.+\)', current_branch):
            branch, rest = current_branch.split(')', 1)
            branch = "%s)" % branch
            sha, msg = rest.split(None, 1)
            item = {'branch': branch, 'commit': sha, 'message': msg}
        else:
            lines.insert(0, current_branch)
    # <branch> <hash> <commit_message>
    # make a list of lists with clean elements of equal length
    breakout = [k.split(None, 2) for k in lines]
    # remove any strange hashless outliers
    breakout = [k for k in breakout if len(k[1]) == 40]
    headers = ['branch', 'commit', 'message']
    # use izip_longest so we fill in None if message was empty
    result = [dict(zip_longest(headers, vals))
              for vals in breakout]
    if item:
        result.append(item)
    return result