protected override bool ProcessLine(string line, out GitLogEntry result)
        {
            base.ProcessLine(line, out result);

            if (line == null)
            {
                ReturnGitLogEntry();
                return(false);
            }

            sb.AppendLine(line);

            if (phase == ProcessingPhase.Files && seenBodyEnd)
            {
                seenBodyEnd = false;
                var proc = new LineParser(line);
                if (proc.Matches(hashRegex))
                {
                    // there's no files on this commit, it's a new one!
                    ReturnGitLogEntry();
                }
            }

            switch (phase)
            {
            case ProcessingPhase.CommitHash:
                commitId = line;
                phase++;
                break;

            case ProcessingPhase.ParentHash:
                var parentHashes = line.Split(new[] { " " }, StringSplitOptions.RemoveEmptyEntries);

                if (parentHashes.Length > 1)
                {
                    mergeA = parentHashes[0];
                    mergeB = parentHashes[1];
                }

                phase++;
                break;

            case ProcessingPhase.AuthorName:
                authorName = line;
                phase++;
                break;

            case ProcessingPhase.AuthorEmail:
                authorEmail = line;
                phase++;
                break;

            case ProcessingPhase.AuthorDate:
                DateTimeOffset t;
                if (DateTimeOffset.TryParse(line, out t))
                {
                    time = t;
                }
                else
                {
                    Logger.Error("ERROR {0}", sb.ToString());
                    throw new FormatException("Invalid line");
                }
                phase++;
                break;

            case ProcessingPhase.CommitterName:
                committerName = line;
                phase++;
                break;

            case ProcessingPhase.CommitterEmail:
                committerEmail = line;
                phase++;
                break;

            case ProcessingPhase.CommitterDate:
                committerTime = DateTimeOffset.Parse(line);
                phase++;
                break;

            case ProcessingPhase.Summary:
            {
                var idx      = line.IndexOf("---GHUBODYEND---", StringComparison.Ordinal);
                var oneliner = idx >= 0;
                if (oneliner)
                {
                    line = line.Substring(0, idx);
                }

                summary = line;
                phase++;
                // there's no description so skip it
                if (oneliner)
                {
                    phase++;
                    seenBodyEnd = true;
                }
            }
            break;

            case ProcessingPhase.Description:
                var indexOf = line.IndexOf("---GHUBODYEND---", StringComparison.InvariantCulture);
                if (indexOf == -1)
                {
                    descriptionLines.Add(line);
                }
                else if (indexOf == 0)
                {
                    phase++;
                    seenBodyEnd = true;
                }
                else
                {
                    var substring = line.Substring(0, indexOf);
                    descriptionLines.Add(substring);
                    phase++;
                    seenBodyEnd = true;
                }
                break;

            case ProcessingPhase.Files:
                if (string.IsNullOrEmpty(line))
                {
                    ReturnGitLogEntry();
                    return(false);
                }

                if (line.IndexOf("---GHUBODYEND---", StringComparison.InvariantCulture) >= 0)
                {
                    seenBodyEnd = true;
                    return(false);
                }

                var proc = new LineParser(line);

                string        file         = null;
                GitFileStatus status       = GitFileStatus.None;
                string        originalPath = null;

                if (proc.IsAtEnd)
                {
                    // there's no files on this commit, it's a new one!
                    ReturnGitLogEntry();
                    return(false);
                }
                else
                {
                    status = GitStatusEntry.ParseStatusMarker(proc.ReadChar());
                }

                if (status == GitFileStatus.None)
                {
                    HandleUnexpected(line);
                    return(false);
                }

                proc.ReadUntilWhitespace();
                if (status == GitFileStatus.Copied || status == GitFileStatus.Renamed)
                {
                    var files =
                        proc.ReadToEnd().Trim()
                        .Split(new char[] { '\t' }, StringSplitOptions.RemoveEmptyEntries)
                        .Select(s => s.Trim())
                        .Select(s => s.Trim('"'))
                        .ToArray();

                    originalPath = files[0];
                    file         = files[1];
                }
                else
                {
                    file = proc.ReadToEnd().Trim().Trim('"');
                }

                changes.Add(gitObjectFactory.CreateGitStatusEntry(file, status, GitFileStatus.None, originalPath));

                break;

            default:
                HandleUnexpected(line);
                break;
            }
            return(false);
        }