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.)