5

Our organization utilizes VisualStudioOnline, GitHub and BitBucket for various repositories. I've been trying to figure out a way in c# to automate the pull of changes from various git repositories on a regular schedule. I've tried starting a process like this and then redirecting the standard input/output.

var p = new Process
{
    StartInfo = new ProcessStartInfo
    {
        FileName = @"C:\Program Files (x86)\Git\bin\sh.exe",
        RedirectStandardInput = true,
        UseShellExecute = false,
        RedirectStandardOutput = true,
        Arguments = "--login -i"
    }
};

p.Start();

using (var so = p.StandardOutput)
{
    using (var si = p.StandardInput)
    {
        if (si.BaseStream.CanWrite)
        {
            ...
        }
    }
}

Inside of the block, I'm able to execute git commands like this:

  • si.WriteLine("cd \"P:/code/testapp\""); which navigates the git shell to that directory
  • si.WriteLine("git rev-parse HEAD"); which will give me the latest hash of the repository at that location.

I can see the hash returned in the bash shell and can also read it in through the standard input like this var hash = so.ReadLine();

When I try to do si.WriteLint("git pull"); though, it asks for username and password, which I would expect, but that isn't done through the standard input/output. I can't us var prompt = so.ReadLine(); to get the prompt for username or password and I can't use si.WriteLine("username"); to input my password to the prompt.

I've tried a number of things to get this to work, but so far no luck. WARNING: messy code ahead, just tried to quickly prototype something, not create a masterpiece


Attempt 1: used standard input/output redirects as shown above to try to write/read the prompts for username/password.


Attempt 2: attempt to get the ssh-agent process that is being utilized by the git bash and write to it

si.WriteLine("ssh-agent --help");
var sshAgentInfo = string.Empty;
var tmp = a.ReadLine();
while (a.Peek() != -1)
{
    sshAgentInfo += tmp;
    tmp = a.ReadLine();
}

var begPos = sshAgentInfo.IndexOf("SSH_AGENT_PID=", StringComparison.Ordinal);
begPos = begPos + "SSH_AGENT_PID=".Length;
var endPos = sshAgentInfo.IndexOf(";", begPos, StringComparison.Ordinal);
var processId = int.Parse(sshAgentInfo.Substring(begPos, endPos - begPos));
var sshProcess = Process.GetProcessById(processId);
sshProcess.StartInfo.RedirectStandardInput = true;
sshProcess.StartInfo.RedirectStandardInput = true;
using (var si1 = sshProcess.StandardInput) { ... }

Attempt 3: Utilize credential git config credential.helper wincred This and four were very similar attempts. Again just trying to figure out how to set the password in either of these credential managers from the command line.


Attempt 4: Utilize Git-Credential-Manager-for-Windows I've tried looking through the documentation here and it seems as though there is an enhancement request to do something along these lines.

Both of these seem to have similar problems to attempt one. The git shell seems to be invoking another process which handles the standard input and output separate from the git shell. The difference and hope I have for these last two though is, Is there a way to call into those credential managers directly to set username/passwords for different urls? In the .git directory, the config file has the credentials setting to tell it which manager to use and it stores the username and email in plain text.

If I invoke a git pull through the shell on the machine and enter my credentials once through that shell it seems to store them, but is there a way to allow users to enter their credentials through a website and then call into the manager through the command line to securely store that information for future automated use?

I also came across this. I haven't had a chance to try it yet, but is this a viable option for doing something like this?

Any help would be greatly appreciated.

Community
  • 1
  • 1
peinearydevelopment
  • 11,042
  • 5
  • 48
  • 76
  • Is it possible to hard-code the credentials into the invocations of the `git` executable? I have a tool that uses `Process.Start` to execute `git`, and this is what I've done. My credentials are stored in a config file. – Dan Forbes Jan 12 '16 at 22:00
  • I'm not sure I know what you mean, an example would be helpful. The only thing I've found online is to do something like this `git clone http://username:password@host/project.git` but it says that the password will be stored in the config file on the box in plain text. Doesn't seem like a good option to me. – peinearydevelopment Jan 13 '16 at 02:53
  • What you describe is essentially what I am doing. For my use case, the fact that the password is stored in plaintext is not an issue. – Dan Forbes Jan 13 '16 at 16:00

0 Answers0