Home > Net >  C# fetch all text from git log command
C# fetch all text from git log command

Time:07-28

I am trying to obtain all the text from the git log command via C# Process.Start.

I need the full output for a tool that i am working on.

The problem I am facing is that UseShellExecute = false ommits some info from the result:

commit 77832ec07a2f96c2151c7a2f6ed0417e7e836eca (HEAD -> master)
Author: xxx yyy <xxx.yyy @zzz.com>
Date:   Thu Jul 21 12:28:26 2022  0300

    wip

commit f2cac40abf3d4b0cb2109376a635f9b8bd2ae56a
Author: xxx yyy <xxx.yyy @zzz.com>
Date:   Tue Jun 21 16:33:57 2022  0300

    wip

so from this output the (HEAD -> master) part gets ommited if i use UseShellExecute = false and if i use UseShellExecute = true i can't capture the output of the process.

I know it has to do something with the fact that those parts of the output get colored so i also tried running git log --no-color but for no avail.

Method declaration:

    private string ExecProcessWait(string path, string arguments, string workingDir)
    {
        var proc = new Process
        {
            StartInfo = new ProcessStartInfo
            {
                FileName = path,
                Arguments = arguments,
                UseShellExecute = false,
                RedirectStandardOutput = true,
                RedirectStandardError = true,
                CreateNoWindow = true,
                WorkingDirectory = workingDir
            },
            EnableRaisingEvents = true,
        };

        var output = string.Empty;

        proc.ErrorDataReceived  = (s, e) =>
        {
            if (e.Data != null)
            {
                output  = e.Data;
            }
        };

        proc.OutputDataReceived  = (s, e) =>
        {
            if (e.Data != null)
            {
                output  = $"{e.Data}{Environment.NewLine}";
            }
        };


        proc.Start();
        proc.BeginErrorReadLine();
        proc.BeginOutputReadLine();

        proc.WaitForExit();

        proc.Dispose();

        return output;
    }

Code sample:

var output = ExecProcessWait("git.exe", "log", @"Git_repo_dir");

@selvin suggested to try a C# git library so i followed this example (LibGit2Sharp) but sadly the same information is missing from it as well.

CodePudding user response:

git log is what Git calls a porcelain command, as opposed to what Git calls a plumbing command. Plumbing commands are meant to be used by other programs and therefore behave well when used by other programs: their output format is well-defined and they don't depend on user configurations or other settings. Porcelain commands are the opposite: their output is squishy and changes without warning, depends on user configurations, and generally cannot be relied-on.

Unfortunately, git log has no exact plumbing equivalent. This means that if you need one of the things that only git log can provide—and can't use something other than a Git command in the first place, e.g., can't use libgit2sharp for some reason—you're stuck with invoking git log. You'll just have to use it very carefully. First, though, you should exhaust other alternatives.

Now, as to this:

I know it has to do something with the fact that those parts of the output get colored

It's related, but not the same thing.

so I also tried running git log --no-color but for no avail.

You'll generally want --no-color and --no-pager to avoid depending on the user's color and pager preferences.

... the (HEAD -> master) part gets omitted

This part is what git log calls a decoration. Its presence or absence is controlled by the --decorate or --no-decorate option. If neither option is specified, it defaults to --decorate=auto (since Git 2.1 but accidentally undocumented until Git 2.9). The auto setting means on if a human appears to be reading the output, but off if a program appears to be reading the output. The user can configure, via global or local git config settings, log.decorate to short or full or no, which will change this from the default "detect whether a program is reading the output" mode.

This sort of thing is why using porcelain commands from other commands is generally a bad idea: there are too many things that can go wrong.

Note that if you want to find all refs that point to a particular commit hash ID, git for-each-ref is the plumbing command that does that (and only that). Of course, if you also want to see the commit message, you need git log. You'll need to carefully control the format (--format=... or --pretty=tformat:... for instance), as well as all those user settings (--decorate=, --no-pager, --no-color, and so on). The git log really needs a --porcelain option the way git status has one now. (--porcelain means yes, this is normally a porcelain command, turn it into a plumbing one for me and logically this should be --no-porcelain or --plumbing. Nobody ever said Git was consistent or logical.)

  • Related