Skip to content

Instantly share code, notes, and snippets.

@kbilsted
Created April 16, 2019 09:53
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save kbilsted/1fc05e68241cc9e87e2b446d740bcbae to your computer and use it in GitHub Desktop.
Save kbilsted/1fc05e68241cc9e87e2b446d740bcbae to your computer and use it in GitHub Desktop.
A simple program to parse git logs and produces change statistics grouped by month
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Globalization;
using System.IO;
using System.Linq;
namespace gitafterstat
{
/// <summary>
/// A simple program to parse git logs and produces change statistics grouped by month
/// To run e.g. use
/// <code>C:\src\MyProject> git log --pretty=format:nyny%cI -u --no-color -U0 --full-history --date-order --no-merges --reverse -p | gitafterstat.exe</code>
///
/// notes
/// * the cmd is much faster than running in powershell
/// * there is a delimiter 'nyny' in the above which is hard-coded into the parser
/// </summary>
class Program
{
static void Main(string[] args)
{
Dictionary<DateTime, List<Commit>> changes = null;
Console.WriteLine("");
Time("Reading input", () => { changes = GitParser.Parse(Console.OpenStandardInput()); });
Time("Filter", () =>
{
foreach (var commits in changes)
foreach (var commit in commits.Value)
commit.Changes = commit.Changes.Where(x => x.Fileextension == "cs" || x.Fileextension == "fs").ToList();
changes = changes.Where(x => x.Value.Any()).ToDictionary(x => x.Key, x => x.Value);
});
Console.WriteLine("");
Console.WriteLine("CSV output");
Console.WriteLine("----------");
Console.WriteLine("date,delta,total,commits");
var previousDelta = 0;
var g = changes.GroupBy(x => FirstInMonth(x.Key));
foreach (var month in g)
{
var sumDelta = month.Sum(x => x.Value.Sum(f => f.TotalDelta()));
previousDelta += sumDelta;
var commits = month.Sum(x => x.Value.Count);
Console.WriteLine($"{month.Key.ToShortDateString()}, {sumDelta}, {previousDelta}, {commits}");
}
}
static DateTime FirstInMonth(DateTime d) => new DateTime(d.Year, d.Month, 1);
static void Time(string title, Action a)
{
var s = Stopwatch.StartNew();
a();
Console.WriteLine($"{title}: {s.Elapsed.ToString()}");
}
}
class GitParser
{
const string Delimiter = "nyny";
const char FirstDelimiter = 'n';
public static Dictionary<DateTime, List<Commit>> Parse(Stream s)
{
var changes = new Dictionary<DateTime, List<Commit>>();
var top = Console.CursorTop;
using (var stream = new StreamReader(s))
{
Commit commit = null;
FileChange fileChange = null;
while (!stream.EndOfStream)
{
var line = stream.ReadLine();
if (line.Length == 0)
continue;
switch (line[0])
{
case '-':
if (!line.StartsWith("---", StringComparison.Ordinal))
fileChange.DeltaLines--;
break;
case '+':
if (!line.StartsWith("+++", StringComparison.Ordinal))
fileChange.DeltaLines++;
break;
case FirstDelimiter:
if (line.StartsWith(Delimiter, StringComparison.Ordinal))
{
var date = GetDate(line);
if (!changes.ContainsKey(date))
{
changes[date] = new List<Commit>();
Console.SetCursorPosition(0, top);
Console.Write(date);
}
commit = new Commit();
changes[date].Add(commit);
}
break;
case 'd':
const string diffGit = "diff --git ";
if (line.StartsWith(diffGit, StringComparison.Ordinal))
{
var posEnd = line.IndexOf(' ', diffGit.Length);
var posDot = line.LastIndexOf('.', posEnd - 1, 7) + 1;
var ext = line.Substring(posDot, posEnd - posDot);
fileChange = new FileChange();
fileChange.Fileextension = string.Intern(ext);
commit.Changes.Add(fileChange);
}
break;
}
}
}
return changes;
}
private static DateTime GetDate(string line)
{
var format = "yyyy-MM-dd";
var datepart = line.Substring(Delimiter.Length, format.Length);
var date = DateTime.ParseExact(datepart, format, CultureInfo.InvariantCulture);
return date;
}
}
class FileChange
{
public int DeltaLines;
public string Fileextension;
}
class Commit
{
public List<FileChange> Changes = new List<FileChange>();
public int TotalDelta() => Changes.Sum(x => x.DeltaLines);
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment