OSDN Git Service

merge original branch.
[tortoisegit/TortoiseGitJp.git] / src / Git / Git.cpp
index f100171..3353b54 100644 (file)
-#include "StdAfx.h"
-#include "Git.h"
-#include "atlconv.h"
-#include "GitRev.h"
-#include "registry.h"
-#include "GitConfig.h"
-#include <map>
-#include "UnicodeUtils.h"
-
-int CGit::m_LogEncode=CP_UTF8;
-
-static LPTSTR nextpath(LPCTSTR src, LPTSTR dst, UINT maxlen)
-{
-       LPCTSTR orgsrc;
-
-       while (*src == _T(';'))
-               src++;
-
-       orgsrc = src;
-
-       if (!--maxlen)
-               goto nullterm;
-
-       while (*src && *src != _T(';'))
-       {
-               if (*src != _T('"'))
-               {
-                       *dst++ = *src++;
-                       if (!--maxlen)
-                       {
-                               orgsrc = src;
-                               goto nullterm;
-                       }
-               }
-               else
-               {
-                       src++;
-                       while (*src && *src != _T('"'))
-                       {
-                               *dst++ = *src++;
-                               if (!--maxlen)
-                               {
-                                       orgsrc = src;
-                                       goto nullterm;
-                               }
-                       }
-
-                       if (*src)
-                               src++;
-               }
-       }
-
-       while (*src == _T(';'))
-               src++;
-
-nullterm:
-
-       *dst = 0;
-
-       return (orgsrc != src) ? (LPTSTR)src : NULL;
-}
-
-static inline BOOL FileExists(LPCTSTR lpszFileName)
-{
-       struct _stat st;
-       return _tstat(lpszFileName, &st) == 0;
-}
-
-static BOOL FindGitPath()
-{
-       size_t size;
-       _tgetenv_s(&size, NULL, 0, _T("PATH"));
-
-       if (!size)
-       {
-               return FALSE;
-       }
-
-       TCHAR *env = (TCHAR*)alloca(size * sizeof(TCHAR));
-       _tgetenv_s(&size, env, size, _T("PATH"));
-
-       TCHAR buf[_MAX_PATH];
-
-       // search in all paths defined in PATH
-       while ((env = nextpath(env, buf, _MAX_PATH-1)) && *buf)
-       {
-               TCHAR *pfin = buf + _tcslen(buf)-1;
-
-               // ensure trailing slash
-               if (*pfin != _T('/') && *pfin != _T('\\'))
-                       _tcscpy(++pfin, _T("\\"));
-
-               const int len = _tcslen(buf);
-
-               if ((len + 7) < _MAX_PATH)
-                       _tcscpy(pfin+1, _T("git.exe"));
-               else
-                       break;
-
-               if ( FileExists(buf) )
-               {
-                       // dir found
-                       pfin[1] = 0;
-                       CGit::ms_LastMsysGitDir = buf;
-                       return TRUE;
-               }
-       }
-
-       return FALSE;
-}
-
-
-#define MAX_DIRBUFFER 1000
-#define CALL_OUTPUT_READ_CHUNK_SIZE 1024
-
-CString CGit::ms_LastMsysGitDir;
-CGit g_Git;
-
-// contains system environment that should be used by child processes (RunAsync)
-// initialized by CheckMsysGitDir
-static LPTSTR l_processEnv = NULL;
-
-
-
-CGit::CGit(void)
-{
-       GetCurrentDirectory(MAX_DIRBUFFER,m_CurrentDir.GetBuffer(MAX_DIRBUFFER));
-       m_CurrentDir.ReleaseBuffer();
-
-       CheckMsysGitDir();
-}
-
-CGit::~CGit(void)
-{
-}
-
-static char g_Buffer[4096];
-
-int CGit::RunAsync(CString cmd,PROCESS_INFORMATION *piOut,HANDLE *hReadOut,CString *StdioFile)
-{
-       SECURITY_ATTRIBUTES sa;
-       HANDLE hRead, hWrite;
-       HANDLE hStdioFile = NULL;
-
-       sa.nLength = sizeof(SECURITY_ATTRIBUTES);
-       sa.lpSecurityDescriptor=NULL;
-       sa.bInheritHandle=TRUE;
-       if(!CreatePipe(&hRead,&hWrite,&sa,0))
-       {
-               return GIT_ERROR_OPEN_PIP;
-       }
-       
-       if(StdioFile)
-       {
-               hStdioFile=CreateFile(*StdioFile,GENERIC_WRITE,FILE_SHARE_READ   |   FILE_SHARE_WRITE,   
-                       &sa,CREATE_ALWAYS,FILE_ATTRIBUTE_NORMAL,NULL);  
-       }
-
-       STARTUPINFO si;
-       PROCESS_INFORMATION pi;
-       si.cb=sizeof(STARTUPINFO);
-       GetStartupInfo(&si);
-
-       si.hStdError=hWrite;
-       if(StdioFile)
-               si.hStdOutput=hStdioFile;
-       else
-               si.hStdOutput=hWrite;
-
-       si.wShowWindow=SW_HIDE;
-       si.dwFlags=STARTF_USESTDHANDLES|STARTF_USESHOWWINDOW;
-
-       LPTSTR pEnv = l_processEnv;
-       DWORD dwFlags = pEnv ? CREATE_UNICODE_ENVIRONMENT : 0;
-       
-       //DETACHED_PROCESS make ssh recognize that it has no console to launch askpass to input password. 
-       dwFlags |= DETACHED_PROCESS | CREATE_NEW_PROCESS_GROUP; 
-
-       memset(&this->m_CurrentGitPi,0,sizeof(PROCESS_INFORMATION));
-
-       if(!CreateProcess(NULL,(LPWSTR)cmd.GetString(), NULL,NULL,TRUE,dwFlags,pEnv,(LPWSTR)m_CurrentDir.GetString(),&si,&pi))
-       {
-               LPVOID lpMsgBuf;
-               FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER|FORMAT_MESSAGE_FROM_SYSTEM,
-                       NULL,GetLastError(),MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
-                       (LPTSTR)&lpMsgBuf,
-                       0,NULL);
-               return GIT_ERROR_CREATE_PROCESS;
-       }
-       
-       m_CurrentGitPi = pi;
-       
-       CloseHandle(hWrite);
-       if(piOut)
-               *piOut=pi;
-       if(hReadOut)
-               *hReadOut=hRead;
-       
-       return 0;
-
-}
-//Must use sperate function to convert ANSI str to union code string
-//Becuase A2W use stack as internal convert buffer. 
-void CGit::StringAppend(CString *str,BYTE *p,int code,int length)
-{
-     //USES_CONVERSION;
-        //str->Append(A2W_CP((LPCSTR)p,code));
-       if(str == NULL)
-               return ;
-
-       WCHAR * buf;
-
-       int len ;
-       if(length<0)
-               len= strlen((const char*)p);
-       else
-               len=length;
-       //if (len==0)
-       //      return ;
-       //buf = new WCHAR[len*4 + 1];
-       buf = str->GetBuffer(len*4+1+str->GetLength())+str->GetLength();
-       SecureZeroMemory(buf, (len*4 + 1)*sizeof(WCHAR));
-       MultiByteToWideChar(code, 0, (LPCSTR)p, len, buf, len*4);
-       str->ReleaseBuffer();
-       //str->Append(buf);
-       //delete buf;
-}      
-BOOL CGit::IsInitRepos()
-{
-       CString cmdout;
-       cmdout.Empty();
-       if(g_Git.Run(_T("git.exe rev-parse --revs-only HEAD"),&cmdout,CP_UTF8))
-       {
-       //      CMessageBox::Show(NULL,cmdout,_T("TortoiseGit"),MB_OK);
-               return TRUE;
-       }
-       if(cmdout.IsEmpty())
-               return TRUE;
-
-       return FALSE;
-}
-int CGit::Run(CGitCall* pcall)
-{
-       PROCESS_INFORMATION pi;
-       HANDLE hRead;
-       if(RunAsync(pcall->GetCmd(),&pi,&hRead))
-               return GIT_ERROR_CREATE_PROCESS;
-
-       DWORD readnumber;
-       BYTE data[CALL_OUTPUT_READ_CHUNK_SIZE];
-       bool bAborted=false;
-       while(ReadFile(hRead,data,CALL_OUTPUT_READ_CHUNK_SIZE,&readnumber,NULL))
-       {
-               //Todo: when OnOutputData() returns 'true', abort git-command. Send CTRL-C signal?
-               if(!bAborted)//For now, flush output when command aborted.
-                       if(pcall->OnOutputData(data,readnumber))
-                               bAborted=true;
-       }
-       if(!bAborted)
-               pcall->OnEnd();
-
-       
-       CloseHandle(pi.hThread);
-
-       WaitForSingleObject(pi.hProcess, INFINITE);
-       DWORD exitcode =0;
-
-       if(!GetExitCodeProcess(pi.hProcess,&exitcode))
-       {
-               return GIT_ERROR_GET_EXIT_CODE;
-       }
-
-       CloseHandle(pi.hProcess);
-
-       CloseHandle(hRead);
-       return exitcode;
-}
-class CGitCall_ByteVector : public CGitCall
-{
-public:
-       CGitCall_ByteVector(CString cmd,BYTE_VECTOR* pvector):CGitCall(cmd),m_pvector(pvector){}
-       virtual bool OnOutputData(const BYTE* data, size_t size)
-       {
-               size_t oldsize=m_pvector->size();
-               m_pvector->resize(m_pvector->size()+size);
-               memcpy(&*(m_pvector->begin()+oldsize),data,size);
-               return false;
-       }
-       BYTE_VECTOR* m_pvector;
-
-};
-int CGit::Run(CString cmd,BYTE_VECTOR *vector)
-{
-       CGitCall_ByteVector call(cmd,vector);
-       return Run(&call);
-}
-int CGit::Run(CString cmd, CString* output,int code)
-{
-       BYTE_VECTOR vector;
-       int ret;
-       ret=Run(cmd,&vector);
-
-       vector.push_back(0);
-       
-       StringAppend(output,&(vector[0]),code);
-       return ret;
-}
-
-CString CGit::GetUserName(void)
-{
-       return GetConfigValue(L"user.name");
-}
-CString CGit::GetUserEmail(void)
-{
-       return GetConfigValue(L"user.email");
-}
-
-CString CGit::GetConfigValue(CString name)
-{
-       CString configValue;
-       CString cmd;
-       cmd.Format(L"git.exe config %s", name);
-       Run(cmd,&configValue,CP_UTF8);
-       int start = 0;
-       return configValue.Tokenize(_T("\n"),start);
-}
-
-
-CString CGit::GetCurrentBranch(void)
-{
-       CString output;
-       //Run(_T("git.exe branch"),&branch);
-
-       int ret=g_Git.Run(_T("git.exe branch --no-color"),&output,CP_UTF8);
-       if(!ret)
-       {               
-               int pos=0;
-               CString one;
-               while( pos>=0 )
-               {
-                       //i++;
-                       one=output.Tokenize(_T("\n"),pos);
-                       //list.push_back(one.Right(one.GetLength()-2));
-                       if(one[0] == _T('*'))
-                               return one.Right(one.GetLength()-2);
-               }
-       }
-       return CString("");
-}
-
-CString CGit::GetSymbolicRef(const wchar_t* symbolicRefName, bool bStripRefsHeads)
-{
-       CString refName;
-       CString cmd;
-       cmd.Format(L"git symbolic-ref %s", symbolicRefName);
-       if(Run(cmd, &refName, CP_UTF8) != 0)
-               return CString();//Error
-       int iStart = 0;
-       refName = refName.Tokenize(L"\n", iStart);
-       if(bStripRefsHeads)
-               refName = StripRefName(refName);
-       return refName;
-}
-
-CString CGit::GetFullRefName(CString shortRefName)
-{
-       CString refName;
-       CString cmd;
-       cmd.Format(L"git rev-parse --symbolic-full-name %s", shortRefName);
-       if(Run(cmd, &refName, CP_UTF8) != 0)
-               return CString();//Error
-       int iStart = 0;
-       return refName.Tokenize(L"\n", iStart);
-}
-
-CString CGit::StripRefName(CString refName)
-{
-       if(wcsncmp(refName, L"refs/heads/", 11) == 0)
-               refName = refName.Mid(11);
-       else if(wcsncmp(refName, L"refs/", 5) == 0)
-               refName = refName.Mid(5);
-       return refName;
-}
-
-int CGit::GetCurrentBranchFromFile(const CString &sProjectRoot, CString &sBranchOut)
-{
-       // read current branch name like git-gui does, by parsing the .git/HEAD file directly
-
-       if ( sProjectRoot.IsEmpty() )
-               return -1;
-
-       CString sHeadFile = sProjectRoot + _T("\\") + g_GitAdminDir.GetAdminDirName() + _T("\\HEAD");
-
-       FILE *pFile;
-       _tfopen_s(&pFile, sHeadFile.GetString(), _T("r"));
-
-       if (!pFile)
-       {
-               return -1;
-       }
-
-       char s[256] = {0};
-    fgets(s, sizeof(s), pFile);
-
-       fclose(pFile);
-
-       const char *pfx = "ref: refs/heads/";
-       const int len = 16;//strlen(pfx)
-
-       if ( !strncmp(s, pfx, len) )
-       {
-               //# We're on a branch.  It might not exist.  But
-               //# HEAD looks good enough to be a branch.
-               sBranchOut = s + len;
-               sBranchOut.TrimRight(_T(" \r\n\t"));
-
-               if ( sBranchOut.IsEmpty() )
-                       return -1;
-       }
-       else
-       {
-               //# Assume this is a detached head.
-               sBranchOut = "HEAD";
-
-               return 1;
-       }
-
-       return 0;
-}
-
-int CGit::BuildOutputFormat(CString &format,bool IsFull)
-{
-       CString log;
-       log.Format(_T("#<%c>%%x00"),LOG_REV_ITEM_BEGIN);
-       format += log;
-       if(IsFull)
-       {
-               log.Format(_T("#<%c>%%an%%x00"),LOG_REV_AUTHOR_NAME);
-               format += log;
-               log.Format(_T("#<%c>%%ae%%x00"),LOG_REV_AUTHOR_EMAIL);
-               format += log;
-               log.Format(_T("#<%c>%%ai%%x00"),LOG_REV_AUTHOR_DATE);
-               format += log;
-               log.Format(_T("#<%c>%%cn%%x00"),LOG_REV_COMMIT_NAME);
-               format += log;
-               log.Format(_T("#<%c>%%ce%%x00"),LOG_REV_COMMIT_EMAIL);
-               format += log;
-               log.Format(_T("#<%c>%%ci%%x00"),LOG_REV_COMMIT_DATE);
-               format += log;
-               log.Format(_T("#<%c>%%b%%x00"),LOG_REV_COMMIT_BODY);
-               format += log;
-       }
-       
-       log.Format(_T("#<%c>%%m%%H%%x00"),LOG_REV_COMMIT_HASH);
-       format += log;
-       log.Format(_T("#<%c>%%P%%x00"),LOG_REV_COMMIT_PARENT);
-       format += log;
-       log.Format(_T("#<%c>%%s%%x00"),LOG_REV_COMMIT_SUBJECT);
-       format += log;
-
-       if(IsFull)
-       {
-               log.Format(_T("#<%c>%%x00"),LOG_REV_COMMIT_FILE);
-               format += log;
-       }
-       return 0;
-}
-
-int CGit::GetLog(BYTE_VECTOR& logOut, CString &hash,  CTGitPath *path ,int count,int mask,CString *from,CString *to)
-{
-       CGitCall_ByteVector gitCall(CString(),&logOut);
-       return GetLog(&gitCall,hash,path,count,mask,from,to);
-}
-
-//int CGit::GetLog(CGitCall* pgitCall, CString &hash,  CTGitPath *path ,int count,int mask)
-int CGit::GetLog(CGitCall* pgitCall, CString &hash, CTGitPath *path, int count, int mask,CString *from,CString *to)
-{
-
-       CString cmd;
-       CString log;
-       CString num;
-       CString since;
-
-       CString file;
-
-       if(path)
-               file.Format(_T(" -- \"%s\""),path->GetGitPathString());
-       
-       if(count>0)
-               num.Format(_T("-n%d"),count);
-
-       CString param;
-
-       if(mask& LOG_INFO_STAT )
-               param += _T(" --numstat ");
-       if(mask& LOG_INFO_FILESTATE)
-               param += _T(" --raw ");
-
-       if(mask& LOG_INFO_FULLHISTORY)
-               param += _T(" --full-history ");
-
-       if(mask& LOG_INFO_BOUNDARY)
-               param += _T(" --left-right --boundary ");
-
-       if(mask& CGit::LOG_INFO_ALL_BRANCH)
-               param += _T(" --all ");
-
-       if(mask& CGit::LOG_INFO_DETECT_COPYRENAME)
-               param += _T(" -C ");
-       
-       if(mask& CGit::LOG_INFO_DETECT_RENAME )
-               param += _T(" -M ");
-
-       if(mask& CGit::LOG_INFO_FIRST_PARENT )
-               param += _T(" --first-parent ");
-       
-       if(mask& CGit::LOG_INFO_NO_MERGE )
-               param += _T(" --no-merges ");
-
-       if(mask& CGit::LOG_INFO_FOLLOW)
-               param += _T(" --follow ");
-
-       if(mask& CGit::LOG_INFO_SHOW_MERGEDFILE)
-               param += _T(" -c ");
-
-       if(mask& CGit::LOG_INFO_FULL_DIFF)
-               param += _T(" --full-diff ");
-
-       if(from != NULL && to != NULL)
-       {
-               CString range;
-               range.Format(_T(" %s..%s "),*from,*to);
-               param += range;
-       }
-       param+=hash;
-
-       cmd.Format(_T("git.exe log %s -z --topo-order %s --parents --pretty=format:\""),
-                               num,param);
-
-       BuildOutputFormat(log,!(mask&CGit::LOG_INFO_ONLY_HASH));
-
-       cmd += log;
-       cmd += CString(_T("\"  "))+hash+file;
-
-       pgitCall->SetCmd(cmd);
-
-       return Run(pgitCall);
-//     return Run(cmd,&logOut);
-}
-
-#if 0
-int CGit::GetShortLog(CString &logOut,CTGitPath * path, int count)
-{
-       CString cmd;
-       CString log;
-       int n;
-       if(count<0)
-               n=100;
-       else
-               n=count;
-       cmd.Format(_T("git.exe log --left-right --boundary --topo-order -n%d --pretty=format:\""),n);
-       BuildOutputFormat(log,false);
-       cmd += log+_T("\"");
-       if (path)
-               cmd+= _T("  -- \"")+path->GetGitPathString()+_T("\"");
-       //cmd += CString(_T("\" HEAD~40..HEAD"));
-       return Run(cmd,&logOut);
-}
-#endif
-
-#define BUFSIZE 512
-void GetTempPath(CString &path)
-{
-       TCHAR lpPathBuffer[BUFSIZE];
-       DWORD dwRetVal;
-       DWORD dwBufSize=BUFSIZE;
-       dwRetVal = GetTempPath(dwBufSize,     // length of the buffer
-                           lpPathBuffer); // buffer for path 
-    if (dwRetVal > dwBufSize || (dwRetVal == 0))
-    {
-        path=_T("");
-    }
-       path.Format(_T("%s"),lpPathBuffer);
-}
-CString GetTempFile()
-{
-       TCHAR lpPathBuffer[BUFSIZE];
-       DWORD dwRetVal;
-    DWORD dwBufSize=BUFSIZE;
-       TCHAR szTempName[BUFSIZE];  
-       UINT uRetVal;
-
-       dwRetVal = GetTempPath(dwBufSize,     // length of the buffer
-                           lpPathBuffer); // buffer for path 
-    if (dwRetVal > dwBufSize || (dwRetVal == 0))
-    {
-        return _T("");
-    }
-        // Create a temporary file. 
-    uRetVal = GetTempFileName(lpPathBuffer, // directory for tmp files
-                              TEXT("Patch"),  // temp file name prefix 
-                              0,            // create unique name 
-                              szTempName);  // buffer for name 
-
-
-    if (uRetVal == 0)
-    {
-        return _T("");
-    }
-
-       return CString(szTempName);
-
-}
-
-int CGit::RunLogFile(CString cmd,CString &filename)
-{
-       STARTUPINFO si;
-       PROCESS_INFORMATION pi;
-       si.cb=sizeof(STARTUPINFO);
-       GetStartupInfo(&si);
-
-       SECURITY_ATTRIBUTES   psa={sizeof(psa),NULL,TRUE};;   
-       psa.bInheritHandle=TRUE;   
-    
-       HANDLE   houtfile=CreateFile(filename,GENERIC_WRITE,FILE_SHARE_READ   |   FILE_SHARE_WRITE,   
-                       &psa,CREATE_ALWAYS,FILE_ATTRIBUTE_NORMAL,NULL);   
-
-
-       si.wShowWindow=SW_HIDE;
-       si.dwFlags=STARTF_USESTDHANDLES|STARTF_USESHOWWINDOW;
-       si.hStdOutput   =   houtfile; 
-       
-       if(!CreateProcess(NULL,(LPWSTR)cmd.GetString(), NULL,NULL,TRUE,NULL,NULL,(LPWSTR)m_CurrentDir.GetString(),&si,&pi))
-       {
-               LPVOID lpMsgBuf;
-               FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER|FORMAT_MESSAGE_FROM_SYSTEM,
-                       NULL,GetLastError(),MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
-                       (LPTSTR)&lpMsgBuf,
-                       0,NULL);
-               return GIT_ERROR_CREATE_PROCESS;
-       }
-       
-       WaitForSingleObject(pi.hProcess,INFINITE);   
-       
-       CloseHandle(pi.hThread);
-       CloseHandle(pi.hProcess);
-       CloseHandle(houtfile);
-       return GIT_SUCCESS;
-//     return 0;
-}
-
-git_revnum_t CGit::GetHash(const CString &friendname)
-{
-       CString cmd;
-       CString out;
-       cmd.Format(_T("git.exe rev-parse %s" ),friendname);
-       Run(cmd,&out,CP_UTF8);
-//     int pos=out.ReverseFind(_T('\n'));
-       int pos=out.FindOneOf(_T("\r\n"));
-       if(pos>0)
-               return out.Left(pos);
-       return out;
-}
-
-int CGit::GetCommitDiffList(CString &rev1,CString &rev2,CTGitPathList &outputlist)
-{
-       CString cmd;
-       
-       if(rev1 == GIT_REV_ZERO || rev2 == GIT_REV_ZERO)
-       {
-               //rev1=+_T("");
-               if(rev1 == GIT_REV_ZERO)
-                       cmd.Format(_T("git.exe diff -r --raw -C -M --numstat -z %s"),rev2);
-               else
-                       cmd.Format(_T("git.exe diff -r -R --raw -C -M --numstat -z %s"),rev1);
-       }else
-       {
-               cmd.Format(_T("git.exe diff-tree -r --raw -C -M --numstat -z %s %s"),rev2,rev1);
-       }
-
-       BYTE_VECTOR out;
-       if(g_Git.Run(cmd,&out))
-               return -1;
-
-       outputlist.ParserFromLog(out);
-
-}
-
-int CGit::GetTagList(STRING_VECTOR &list)
-{
-       int ret;
-       CString cmd,output;
-       cmd=_T("git.exe tag -l");
-       int i=0;
-       ret=g_Git.Run(cmd,&output,CP_UTF8);
-       if(!ret)
-       {               
-               int pos=0;
-               CString one;
-               while( pos>=0 )
-               {
-                       i++;
-                       one=output.Tokenize(_T("\n"),pos);
-                       list.push_back(one);
-               }
-       }
-       return ret;
-}
-
-int CGit::GetBranchList(STRING_VECTOR &list,int *current,BRANCH_TYPE type)
-{
-       int ret;
-       CString cmd,output;
-       cmd=_T("git.exe branch --no-color");
-
-       if(type==(BRANCH_LOCAL|BRANCH_REMOTE))
-               cmd+=_T(" -a");
-       else if(type==BRANCH_REMOTE)
-               cmd+=_T(" -r");
-
-       int i=0;
-       ret=g_Git.Run(cmd,&output,CP_UTF8);
-       if(!ret)
-       {               
-               int pos=0;
-               CString one;
-               while( pos>=0 )
-               {
-                       one=output.Tokenize(_T("\n"),pos);
-                       one.Trim(L" \r\n\t");
-                       if(one.Find(L" -> ") >= 0 || one.IsEmpty())
-                               continue; // skip something like: refs/origin/HEAD -> refs/origin/master
-                       if(one[0] == _T('*'))
-                       {
-                               if(current)
-                                       *current=i;
-                               one = one.Mid(2);
-                       }
-                       list.push_back(one);
-                       i++;
-               }
-       }
-       return ret;
-}
-
-int CGit::GetRemoteList(STRING_VECTOR &list)
-{
-       int ret;
-       CString cmd,output;
-       cmd=_T("git.exe config  --get-regexp '^^remote[.].*[.]url'");
-       ret=g_Git.Run(cmd,&output,CP_UTF8);
-       if(!ret)
-       {
-               int pos=0;
-               CString one;
-               while( pos>=0 )
-               {
-                       one=output.Tokenize(_T("\n"),pos);
-                       int start=one.Find(_T("."),0);
-                       if(start>0)
-                       {
-                               CString url;
-                               url=one.Right(one.GetLength()-start-1);
-                               one=url;
-                               one=one.Left(one.Find(_T("."),0));
-                               list.push_back(one);
-                       }
-               }
-       }
-       return ret;
-}
-
-int CGit::GetRefList(STRING_VECTOR &list)
-{
-       int ret;
-       CString cmd,output;
-       cmd=_T("git show-ref -d");
-       ret=g_Git.Run(cmd,&output,CP_UTF8);
-       if(!ret)
-       {
-               int pos=0;
-               CString one;
-               while( pos>=0 )
-               {
-                       one=output.Tokenize(_T("\n"),pos);
-                       int start=one.Find(_T(" "),0);
-                       if(start>0)
-                       {
-                               CString name;
-                               name=one.Right(one.GetLength()-start-1);
-                               list.push_back(name);
-                       }
-               }
-       }
-       return ret;
-}
-int CGit::GetMapHashToFriendName(MAP_HASH_NAME &map)
-{
-       int ret;
-       CString cmd,output;
-       cmd=_T("git show-ref -d");
-       ret=g_Git.Run(cmd,&output,CP_UTF8);
-       if(!ret)
-       {
-               int pos=0;
-               CString one;
-               while( pos>=0 )
-               {
-                       one=output.Tokenize(_T("\n"),pos);
-                       int start=one.Find(_T(" "),0);
-                       if(start>0)
-                       {
-                               CString name;
-                               name=one.Right(one.GetLength()-start-1);
-
-                               CString hash;
-                               hash=one.Left(start);
-
-                               map[hash].push_back(name);
-                       }
-               }
-       }
-       return ret;
-}
-
-BOOL CGit::CheckMsysGitDir()
-{
-       static BOOL bInitialized = FALSE;
-
-       if (bInitialized)
-       {
-               return TRUE;
-       }
-
-       TCHAR *oldpath,*home;
-       size_t homesize,size,httpsize;
-
-       // set HOME if not set already
-       _tgetenv_s(&homesize, NULL, 0, _T("HOME"));
-       if (!homesize)
-       {
-               _tdupenv_s(&home,&size,_T("USERPROFILE")); 
-               _tputenv_s(_T("HOME"),home);
-               free(home);
-       }
-       CString str;
-
-#ifndef _TORTOISESHELL
-       //set http_proxy
-       _tgetenv_s(&httpsize, NULL, 0, _T("http_proxy"));
-       if (!httpsize)
-       {
-               CString regServeraddress_copy = CRegString(_T("Software\\TortoiseGit\\Servers\\global\\http-proxy-host"), _T(""));
-               CString regServerport_copy = CRegString(_T("Software\\TortoiseGit\\Servers\\global\\http-proxy-port"), _T(""));
-               CString regUsername_copy = CRegString(_T("Software\\TortoiseGit\\Servers\\global\\http-proxy-username"), _T(""));
-               CString regPassword_copy = CRegString(_T("Software\\TortoiseGit\\Servers\\global\\http-proxy-password"), _T(""));
-               CString regTimeout_copy = CRegString(_T("Software\\TortoiseGit\\Servers\\global\\http-proxy-timeout"), _T(""));
-               CString regExceptions_copy = CRegString(_T("Software\\TortoiseGit\\Servers\\global\\http-proxy-exceptions"), _T(""));
-
-               CString http_proxy;
-               if(!regServeraddress_copy.IsEmpty())
-               {
-                       if(regServeraddress_copy.Left(4) != _T("http"))
-                               http_proxy=_T("http://");
-
-                       if(!regUsername_copy.IsEmpty())
-                       {
-                               http_proxy += regUsername_copy;
-                               http_proxy += _T(":")+regPassword_copy;
-                               http_proxy += _T("@");
-                       }
-                       http_proxy+=regServeraddress_copy;
-                       if(!regServerport_copy.IsEmpty())
-                       {
-                               http_proxy +=_T(":")+regServerport_copy;
-                       }
-                       _tputenv_s(_T("http_proxy"),http_proxy);
-               }
-       }
-       //setup ssh client
-       CString sshclient=CRegString(_T("Software\\TortoiseGit\\SSH"));
-
-       if(!sshclient.IsEmpty())
-       {
-               _tputenv_s(_T("GIT_SSH"),sshclient);
-               
-               //Setup SVN_SSH
-               CString ssh=sshclient;
-               ssh.Replace(_T("/"),_T("\\"));
-               ssh.Replace(_T("\\"),_T("\\\\"));
-               ssh=CString(_T("\""))+ssh+_T('\"');
-               _tputenv_s(_T("SVN_SSH"),ssh);
-
-       }else
-       {
-               TCHAR sPlink[MAX_PATH];
-               GetModuleFileName(NULL, sPlink, _countof(sPlink));
-               LPTSTR ptr = _tcsrchr(sPlink, _T('\\'));
-               if (ptr) {
-                       _tcscpy(ptr + 1, _T("TortoisePlink.exe"));
-                       _tputenv_s(_T("GIT_SSH"), sPlink);
-
-                       //Setup SVN_SSH
-                       CString ssh=sPlink;
-                       ssh.Replace(_T("/"),_T("\\"));
-                       ssh.Replace(_T("\\"),_T("\\\\"));
-                       ssh=CString(_T("\""))+ssh+_T('\"');
-                       _tputenv_s(_T("SVN_SSH"),ssh);
-               }
-       }
-
-       {
-               TCHAR sAskPass[MAX_PATH];
-               GetModuleFileName(NULL, sAskPass, _countof(sAskPass));
-               LPTSTR ptr = _tcsrchr(sAskPass, _T('\\'));
-               if (ptr) 
-               {
-                       _tcscpy(ptr + 1, _T("SshAskPass.exe"));
-                       _tputenv_s(_T("DISPLAY"),_T(":9999"));
-                       _tputenv_s(_T("SSH_ASKPASS"),sAskPass);
-               }
-       }
-       // search PATH if git/bin directory is alredy present
-       if ( FindGitPath() )
-       {
-               bInitialized = TRUE;
-               return TRUE;
-       }
-
-       // add git/bin path to PATH
-
-       CRegString msysdir=CRegString(REG_MSYSGIT_PATH,_T(""),FALSE);
-       str=msysdir;
-       if(str.IsEmpty())
-       {
-               CRegString msysinstalldir=CRegString(REG_MSYSGIT_INSTALL,_T(""),FALSE,HKEY_LOCAL_MACHINE);
-               str=msysinstalldir;
-               if ( !str.IsEmpty() )
-               {
-                       str += (str[str.GetLength()-1] != '\\') ? "\\bin" : "bin";
-                       msysdir=str;
-                       msysdir.write();
-               }
-               else
-               {
-                       return false;
-               }
-       }
-#endif
-       //CGit::m_MsysGitPath=str;
-
-       //set path
-
-       _tdupenv_s(&oldpath,&size,_T("PATH")); 
-
-       CString path;
-       path.Format(_T("%s;%s"),oldpath,str);
-
-       _tputenv_s(_T("PATH"),path);
-
-       CString sOldPath = oldpath;
-       free(oldpath);
-
-
-    if( !FindGitPath() )
-       {
-               if(!homesize)
-               {
-                       _tputenv_s(_T("HOME"),_T(""));
-               }
-               return false;
-       }
-       else
-       {
-#ifdef _TORTOISESHELL
-               l_processEnv = GetEnvironmentStrings();
-               // updated environment is now duplicated for use in CreateProcess, restore original PATH for current process
-               _tputenv_s(_T("PATH"),sOldPath);
-               if(!homesize)
-               {
-                       _tputenv_s(_T("HOME"),_T(""));
-               }
-#endif
-
-               bInitialized = TRUE;
-               return true;
-       }
-}
-
-
-class CGitCall_EnumFiles : public CGitCall
-{
-public:
-       CGitCall_EnumFiles(const TCHAR *pszProjectPath, const TCHAR *pszSubPath, unsigned int nFlags, WGENUMFILECB *pEnumCb, void *pUserData)
-       :       m_pszProjectPath(pszProjectPath),
-               m_pszSubPath(pszSubPath),
-               m_nFlags(nFlags),
-               m_pEnumCb(pEnumCb),
-               m_pUserData(pUserData)
-       {
-       }
-
-       typedef std::map<CStringA,char> TStrCharMap;
-
-       const TCHAR *   m_pszProjectPath;
-       const TCHAR *   m_pszSubPath;
-       unsigned int    m_nFlags;
-       WGENUMFILECB *  m_pEnumCb;
-       void *                  m_pUserData;
-
-       BYTE_VECTOR             m_DataCollector;
-
-       virtual bool    OnOutputData(const BYTE* data, size_t size)
-       {
-               m_DataCollector.append(data,size);
-               while(true)
-               {
-                       // lines from igit.exe are 0 terminated
-                       int found=m_DataCollector.findData((const BYTE*)"",1);
-                       if(found<0)
-                               return false;
-                       OnSingleLine( (LPCSTR)&*m_DataCollector.begin() );
-                       m_DataCollector.erase(m_DataCollector.begin(), m_DataCollector.begin()+found+1);
-               }
-               return false;//Should never reach this
-       }
-       virtual void    OnEnd()
-       {
-       }
-
-       BYTE HexChar(char ch)
-       {
-               if (ch >= '0' && ch <= '9')
-                       return (UINT)(ch - '0');
-               else if (ch >= 'A' && ch <= 'F')
-                       return (UINT)(ch - 'A') + 10;
-               else if (ch >= 'a' && ch <= 'f')
-                       return (UINT)(ch - 'a') + 10;
-               else
-                       return 0;
-       }
-
-       bool OnSingleLine(LPCSTR line)
-       {
-               //Parse single line
-
-               wgFile_s fileStatus;
-
-               // file/dir type
-
-               fileStatus.nFlags = 0;
-               if (*line == 'D')
-                       fileStatus.nFlags |= WGFF_Directory;
-               else if (*line != 'F')
-                       // parse error
-                       return false;
-               line += 2;
-
-               // status
-
-               fileStatus.nStatus = WGFS_Unknown;
-               switch (*line)
-               {
-               case 'N': fileStatus.nStatus = WGFS_Normal; break;
-               case 'M': fileStatus.nStatus = WGFS_Modified; break;
-               case 'S': fileStatus.nStatus = WGFS_Staged; break;
-               case 'A': fileStatus.nStatus = WGFS_Added; break;
-               case 'C': fileStatus.nStatus = WGFS_Conflicted; break;
-               case 'D': fileStatus.nStatus = WGFS_Deleted; break;
-               case 'I': fileStatus.nStatus = WGFS_Ignored; break;
-               case 'U': fileStatus.nStatus = WGFS_Unversioned; break;
-               case 'E': fileStatus.nStatus = WGFS_Empty; break;
-               case '?': fileStatus.nStatus = WGFS_Unknown; break;
-               default:
-                       // parse error
-                       return false;
-               }
-               line += 2;
-
-               // file sha1
-
-               BYTE sha1[20];
-               fileStatus.sha1 = NULL;
-               if ( !(fileStatus.nFlags & WGFF_Directory) )
-               {
-                       for (int i=0; i<20; i++)
-                       {
-                               sha1[i]  = (HexChar(line[0])<<4)&0xF0;
-                               sha1[i] |= HexChar(line[1])&0xF;
-
-                               line += 2;
-                       }
-
-                       line++;
-               }
-
-               // filename
-               int len = strlen(line);
-               if (len && len < 2048)
-               {
-                       WCHAR *buf = (WCHAR*)alloca((len*4+2)*sizeof(WCHAR));
-                       *buf = 0;
-                       MultiByteToWideChar(CP_ACP, 0, line, len+1, buf, len*4+1);
-                       fileStatus.sFileName = buf;
-
-                       if (*buf && (*m_pEnumCb)(&fileStatus,m_pUserData))
-                               return false;
-               }
-
-               return true;
-       }
-};
-
-BOOL CGit::EnumFiles(const TCHAR *pszProjectPath, const TCHAR *pszSubPath, unsigned int nFlags, WGENUMFILECB *pEnumCb, void *pUserData)
-{
-       if(!pszProjectPath || *pszProjectPath=='\0')
-               return FALSE;
-
-       CGitCall_EnumFiles W_GitCall(pszProjectPath,pszSubPath,nFlags,pEnumCb,pUserData);
-       CString cmd;
-
-/*     char W_szToDir[MAX_PATH];
-       strncpy(W_szToDir,pszProjectPath,sizeof(W_szToDir)-1);
-       if(W_szToDir[strlen(W_szToDir)-1]!='\\')
-               strncat(W_szToDir,"\\",sizeof(W_szToDir)-1);
-
-       SetCurrentDirectoryA(W_szToDir);
-       GetCurrentDirectoryA(sizeof(W_szToDir)-1,W_szToDir);
-*/
-       SetCurrentDir(pszProjectPath);
-
-       CString sMode;
-       if (nFlags)
-       {
-               if (nFlags & WGEFF_NoRecurse) sMode += _T("r");
-               if (nFlags & WGEFF_FullPath) sMode += _T("f");
-               if (nFlags & WGEFF_DirStatusDelta) sMode += _T("d");
-               if (nFlags & WGEFF_DirStatusAll) sMode += _T("D");
-               if (nFlags & WGEFF_EmptyAsNormal) sMode += _T("e");
-               if (nFlags & WGEFF_SingleFile) sMode += _T("s");
-       }
-       else
-       {
-               sMode = _T("-");
-       }
-
-       // NOTE: there seems to be some issue with msys based app receiving backslash on commandline, at least
-       // if followed by " like for example 'igit "C:\"', the commandline igit receives is 'igit.exe C:" status' with
-       // the 'C:" status' part as a single arg, Maybe it uses unix style processing. In order to avoid this just
-       // use forward slashes for supplied project and sub paths
-
-       CString sProjectPath = pszProjectPath;
-       sProjectPath.Replace(_T('\\'), _T('/'));
-
-       if (pszSubPath)
-       {
-               CString sSubPath = pszSubPath;
-               sSubPath.Replace(_T('\\'), _T('/'));
-
-               cmd.Format(_T("igit.exe \"%s\" status %s \"%s\""), sProjectPath, sMode, sSubPath);
-       }
-       else
-       {
-               cmd.Format(_T("igit.exe \"%s\" status %s"), sProjectPath, sMode);
-       }
-
-       //OutputDebugStringA("---");OutputDebugStringW(cmd);OutputDebugStringA("\r\n");
-
-       W_GitCall.SetCmd(cmd);
-       // NOTE: should igit get added as a part of msysgit then use below line instead of the above one
-       //W_GitCall.SetCmd(CGit::ms_LastMsysGitDir + cmd);
-
-       if ( Run(&W_GitCall) )
-               return FALSE;
-
-       return TRUE;
-}
-
-BOOL CGit::CheckCleanWorkTree()
-{
-       CString out;
-       CString cmd;
-       cmd=_T("git.exe rev-parse --verify HEAD");
-
-       if(g_Git.Run(cmd,&out,CP_UTF8))
-               return FALSE;
-
-       cmd=_T("git.exe update-index --ignore-submodules --refresh");
-       if(g_Git.Run(cmd,&out,CP_UTF8))
-               return FALSE;
-
-       cmd=_T("git.exe diff-files --quiet --ignore-submodules");
-       if(g_Git.Run(cmd,&out,CP_UTF8))
-               return FALSE;
-
-       cmd=_T("git diff-index --cached --quiet HEAD --ignore-submodules");
-       if(g_Git.Run(cmd,&out,CP_UTF8))
-               return FALSE;
-
-       return TRUE;
-}
-int CGit::Revert(CTGitPathList &list,bool keep)
-{
-       int ret;
-       for(int i=0;i<list.GetCount();i++)
-       {       
-               ret = Revert((CTGitPath&)list[i],keep);
-               if(ret)
-                       return ret;
-       }
-       return 0;
-}
-int CGit::Revert(CTGitPath &path,bool keep)
-{
-       CString cmd, out;
-       if(path.m_Action & CTGitPath::LOGACTIONS_ADDED)
-       {       //To init git repository, there are not HEAD, so we can use git reset command
-               cmd.Format(_T("git.exe rm --cached -- \"%s\""),path.GetGitPathString());
-
-               if(g_Git.Run(cmd,&out,CP_ACP))
-                       return -1;
-       }
-       else if(path.m_Action & CTGitPath::LOGACTIONS_REPLACED )
-       {
-               cmd.Format(_T("git.exe mv -- \"%s\" \"%s\""),path.GetGitPathString(),path.GetGitOldPathString());
-               if(g_Git.Run(cmd,&out,CP_ACP))
-                       return -1;
-               
-               cmd.Format(_T("git.exe checkout HEAD -f -- \"%s\""),path.GetGitOldPathString());
-               if(g_Git.Run(cmd,&out,CP_ACP))
-                       return -1;
-       }
-       else
-       {
-               cmd.Format(_T("git.exe checkout HEAD -f -- \"%s\""),path.GetGitPathString());
-               if(g_Git.Run(cmd,&out,CP_ACP))
-                       return -1;
-       }
-       return 0;
-}
-
-int CGit::ListConflictFile(CTGitPathList &list,CTGitPath *path)
-{
-       BYTE_VECTOR vector;
-
-       CString cmd;
-       if(path)
-               cmd.Format(_T("git.exe ls-files -u -t -z -- \"%s\""),path->GetGitPathString());
-       else
-               cmd=_T("git.exe ls-files -u -t -z");
-
-       if(g_Git.Run(cmd,&vector))
-       {
-               return -1;
-       }
-
-       list.ParserFromLsFile(vector);
-
-       return 0;
-}
-
-bool CGit::IsFastForward(CString &from, CString &to)
-{
-       CString base,hash;
-       CString cmd;
-       cmd.Format(_T("git.exe merge-base %s %s"), to,from);
-
-       if(g_Git.Run(cmd,&base,CP_ACP))
-       {
-               //CMessageBox::Show(NULL,base,_T("TortoiseGit"),MB_OK|MB_ICONERROR);
-               return false;
-       }
-       base=base.Left(40);
-
-       hash=g_Git.GetHash(from);
-
-       hash=hash.Left(40);
-       
-       return hash == base;
-}
-
-unsigned int CGit::Hash2int(CString &hash)
-{
-       int ret=0;
-       for(int i=0;i<8;i++)
-       {
-               ret =ret <<4;
-               if(hash[i]>=_T('a'))
-                       ret |= (hash[i]-_T('a')+10)&0xFF;
-               else if(hash[i]>=_T('A'))
-                       ret |= (hash[i]-_T('A')+10)&0xFF;
-               else
-                       ret |= (hash[i]-_T('0'))&0xFF;          
-               
-       }
-       return ret;
-}
\ No newline at end of file
+#include "StdAfx.h"\r
+#include "Git.h"\r
+#include "atlconv.h"\r
+#include "GitRev.h"\r
+#include "registry.h"\r
+#include "GitConfig.h"\r
+#include <map>\r
+#include "UnicodeUtils.h"\r
+#include "gitdll.h"\r
+\r
+int CGit::m_LogEncode=CP_UTF8;\r
+\r
+\r
+static LPTSTR nextpath(LPCTSTR src, LPTSTR dst, UINT maxlen)\r
+{\r
+       LPCTSTR orgsrc;\r
+\r
+       while (*src == _T(';'))\r
+               src++;\r
+\r
+       orgsrc = src;\r
+\r
+       if (!--maxlen)\r
+               goto nullterm;\r
+\r
+       while (*src && *src != _T(';'))\r
+       {\r
+               if (*src != _T('"'))\r
+               {\r
+                       *dst++ = *src++;\r
+                       if (!--maxlen)\r
+                       {\r
+                               orgsrc = src;\r
+                               goto nullterm;\r
+                       }\r
+               }\r
+               else\r
+               {\r
+                       src++;\r
+                       while (*src && *src != _T('"'))\r
+                       {\r
+                               *dst++ = *src++;\r
+                               if (!--maxlen)\r
+                               {\r
+                                       orgsrc = src;\r
+                                       goto nullterm;\r
+                               }\r
+                       }\r
+\r
+                       if (*src)\r
+                               src++;\r
+               }\r
+       }\r
+\r
+       while (*src == _T(';'))\r
+               src++;\r
+\r
+nullterm:\r
+\r
+       *dst = 0;\r
+\r
+       return (orgsrc != src) ? (LPTSTR)src : NULL;\r
+}\r
+\r
+static inline BOOL FileExists(LPCTSTR lpszFileName)\r
+{\r
+       struct _stat st;\r
+       return _tstat(lpszFileName, &st) == 0;\r
+}\r
+\r
+static BOOL FindGitPath()\r
+{\r
+       size_t size;\r
+       _tgetenv_s(&size, NULL, 0, _T("PATH"));\r
+\r
+       if (!size)\r
+       {\r
+               return FALSE;\r
+       }\r
+\r
+       TCHAR *env = (TCHAR*)alloca(size * sizeof(TCHAR));\r
+       _tgetenv_s(&size, env, size, _T("PATH"));\r
+\r
+       TCHAR buf[_MAX_PATH];\r
+\r
+       // search in all paths defined in PATH\r
+       while ((env = nextpath(env, buf, _MAX_PATH-1)) && *buf)\r
+       {\r
+               TCHAR *pfin = buf + _tcslen(buf)-1;\r
+\r
+               // ensure trailing slash\r
+               if (*pfin != _T('/') && *pfin != _T('\\'))\r
+                       _tcscpy(++pfin, _T("\\"));\r
+\r
+               const int len = _tcslen(buf);\r
+\r
+               if ((len + 7) < _MAX_PATH)\r
+                       _tcscpy(pfin+1, _T("git.exe"));\r
+               else\r
+                       break;\r
+\r
+               if ( FileExists(buf) )\r
+               {\r
+                       // dir found\r
+                       pfin[1] = 0;\r
+                       CGit::ms_LastMsysGitDir = buf;\r
+                       return TRUE;\r
+               }\r
+       }\r
+\r
+       return FALSE;\r
+}\r
+\r
+\r
+#define MAX_DIRBUFFER 1000\r
+#define CALL_OUTPUT_READ_CHUNK_SIZE 1024\r
+\r
+CString CGit::ms_LastMsysGitDir;\r
+CGit g_Git;\r
+\r
+// contains system environment that should be used by child processes (RunAsync)\r
+// initialized by CheckMsysGitDir\r
+static LPTSTR l_processEnv = NULL;\r
+\r
+\r
+\r
+CGit::CGit(void)\r
+{\r
+       GetCurrentDirectory(MAX_DIRBUFFER,m_CurrentDir.GetBuffer(MAX_DIRBUFFER));\r
+       m_CurrentDir.ReleaseBuffer();\r
+       m_IsGitDllInited = false;\r
+       m_GitDiff=0;\r
+       CheckMsysGitDir();\r
+}\r
+\r
+CGit::~CGit(void)\r
+{\r
+       if(this->m_GitDiff)\r
+       {\r
+               git_close_diff(m_GitDiff);\r
+               m_GitDiff=0;\r
+       }\r
+}\r
+\r
+static char g_Buffer[4096];\r
+\r
+int CGit::RunAsync(CString cmd,PROCESS_INFORMATION *piOut,HANDLE *hReadOut,CString *StdioFile)\r
+{\r
+       SECURITY_ATTRIBUTES sa;\r
+       HANDLE hRead, hWrite;\r
+       HANDLE hStdioFile = NULL;\r
+\r
+       sa.nLength = sizeof(SECURITY_ATTRIBUTES);\r
+       sa.lpSecurityDescriptor=NULL;\r
+       sa.bInheritHandle=TRUE;\r
+       if(!CreatePipe(&hRead,&hWrite,&sa,0))\r
+       {\r
+               return GIT_ERROR_OPEN_PIP;\r
+       }\r
+       \r
+       if(StdioFile)\r
+       {\r
+               hStdioFile=CreateFile(*StdioFile,GENERIC_WRITE,FILE_SHARE_READ   |   FILE_SHARE_WRITE,   \r
+                       &sa,CREATE_ALWAYS,FILE_ATTRIBUTE_NORMAL,NULL);  \r
+       }\r
+\r
+       STARTUPINFO si;\r
+       PROCESS_INFORMATION pi;\r
+       si.cb=sizeof(STARTUPINFO);\r
+       GetStartupInfo(&si);\r
+\r
+       si.hStdError=hWrite;\r
+       if(StdioFile)\r
+               si.hStdOutput=hStdioFile;\r
+       else\r
+               si.hStdOutput=hWrite;\r
+\r
+       si.wShowWindow=SW_HIDE;\r
+       si.dwFlags=STARTF_USESTDHANDLES|STARTF_USESHOWWINDOW;\r
+\r
+       LPTSTR pEnv = l_processEnv;\r
+       DWORD dwFlags = pEnv ? CREATE_UNICODE_ENVIRONMENT : 0;\r
+       \r
+       //DETACHED_PROCESS make ssh recognize that it has no console to launch askpass to input password. \r
+       dwFlags |= DETACHED_PROCESS | CREATE_NEW_PROCESS_GROUP; \r
+\r
+       memset(&this->m_CurrentGitPi,0,sizeof(PROCESS_INFORMATION));\r
+\r
+       if(!CreateProcess(NULL,(LPWSTR)cmd.GetString(), NULL,NULL,TRUE,dwFlags,pEnv,(LPWSTR)m_CurrentDir.GetString(),&si,&pi))\r
+       {\r
+               LPVOID lpMsgBuf;\r
+               FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER|FORMAT_MESSAGE_FROM_SYSTEM,\r
+                       NULL,GetLastError(),MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),\r
+                       (LPTSTR)&lpMsgBuf,\r
+                       0,NULL);\r
+               return GIT_ERROR_CREATE_PROCESS;\r
+       }\r
+       \r
+       m_CurrentGitPi = pi;\r
+       \r
+       CloseHandle(hWrite);\r
+       if(piOut)\r
+               *piOut=pi;\r
+       if(hReadOut)\r
+               *hReadOut=hRead;\r
+       \r
+       return 0;\r
+\r
+}\r
+//Must use sperate function to convert ANSI str to union code string\r
+//Becuase A2W use stack as internal convert buffer. \r
+void CGit::StringAppend(CString *str,BYTE *p,int code,int length)\r
+{\r
+     //USES_CONVERSION;\r
+        //str->Append(A2W_CP((LPCSTR)p,code));\r
+       if(str == NULL)\r
+               return ;\r
+\r
+       WCHAR * buf;\r
+\r
+       int len ;\r
+       if(length<0)\r
+               len= strlen((const char*)p);\r
+       else\r
+               len=length;\r
+       //if (len==0)\r
+       //      return ;\r
+       //buf = new WCHAR[len*4 + 1];\r
+       buf = str->GetBuffer(len*4+1+str->GetLength())+str->GetLength();\r
+       SecureZeroMemory(buf, (len*4 + 1)*sizeof(WCHAR));\r
+       MultiByteToWideChar(code, 0, (LPCSTR)p, len, buf, len*4);\r
+       str->ReleaseBuffer();\r
+       //str->Append(buf);\r
+       //delete buf;\r
+}      \r
+BOOL CGit::IsInitRepos()\r
+{\r
+       CString cmdout;\r
+       cmdout.Empty();\r
+       if(g_Git.Run(_T("git.exe rev-parse --revs-only HEAD"),&cmdout,CP_UTF8))\r
+       {\r
+       //      CMessageBox::Show(NULL,cmdout,_T("TortoiseGit"),MB_OK);\r
+               return TRUE;\r
+       }\r
+       if(cmdout.IsEmpty())\r
+               return TRUE;\r
+\r
+       return FALSE;\r
+}\r
+int CGit::Run(CGitCall* pcall)\r
+{\r
+       PROCESS_INFORMATION pi;\r
+       HANDLE hRead;\r
+       if(RunAsync(pcall->GetCmd(),&pi,&hRead))\r
+               return GIT_ERROR_CREATE_PROCESS;\r
+\r
+       DWORD readnumber;\r
+       BYTE data[CALL_OUTPUT_READ_CHUNK_SIZE];\r
+       bool bAborted=false;\r
+       while(ReadFile(hRead,data,CALL_OUTPUT_READ_CHUNK_SIZE,&readnumber,NULL))\r
+       {\r
+               //Todo: when OnOutputData() returns 'true', abort git-command. Send CTRL-C signal?\r
+               if(!bAborted)//For now, flush output when command aborted.\r
+                       if(pcall->OnOutputData(data,readnumber))\r
+                               bAborted=true;\r
+       }\r
+       if(!bAborted)\r
+               pcall->OnEnd();\r
+\r
+       \r
+       CloseHandle(pi.hThread);\r
+\r
+       WaitForSingleObject(pi.hProcess, INFINITE);\r
+       DWORD exitcode =0;\r
+\r
+       if(!GetExitCodeProcess(pi.hProcess,&exitcode))\r
+       {\r
+               return GIT_ERROR_GET_EXIT_CODE;\r
+       }\r
+\r
+       CloseHandle(pi.hProcess);\r
+\r
+       CloseHandle(hRead);\r
+       return exitcode;\r
+}\r
+class CGitCall_ByteVector : public CGitCall\r
+{\r
+public:\r
+       CGitCall_ByteVector(CString cmd,BYTE_VECTOR* pvector):CGitCall(cmd),m_pvector(pvector){}\r
+       virtual bool OnOutputData(const BYTE* data, size_t size)\r
+       {\r
+               size_t oldsize=m_pvector->size();\r
+               m_pvector->resize(m_pvector->size()+size);\r
+               memcpy(&*(m_pvector->begin()+oldsize),data,size);\r
+               return false;\r
+       }\r
+       BYTE_VECTOR* m_pvector;\r
+\r
+};\r
+int CGit::Run(CString cmd,BYTE_VECTOR *vector)\r
+{\r
+       CGitCall_ByteVector call(cmd,vector);\r
+       return Run(&call);\r
+}\r
+int CGit::Run(CString cmd, CString* output,int code)\r
+{\r
+       BYTE_VECTOR vector;\r
+       int ret;\r
+       ret=Run(cmd,&vector);\r
+\r
+       vector.push_back(0);\r
+       \r
+       StringAppend(output,&(vector[0]),code);\r
+       return ret;\r
+}\r
+\r
+CString CGit::GetUserName(void)\r
+{\r
+       return GetConfigValue(L"user.name");\r
+}\r
+CString CGit::GetUserEmail(void)\r
+{\r
+       return GetConfigValue(L"user.email");\r
+}\r
+\r
+CString CGit::GetConfigValue(CString name)\r
+{\r
+       CString configValue;\r
+       CString cmd;\r
+       cmd.Format(L"git.exe config %s", name);\r
+       Run(cmd,&configValue,CP_UTF8);\r
+       int start = 0;\r
+       return configValue.Tokenize(_T("\n"),start);\r
+}\r
+\r
+\r
+CString CGit::GetCurrentBranch(void)\r
+{\r
+       CString output;\r
+       //Run(_T("git.exe branch"),&branch);\r
+\r
+       int ret=g_Git.Run(_T("git.exe branch --no-color"),&output,CP_UTF8);\r
+       if(!ret)\r
+       {               \r
+               int pos=0;\r
+               CString one;\r
+               while( pos>=0 )\r
+               {\r
+                       //i++;\r
+                       one=output.Tokenize(_T("\n"),pos);\r
+                       //list.push_back(one.Right(one.GetLength()-2));\r
+                       if(one[0] == _T('*'))\r
+                               return one.Right(one.GetLength()-2);\r
+               }\r
+       }\r
+       return CString("");\r
+}\r
+\r
+CString CGit::GetSymbolicRef(const wchar_t* symbolicRefName, bool bStripRefsHeads)\r
+{\r
+       CString refName;\r
+       CString cmd;\r
+       cmd.Format(L"git symbolic-ref %s", symbolicRefName);\r
+       if(Run(cmd, &refName, CP_UTF8) != 0)\r
+               return CString();//Error\r
+       int iStart = 0;\r
+       refName = refName.Tokenize(L"\n", iStart);\r
+       if(bStripRefsHeads)\r
+               refName = StripRefName(refName);\r
+       return refName;\r
+}\r
+\r
+CString CGit::GetFullRefName(CString shortRefName)\r
+{\r
+       CString refName;\r
+       CString cmd;\r
+       cmd.Format(L"git rev-parse --symbolic-full-name %s", shortRefName);\r
+       if(Run(cmd, &refName, CP_UTF8) != 0)\r
+               return CString();//Error\r
+       int iStart = 0;\r
+       return refName.Tokenize(L"\n", iStart);\r
+}\r
+\r
+CString CGit::StripRefName(CString refName)\r
+{\r
+       if(wcsncmp(refName, L"refs/heads/", 11) == 0)\r
+               refName = refName.Mid(11);\r
+       else if(wcsncmp(refName, L"refs/", 5) == 0)\r
+               refName = refName.Mid(5);\r
+       return refName;\r
+}\r
+\r
+int CGit::GetCurrentBranchFromFile(const CString &sProjectRoot, CString &sBranchOut)\r
+{\r
+       // read current branch name like git-gui does, by parsing the .git/HEAD file directly\r
+\r
+       if ( sProjectRoot.IsEmpty() )\r
+               return -1;\r
+\r
+       CString sHeadFile = sProjectRoot + _T("\\") + g_GitAdminDir.GetAdminDirName() + _T("\\HEAD");\r
+\r
+       FILE *pFile;\r
+       _tfopen_s(&pFile, sHeadFile.GetString(), _T("r"));\r
+\r
+       if (!pFile)\r
+       {\r
+               return -1;\r
+       }\r
+\r
+       char s[256] = {0};\r
+    fgets(s, sizeof(s), pFile);\r
+\r
+       fclose(pFile);\r
+\r
+       const char *pfx = "ref: refs/heads/";\r
+       const int len = 16;//strlen(pfx)\r
+\r
+       if ( !strncmp(s, pfx, len) )\r
+       {\r
+               //# We're on a branch.  It might not exist.  But\r
+               //# HEAD looks good enough to be a branch.\r
+               sBranchOut = s + len;\r
+               sBranchOut.TrimRight(_T(" \r\n\t"));\r
+\r
+               if ( sBranchOut.IsEmpty() )\r
+                       return -1;\r
+       }\r
+       else\r
+       {\r
+               //# Assume this is a detached head.\r
+               sBranchOut = "HEAD";\r
+\r
+               return 1;\r
+       }\r
+\r
+       return 0;\r
+}\r
+\r
+int CGit::BuildOutputFormat(CString &format,bool IsFull)\r
+{\r
+       CString log;\r
+       log.Format(_T("#<%c>%%x00"),LOG_REV_ITEM_BEGIN);\r
+       format += log;\r
+       if(IsFull)\r
+       {\r
+               log.Format(_T("#<%c>%%an%%x00"),LOG_REV_AUTHOR_NAME);\r
+               format += log;\r
+               log.Format(_T("#<%c>%%ae%%x00"),LOG_REV_AUTHOR_EMAIL);\r
+               format += log;\r
+               log.Format(_T("#<%c>%%ai%%x00"),LOG_REV_AUTHOR_DATE);\r
+               format += log;\r
+               log.Format(_T("#<%c>%%cn%%x00"),LOG_REV_COMMIT_NAME);\r
+               format += log;\r
+               log.Format(_T("#<%c>%%ce%%x00"),LOG_REV_COMMIT_EMAIL);\r
+               format += log;\r
+               log.Format(_T("#<%c>%%ci%%x00"),LOG_REV_COMMIT_DATE);\r
+               format += log;\r
+               log.Format(_T("#<%c>%%b%%x00"),LOG_REV_COMMIT_BODY);\r
+               format += log;\r
+       }\r
+       \r
+       log.Format(_T("#<%c>%%m%%H%%x00"),LOG_REV_COMMIT_HASH);\r
+       format += log;\r
+       log.Format(_T("#<%c>%%P%%x00"),LOG_REV_COMMIT_PARENT);\r
+       format += log;\r
+       log.Format(_T("#<%c>%%s%%x00"),LOG_REV_COMMIT_SUBJECT);\r
+       format += log;\r
+\r
+       if(IsFull)\r
+       {\r
+               log.Format(_T("#<%c>%%x00"),LOG_REV_COMMIT_FILE);\r
+               format += log;\r
+       }\r
+       return 0;\r
+}\r
+\r
+int CGit::GetLog(BYTE_VECTOR& logOut, CString &hash,  CTGitPath *path ,int count,int mask,CString *from,CString *to)\r
+{\r
+       CGitCall_ByteVector gitCall(CString(),&logOut);\r
+       return GetLog(&gitCall,hash,path,count,mask,from,to);\r
+}\r
+\r
+CString CGit::GetLogCmd( CString &hash, CTGitPath *path, int count, int mask,CString *from,CString *to,bool paramonly)\r
+{\r
+       CString cmd;\r
+       CString log;\r
+       CString num;\r
+       CString since;\r
+\r
+       CString file;\r
+\r
+       if(path)\r
+               file.Format(_T(" -- \"%s\""),path->GetGitPathString());\r
+       \r
+       if(count>0)\r
+               num.Format(_T("-n%d"),count);\r
+\r
+       CString param;\r
+\r
+       if(mask& LOG_INFO_STAT )\r
+               param += _T(" --numstat ");\r
+       if(mask& LOG_INFO_FILESTATE)\r
+               param += _T(" --raw ");\r
+\r
+       if(mask& LOG_INFO_FULLHISTORY)\r
+               param += _T(" --full-history ");\r
+\r
+       if(mask& LOG_INFO_BOUNDARY)\r
+               param += _T(" --left-right --boundary ");\r
+\r
+       if(mask& CGit::LOG_INFO_ALL_BRANCH)\r
+               param += _T(" --all ");\r
+\r
+       if(mask& CGit::LOG_INFO_DETECT_COPYRENAME)\r
+               param += _T(" -C ");\r
+       \r
+       if(mask& CGit::LOG_INFO_DETECT_RENAME )\r
+               param += _T(" -M ");\r
+\r
+       if(mask& CGit::LOG_INFO_FIRST_PARENT )\r
+               param += _T(" --first-parent ");\r
+       \r
+       if(mask& CGit::LOG_INFO_NO_MERGE )\r
+               param += _T(" --no-merges ");\r
+\r
+       if(mask& CGit::LOG_INFO_FOLLOW)\r
+               param += _T(" --follow ");\r
+\r
+       if(mask& CGit::LOG_INFO_SHOW_MERGEDFILE)\r
+               param += _T(" -c ");\r
+\r
+       if(mask& CGit::LOG_INFO_FULL_DIFF)\r
+               param += _T(" --full-diff ");\r
+\r
+       if(from != NULL && to != NULL)\r
+       {\r
+               CString range;\r
+               range.Format(_T(" %s..%s "),*from,*to);\r
+               param += range;\r
+       }\r
+       param+=hash;\r
+\r
+       if(paramonly)\r
+               cmd.Format(_T("%s -z --topo-order %s --parents "),\r
+                               num,param);\r
+       else\r
+               cmd.Format(_T("git.exe log %s -z --topo-order %s --parents --pretty=format:\""),\r
+                               num,param);\r
+\r
+       BuildOutputFormat(log,!(mask&CGit::LOG_INFO_ONLY_HASH));\r
+\r
+       if(paramonly)\r
+       {\r
+               cmd += hash+file;\r
+       }else\r
+       {\r
+               cmd += log;\r
+               cmd += CString(_T("\"  "))+hash+file;\r
+       }\r
+\r
+       return cmd;\r
+}\r
+//int CGit::GetLog(CGitCall* pgitCall, CString &hash,  CTGitPath *path ,int count,int mask)\r
+int CGit::GetLog(CGitCall* pgitCall, CString &hash, CTGitPath *path, int count, int mask,CString *from,CString *to)\r
+{\r
+       pgitCall->SetCmd( GetLogCmd(hash,path,count,mask,from,to) );\r
+\r
+       return Run(pgitCall);\r
+//     return Run(cmd,&logOut);\r
+}\r
+\r
+#define BUFSIZE 512\r
+void GetTempPath(CString &path)\r
+{\r
+       TCHAR lpPathBuffer[BUFSIZE];\r
+       DWORD dwRetVal;\r
+       DWORD dwBufSize=BUFSIZE;\r
+       dwRetVal = GetTempPath(dwBufSize,     // length of the buffer\r
+                           lpPathBuffer); // buffer for path \r
+    if (dwRetVal > dwBufSize || (dwRetVal == 0))\r
+    {\r
+        path=_T("");\r
+    }\r
+       path.Format(_T("%s"),lpPathBuffer);\r
+}\r
+CString GetTempFile()\r
+{\r
+       TCHAR lpPathBuffer[BUFSIZE];\r
+       DWORD dwRetVal;\r
+    DWORD dwBufSize=BUFSIZE;\r
+       TCHAR szTempName[BUFSIZE];  \r
+       UINT uRetVal;\r
+\r
+       dwRetVal = GetTempPath(dwBufSize,     // length of the buffer\r
+                           lpPathBuffer); // buffer for path \r
+    if (dwRetVal > dwBufSize || (dwRetVal == 0))\r
+    {\r
+        return _T("");\r
+    }\r
+        // Create a temporary file. \r
+    uRetVal = GetTempFileName(lpPathBuffer, // directory for tmp files\r
+                              TEXT("Patch"),  // temp file name prefix \r
+                              0,            // create unique name \r
+                              szTempName);  // buffer for name \r
+\r
+\r
+    if (uRetVal == 0)\r
+    {\r
+        return _T("");\r
+    }\r
+\r
+       return CString(szTempName);\r
+\r
+}\r
+\r
+int CGit::RunLogFile(CString cmd,CString &filename)\r
+{\r
+       STARTUPINFO si;\r
+       PROCESS_INFORMATION pi;\r
+       si.cb=sizeof(STARTUPINFO);\r
+       GetStartupInfo(&si);\r
+\r
+       SECURITY_ATTRIBUTES   psa={sizeof(psa),NULL,TRUE};;   \r
+       psa.bInheritHandle=TRUE;   \r
+    \r
+       HANDLE   houtfile=CreateFile(filename,GENERIC_WRITE,FILE_SHARE_READ   |   FILE_SHARE_WRITE,   \r
+                       &psa,CREATE_ALWAYS,FILE_ATTRIBUTE_NORMAL,NULL);   \r
+\r
+\r
+       si.wShowWindow=SW_HIDE;\r
+       si.dwFlags=STARTF_USESTDHANDLES|STARTF_USESHOWWINDOW;\r
+       si.hStdOutput   =   houtfile; \r
+       \r
+       if(!CreateProcess(NULL,(LPWSTR)cmd.GetString(), NULL,NULL,TRUE,NULL,NULL,(LPWSTR)m_CurrentDir.GetString(),&si,&pi))\r
+       {\r
+               LPVOID lpMsgBuf;\r
+               FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER|FORMAT_MESSAGE_FROM_SYSTEM,\r
+                       NULL,GetLastError(),MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),\r
+                       (LPTSTR)&lpMsgBuf,\r
+                       0,NULL);\r
+               return GIT_ERROR_CREATE_PROCESS;\r
+       }\r
+       \r
+       WaitForSingleObject(pi.hProcess,INFINITE);   \r
+       \r
+       CloseHandle(pi.hThread);\r
+       CloseHandle(pi.hProcess);\r
+       CloseHandle(houtfile);\r
+       return GIT_SUCCESS;\r
+//     return 0;\r
+}\r
+\r
+git_revnum_t CGit::GetHash(const CString &friendname)\r
+{\r
+       CString cmd;\r
+       CString out;\r
+       cmd.Format(_T("git.exe rev-parse %s" ),friendname);\r
+       Run(cmd,&out,CP_UTF8);\r
+//     int pos=out.ReverseFind(_T('\n'));\r
+       int pos=out.FindOneOf(_T("\r\n"));\r
+       if(pos>0)\r
+               return out.Left(pos);\r
+       return out;\r
+}\r
+\r
+int CGit::GetCommitDiffList(CString &rev1,CString &rev2,CTGitPathList &outputlist)\r
+{\r
+       CString cmd;\r
+       \r
+       if(rev1 == GIT_REV_ZERO || rev2 == GIT_REV_ZERO)\r
+       {\r
+               //rev1=+_T("");\r
+               if(rev1 == GIT_REV_ZERO)\r
+                       cmd.Format(_T("git.exe diff -r --raw -C -M --numstat -z %s"),rev2);\r
+               else\r
+                       cmd.Format(_T("git.exe diff -r -R --raw -C -M --numstat -z %s"),rev1);\r
+       }else\r
+       {\r
+               cmd.Format(_T("git.exe diff-tree -r --raw -C -M --numstat -z %s %s"),rev2,rev1);\r
+       }\r
+\r
+       BYTE_VECTOR out;\r
+       if(g_Git.Run(cmd,&out))\r
+               return -1;\r
+\r
+       outputlist.ParserFromLog(out);\r
+\r
+}\r
+\r
+int CGit::GetTagList(STRING_VECTOR &list)\r
+{\r
+       int ret;\r
+       CString cmd,output;\r
+       cmd=_T("git.exe tag -l");\r
+       int i=0;\r
+       ret=g_Git.Run(cmd,&output,CP_UTF8);\r
+       if(!ret)\r
+       {               \r
+               int pos=0;\r
+               CString one;\r
+               while( pos>=0 )\r
+               {\r
+                       i++;\r
+                       one=output.Tokenize(_T("\n"),pos);\r
+                       list.push_back(one);\r
+               }\r
+       }\r
+       return ret;\r
+}\r
+\r
+int CGit::GetBranchList(STRING_VECTOR &list,int *current,BRANCH_TYPE type)\r
+{\r
+       int ret;\r
+       CString cmd,output;\r
+       cmd=_T("git.exe branch --no-color");\r
+\r
+       if(type==(BRANCH_LOCAL|BRANCH_REMOTE))\r
+               cmd+=_T(" -a");\r
+       else if(type==BRANCH_REMOTE)\r
+               cmd+=_T(" -r");\r
+\r
+       int i=0;\r
+       ret=g_Git.Run(cmd,&output,CP_UTF8);\r
+       if(!ret)\r
+       {               \r
+               int pos=0;\r
+               CString one;\r
+               while( pos>=0 )\r
+               {\r
+                       one=output.Tokenize(_T("\n"),pos);\r
+                       one.Trim(L" \r\n\t");\r
+                       if(one.Find(L" -> ") >= 0 || one.IsEmpty())\r
+                               continue; // skip something like: refs/origin/HEAD -> refs/origin/master\r
+                       if(one[0] == _T('*'))\r
+                       {\r
+                               if(current)\r
+                                       *current=i;\r
+                               one = one.Mid(2);\r
+                       }\r
+                       list.push_back(one);\r
+                       i++;\r
+               }\r
+       }\r
+       return ret;\r
+}\r
+\r
+int CGit::GetRemoteList(STRING_VECTOR &list)\r
+{\r
+       int ret;\r
+       CString cmd,output;\r
+       cmd=_T("git.exe config  --get-regexp \"^^remote[.].*[.]url\"");\r
+       ret=g_Git.Run(cmd,&output,CP_UTF8);\r
+       if(!ret)\r
+       {\r
+               int pos=0;\r
+               CString one;\r
+               while( pos>=0 )\r
+               {\r
+                       one=output.Tokenize(_T("\n"),pos);\r
+                       int start=one.Find(_T("."),0);\r
+                       if(start>0)\r
+                       {\r
+                               CString url;\r
+                               url=one.Right(one.GetLength()-start-1);\r
+                               one=url;\r
+                               one=one.Left(one.Find(_T("."),0));\r
+                               list.push_back(one);\r
+                       }\r
+               }\r
+       }\r
+       return ret;\r
+}\r
+\r
+int CGit::GetRefList(STRING_VECTOR &list)\r
+{\r
+       int ret;\r
+       CString cmd,output;\r
+       cmd=_T("git show-ref -d");\r
+       ret=g_Git.Run(cmd,&output,CP_UTF8);\r
+       if(!ret)\r
+       {\r
+               int pos=0;\r
+               CString one;\r
+               while( pos>=0 )\r
+               {\r
+                       one=output.Tokenize(_T("\n"),pos);\r
+                       int start=one.Find(_T(" "),0);\r
+                       if(start>0)\r
+                       {\r
+                               CString name;\r
+                               name=one.Right(one.GetLength()-start-1);\r
+                               list.push_back(name);\r
+                       }\r
+               }\r
+       }\r
+       return ret;\r
+}\r
+int CGit::GetMapHashToFriendName(MAP_HASH_NAME &map)\r
+{\r
+       int ret;\r
+       CString cmd,output;\r
+       cmd=_T("git show-ref -d");\r
+       ret=g_Git.Run(cmd,&output,CP_UTF8);\r
+       if(!ret)\r
+       {\r
+               int pos=0;\r
+               CString one;\r
+               while( pos>=0 )\r
+               {\r
+                       one=output.Tokenize(_T("\n"),pos);\r
+                       int start=one.Find(_T(" "),0);\r
+                       if(start>0)\r
+                       {\r
+                               CString name;\r
+                               name=one.Right(one.GetLength()-start-1);\r
+\r
+                               CString hash;\r
+                               hash=one.Left(start);\r
+\r
+                               map[hash].push_back(name);\r
+                       }\r
+               }\r
+       }\r
+       return ret;\r
+}\r
+\r
+BOOL CGit::CheckMsysGitDir()\r
+{\r
+       static BOOL bInitialized = FALSE;\r
+\r
+       if (bInitialized)\r
+       {\r
+               return TRUE;\r
+       }\r
+\r
+       TCHAR *oldpath,*home;\r
+       size_t homesize,size,httpsize;\r
+\r
+       // set HOME if not set already\r
+       _tgetenv_s(&homesize, NULL, 0, _T("HOME"));\r
+       if (!homesize)\r
+       {\r
+               _tdupenv_s(&home,&size,_T("USERPROFILE")); \r
+               _tputenv_s(_T("HOME"),home);\r
+               free(home);\r
+       }\r
+       CString str;\r
+\r
+#ifndef _TORTOISESHELL\r
+       //set http_proxy\r
+       _tgetenv_s(&httpsize, NULL, 0, _T("http_proxy"));\r
+       if (!httpsize)\r
+       {\r
+               CString regServeraddress_copy = CRegString(_T("Software\\TortoiseGit\\Servers\\global\\http-proxy-host"), _T(""));\r
+               CString regServerport_copy = CRegString(_T("Software\\TortoiseGit\\Servers\\global\\http-proxy-port"), _T(""));\r
+               CString regUsername_copy = CRegString(_T("Software\\TortoiseGit\\Servers\\global\\http-proxy-username"), _T(""));\r
+               CString regPassword_copy = CRegString(_T("Software\\TortoiseGit\\Servers\\global\\http-proxy-password"), _T(""));\r
+               CString regTimeout_copy = CRegString(_T("Software\\TortoiseGit\\Servers\\global\\http-proxy-timeout"), _T(""));\r
+               CString regExceptions_copy = CRegString(_T("Software\\TortoiseGit\\Servers\\global\\http-proxy-exceptions"), _T(""));\r
+\r
+               CString http_proxy;\r
+               if(!regServeraddress_copy.IsEmpty())\r
+               {\r
+                       if(regServeraddress_copy.Left(4) != _T("http"))\r
+                               http_proxy=_T("http://");\r
+\r
+                       if(!regUsername_copy.IsEmpty())\r
+                       {\r
+                               http_proxy += regUsername_copy;\r
+                               http_proxy += _T(":")+regPassword_copy;\r
+                               http_proxy += _T("@");\r
+                       }\r
+                       http_proxy+=regServeraddress_copy;\r
+                       if(!regServerport_copy.IsEmpty())\r
+                       {\r
+                               http_proxy +=_T(":")+regServerport_copy;\r
+                       }\r
+                       _tputenv_s(_T("http_proxy"),http_proxy);\r
+               }\r
+       }\r
+       //setup ssh client\r
+       CString sshclient=CRegString(_T("Software\\TortoiseGit\\SSH"));\r
+\r
+       if(!sshclient.IsEmpty())\r
+       {\r
+               _tputenv_s(_T("GIT_SSH"),sshclient);\r
+               \r
+               //Setup SVN_SSH\r
+               CString ssh=sshclient;\r
+               ssh.Replace(_T("/"),_T("\\"));\r
+               ssh.Replace(_T("\\"),_T("\\\\"));\r
+               ssh=CString(_T("\""))+ssh+_T('\"');\r
+               _tputenv_s(_T("SVN_SSH"),ssh);\r
+\r
+       }else\r
+       {\r
+               TCHAR sPlink[MAX_PATH];\r
+               GetModuleFileName(NULL, sPlink, _countof(sPlink));\r
+               LPTSTR ptr = _tcsrchr(sPlink, _T('\\'));\r
+               if (ptr) {\r
+                       _tcscpy(ptr + 1, _T("TortoisePlink.exe"));\r
+                       _tputenv_s(_T("GIT_SSH"), sPlink);\r
+\r
+                       //Setup SVN_SSH\r
+                       CString ssh=sPlink;\r
+                       ssh.Replace(_T("/"),_T("\\"));\r
+                       ssh.Replace(_T("\\"),_T("\\\\"));\r
+                       ssh=CString(_T("\""))+ssh+_T('\"');\r
+                       _tputenv_s(_T("SVN_SSH"),ssh);\r
+               }\r
+       }\r
+\r
+       {\r
+               TCHAR sAskPass[MAX_PATH];\r
+               GetModuleFileName(NULL, sAskPass, _countof(sAskPass));\r
+               LPTSTR ptr = _tcsrchr(sAskPass, _T('\\'));\r
+               if (ptr) \r
+               {\r
+                       _tcscpy(ptr + 1, _T("SshAskPass.exe"));\r
+                       _tputenv_s(_T("DISPLAY"),_T(":9999"));\r
+                       _tputenv_s(_T("SSH_ASKPASS"),sAskPass);\r
+               }\r
+       }\r
+       // search PATH if git/bin directory is alredy present\r
+       if ( FindGitPath() )\r
+       {\r
+               bInitialized = TRUE;\r
+               return TRUE;\r
+       }\r
+\r
+       // add git/bin path to PATH\r
+\r
+       CRegString msysdir=CRegString(REG_MSYSGIT_PATH,_T(""),FALSE);\r
+       str=msysdir;\r
+       if(str.IsEmpty())\r
+       {\r
+               CRegString msysinstalldir=CRegString(REG_MSYSGIT_INSTALL,_T(""),FALSE,HKEY_LOCAL_MACHINE);\r
+               str=msysinstalldir;\r
+               if ( !str.IsEmpty() )\r
+               {\r
+                       str += (str[str.GetLength()-1] != '\\') ? "\\bin" : "bin";\r
+                       msysdir=str;\r
+                       msysdir.write();\r
+               }\r
+               else\r
+               {\r
+                       return false;\r
+               }\r
+       }\r
+#endif\r
+       //CGit::m_MsysGitPath=str;\r
+\r
+       //set path\r
+\r
+       _tdupenv_s(&oldpath,&size,_T("PATH")); \r
+\r
+       CString path;\r
+       path.Format(_T("%s;%s"),oldpath,str);\r
+\r
+       _tputenv_s(_T("PATH"),path);\r
+\r
+       CString sOldPath = oldpath;\r
+       free(oldpath);\r
+\r
+\r
+    if( !FindGitPath() )\r
+       {\r
+               if(!homesize)\r
+               {\r
+                       _tputenv_s(_T("HOME"),_T(""));\r
+               }\r
+               return false;\r
+       }\r
+       else\r
+       {\r
+#ifdef _TORTOISESHELL\r
+               l_processEnv = GetEnvironmentStrings();\r
+               // updated environment is now duplicated for use in CreateProcess, restore original PATH for current process\r
+               _tputenv_s(_T("PATH"),sOldPath);\r
+               if(!homesize)\r
+               {\r
+                       _tputenv_s(_T("HOME"),_T(""));\r
+               }\r
+#endif\r
+\r
+               bInitialized = TRUE;\r
+               return true;\r
+       }\r
+}\r
+\r
+\r
+class CGitCall_EnumFiles : public CGitCall\r
+{\r
+public:\r
+       CGitCall_EnumFiles(const TCHAR *pszProjectPath, const TCHAR *pszSubPath, unsigned int nFlags, WGENUMFILECB *pEnumCb, void *pUserData)\r
+       :       m_pszProjectPath(pszProjectPath),\r
+               m_pszSubPath(pszSubPath),\r
+               m_nFlags(nFlags),\r
+               m_pEnumCb(pEnumCb),\r
+               m_pUserData(pUserData)\r
+       {\r
+       }\r
+\r
+       typedef std::map<CStringA,char> TStrCharMap;\r
+\r
+       const TCHAR *   m_pszProjectPath;\r
+       const TCHAR *   m_pszSubPath;\r
+       unsigned int    m_nFlags;\r
+       WGENUMFILECB *  m_pEnumCb;\r
+       void *                  m_pUserData;\r
+\r
+       BYTE_VECTOR             m_DataCollector;\r
+\r
+       virtual bool    OnOutputData(const BYTE* data, size_t size)\r
+       {\r
+               m_DataCollector.append(data,size);\r
+               while(true)\r
+               {\r
+                       // lines from igit.exe are 0 terminated\r
+                       int found=m_DataCollector.findData((const BYTE*)"",1);\r
+                       if(found<0)\r
+                               return false;\r
+                       OnSingleLine( (LPCSTR)&*m_DataCollector.begin() );\r
+                       m_DataCollector.erase(m_DataCollector.begin(), m_DataCollector.begin()+found+1);\r
+               }\r
+               return false;//Should never reach this\r
+       }\r
+       virtual void    OnEnd()\r
+       {\r
+       }\r
+\r
+       BYTE HexChar(char ch)\r
+       {\r
+               if (ch >= '0' && ch <= '9')\r
+                       return (UINT)(ch - '0');\r
+               else if (ch >= 'A' && ch <= 'F')\r
+                       return (UINT)(ch - 'A') + 10;\r
+               else if (ch >= 'a' && ch <= 'f')\r
+                       return (UINT)(ch - 'a') + 10;\r
+               else\r
+                       return 0;\r
+       }\r
+\r
+       bool OnSingleLine(LPCSTR line)\r
+       {\r
+               //Parse single line\r
+\r
+               wgFile_s fileStatus;\r
+\r
+               // file/dir type\r
+\r
+               fileStatus.nFlags = 0;\r
+               if (*line == 'D')\r
+                       fileStatus.nFlags |= WGFF_Directory;\r
+               else if (*line != 'F')\r
+                       // parse error\r
+                       return false;\r
+               line += 2;\r
+\r
+               // status\r
+\r
+               fileStatus.nStatus = WGFS_Unknown;\r
+               switch (*line)\r
+               {\r
+               case 'N': fileStatus.nStatus = WGFS_Normal; break;\r
+               case 'M': fileStatus.nStatus = WGFS_Modified; break;\r
+               case 'S': fileStatus.nStatus = WGFS_Staged; break;\r
+               case 'A': fileStatus.nStatus = WGFS_Added; break;\r
+               case 'C': fileStatus.nStatus = WGFS_Conflicted; break;\r
+               case 'D': fileStatus.nStatus = WGFS_Deleted; break;\r
+               case 'I': fileStatus.nStatus = WGFS_Ignored; break;\r
+               case 'U': fileStatus.nStatus = WGFS_Unversioned; break;\r
+               case 'E': fileStatus.nStatus = WGFS_Empty; break;\r
+               case '?': fileStatus.nStatus = WGFS_Unknown; break;\r
+               default:\r
+                       // parse error\r
+                       return false;\r
+               }\r
+               line += 2;\r
+\r
+               // file sha1\r
+\r
+               BYTE sha1[20];\r
+               fileStatus.sha1 = NULL;\r
+               if ( !(fileStatus.nFlags & WGFF_Directory) )\r
+               {\r
+                       for (int i=0; i<20; i++)\r
+                       {\r
+                               sha1[i]  = (HexChar(line[0])<<4)&0xF0;\r
+                               sha1[i] |= HexChar(line[1])&0xF;\r
+\r
+                               line += 2;\r
+                       }\r
+\r
+                       line++;\r
+               }\r
+\r
+               // filename\r
+               int len = strlen(line);\r
+               if (len && len < 2048)\r
+               {\r
+                       WCHAR *buf = (WCHAR*)alloca((len*4+2)*sizeof(WCHAR));\r
+                       *buf = 0;\r
+                       MultiByteToWideChar(CP_ACP, 0, line, len+1, buf, len*4+1);\r
+                       fileStatus.sFileName = buf;\r
+\r
+                       if (*buf && (*m_pEnumCb)(&fileStatus,m_pUserData))\r
+                               return false;\r
+               }\r
+\r
+               return true;\r
+       }\r
+};\r
+\r
+BOOL CGit::EnumFiles(const TCHAR *pszProjectPath, const TCHAR *pszSubPath, unsigned int nFlags, WGENUMFILECB *pEnumCb, void *pUserData)\r
+{\r
+       if(!pszProjectPath || *pszProjectPath=='\0')\r
+               return FALSE;\r
+\r
+       CGitCall_EnumFiles W_GitCall(pszProjectPath,pszSubPath,nFlags,pEnumCb,pUserData);\r
+       CString cmd;\r
+\r
+/*     char W_szToDir[MAX_PATH];\r
+       strncpy(W_szToDir,pszProjectPath,sizeof(W_szToDir)-1);\r
+       if(W_szToDir[strlen(W_szToDir)-1]!='\\')\r
+               strncat(W_szToDir,"\\",sizeof(W_szToDir)-1);\r
+\r
+       SetCurrentDirectoryA(W_szToDir);\r
+       GetCurrentDirectoryA(sizeof(W_szToDir)-1,W_szToDir);\r
+*/\r
+       SetCurrentDir(pszProjectPath);\r
+\r
+       CString sMode;\r
+       if (nFlags)\r
+       {\r
+               if (nFlags & WGEFF_NoRecurse) sMode += _T("r");\r
+               if (nFlags & WGEFF_FullPath) sMode += _T("f");\r
+               if (nFlags & WGEFF_DirStatusDelta) sMode += _T("d");\r
+               if (nFlags & WGEFF_DirStatusAll) sMode += _T("D");\r
+               if (nFlags & WGEFF_EmptyAsNormal) sMode += _T("e");\r
+               if (nFlags & WGEFF_SingleFile) sMode += _T("s");\r
+       }\r
+       else\r
+       {\r
+               sMode = _T("-");\r
+       }\r
+\r
+       // NOTE: there seems to be some issue with msys based app receiving backslash on commandline, at least\r
+       // if followed by " like for example 'igit "C:\"', the commandline igit receives is 'igit.exe C:" status' with\r
+       // the 'C:" status' part as a single arg, Maybe it uses unix style processing. In order to avoid this just\r
+       // use forward slashes for supplied project and sub paths\r
+\r
+       CString sProjectPath = pszProjectPath;\r
+       sProjectPath.Replace(_T('\\'), _T('/'));\r
+\r
+       if (pszSubPath)\r
+       {\r
+               CString sSubPath = pszSubPath;\r
+               sSubPath.Replace(_T('\\'), _T('/'));\r
+\r
+               cmd.Format(_T("tgit.exe statusex \"%s\" status %s \"%s\""), sProjectPath, sMode, sSubPath);\r
+       }\r
+       else\r
+       {\r
+               cmd.Format(_T("tgit.exe statusex \"%s\" status %s"), sProjectPath, sMode);\r
+       }\r
+\r
+       //OutputDebugStringA("---");OutputDebugStringW(cmd);OutputDebugStringA("\r\n");\r
+\r
+       W_GitCall.SetCmd(cmd);\r
+       // NOTE: should igit get added as a part of msysgit then use below line instead of the above one\r
+       //W_GitCall.SetCmd(CGit::ms_LastMsysGitDir + cmd);\r
+\r
+       if ( Run(&W_GitCall) )\r
+               return FALSE;\r
+\r
+       return TRUE;\r
+}\r
+\r
+BOOL CGit::CheckCleanWorkTree()\r
+{\r
+       CString out;\r
+       CString cmd;\r
+       cmd=_T("git.exe rev-parse --verify HEAD");\r
+\r
+       if(g_Git.Run(cmd,&out,CP_UTF8))\r
+               return FALSE;\r
+\r
+       cmd=_T("git.exe update-index --ignore-submodules --refresh");\r
+       if(g_Git.Run(cmd,&out,CP_UTF8))\r
+               return FALSE;\r
+\r
+       cmd=_T("git.exe diff-files --quiet --ignore-submodules");\r
+       if(g_Git.Run(cmd,&out,CP_UTF8))\r
+               return FALSE;\r
+\r
+       cmd=_T("git diff-index --cached --quiet HEAD --ignore-submodules");\r
+       if(g_Git.Run(cmd,&out,CP_UTF8))\r
+               return FALSE;\r
+\r
+       return TRUE;\r
+}\r
+int CGit::Revert(CTGitPathList &list,bool keep)\r
+{\r
+       int ret;\r
+       for(int i=0;i<list.GetCount();i++)\r
+       {       \r
+               ret = Revert((CTGitPath&)list[i],keep);\r
+               if(ret)\r
+                       return ret;\r
+       }\r
+       return 0;\r
+}\r
+int CGit::Revert(CTGitPath &path,bool keep)\r
+{\r
+       CString cmd, out;\r
+       if(path.m_Action & CTGitPath::LOGACTIONS_ADDED)\r
+       {       //To init git repository, there are not HEAD, so we can use git reset command\r
+               cmd.Format(_T("git.exe rm --cached -- \"%s\""),path.GetGitPathString());\r
+\r
+               if(g_Git.Run(cmd,&out,CP_ACP))\r
+                       return -1;\r
+       }\r
+       else if(path.m_Action & CTGitPath::LOGACTIONS_REPLACED )\r
+       {\r
+               cmd.Format(_T("git.exe mv -- \"%s\" \"%s\""),path.GetGitPathString(),path.GetGitOldPathString());\r
+               if(g_Git.Run(cmd,&out,CP_ACP))\r
+                       return -1;\r
+               \r
+               cmd.Format(_T("git.exe checkout HEAD -f -- \"%s\""),path.GetGitOldPathString());\r
+               if(g_Git.Run(cmd,&out,CP_ACP))\r
+                       return -1;\r
+       }\r
+       else\r
+       {\r
+               cmd.Format(_T("git.exe checkout HEAD -f -- \"%s\""),path.GetGitPathString());\r
+               if(g_Git.Run(cmd,&out,CP_ACP))\r
+                       return -1;\r
+       }\r
+       return 0;\r
+}\r
+\r
+int CGit::ListConflictFile(CTGitPathList &list,CTGitPath *path)\r
+{\r
+       BYTE_VECTOR vector;\r
+\r
+       CString cmd;\r
+       if(path)\r
+               cmd.Format(_T("git.exe ls-files -u -t -z -- \"%s\""),path->GetGitPathString());\r
+       else\r
+               cmd=_T("git.exe ls-files -u -t -z");\r
+\r
+       if(g_Git.Run(cmd,&vector))\r
+       {\r
+               return -1;\r
+       }\r
+\r
+       list.ParserFromLsFile(vector);\r
+\r
+       return 0;\r
+}\r
+\r
+bool CGit::IsFastForward(CString &from, CString &to)\r
+{\r
+       CString base,hash;\r
+       CString cmd;\r
+       cmd.Format(_T("git.exe merge-base %s %s"), to,from);\r
+\r
+       if(g_Git.Run(cmd,&base,CP_ACP))\r
+       {\r
+               //CMessageBox::Show(NULL,base,_T("TortoiseGit"),MB_OK|MB_ICONERROR);\r
+               return false;\r
+       }\r
+       base=base.Left(40);\r
+\r
+       hash=g_Git.GetHash(from);\r
+\r
+       hash=hash.Left(40);\r
+       \r
+       return hash == base;\r
+}\r
+\r
+unsigned int CGit::Hash2int(CString &hash)\r
+{\r
+       int ret=0;\r
+       for(int i=0;i<8;i++)\r
+       {\r
+               ret =ret <<4;\r
+               if(hash[i]>=_T('a'))\r
+                       ret |= (hash[i]-_T('a')+10)&0xFF;\r
+               else if(hash[i]>=_T('A'))\r
+                       ret |= (hash[i]-_T('A')+10)&0xFF;\r
+               else\r
+                       ret |= (hash[i]-_T('0'))&0xFF;          \r
+               \r
+       }\r
+       return ret;\r
+}\r
+\r
+int CGit::RefreshGitIndex()\r
+{\r
+       CString cmd,output;\r
+       cmd=_T("git.exe update-index --refresh");\r
+       return Run(cmd,&output,CP_ACP);\r
+}\r
+\r