X-Git-Url: http://git.sourceforge.jp/view?a=blobdiff_plain;f=src%2FGit%2FGit.cpp;h=300011353dab7a5918bc515c4cf4ec3509e58854;hb=969d1260761a3a62a6cdb4fb3ab000396d65cd69;hp=5d62fb2d6aacc482f378babf0d92ee9c84d0001d;hpb=0720fd3abc8e2ed4e95d1265d9e70c1b6a476de4;p=tortoisegit%2FTortoiseGitJp.git diff --git a/src/Git/Git.cpp b/src/Git/Git.cpp index 5d62fb2..3000113 100644 --- a/src/Git/Git.cpp +++ b/src/Git/Git.cpp @@ -7,6 +7,7 @@ #include #include "UnicodeUtils.h" +int CGit::m_LogEncode=CP_UTF8; static LPTSTR nextpath(LPCTSTR src, LPTSTR dst, UINT maxlen) { @@ -120,27 +121,6 @@ CGit g_Git; static LPTSTR l_processEnv = NULL; -BOOL CGit::IsVista() -{ - - if( CRegStdWORD(_T("Software\\TortoiseGit\\CacheType") ) == 0) - { - return TRUE; - } - - OSVERSIONINFO osvi; - BOOL bIsWindowsXPorLater; - - ZeroMemory(&osvi, sizeof(OSVERSIONINFO)); - osvi.dwOSVersionInfoSize = sizeof(OSVERSIONINFO); - - GetVersionEx(&osvi); - - if(osvi.dwMajorVersion >= 6) - return TRUE; - else - return FALSE; -} CGit::CGit(void) { @@ -192,6 +172,9 @@ int CGit::RunAsync(CString cmd,PROCESS_INFORMATION *piOut,HANDLE *hReadOut,CStri 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; if(!CreateProcess(NULL,(LPWSTR)cmd.GetString(), NULL,NULL,TRUE,dwFlags,pEnv,(LPWSTR)m_CurrentDir.GetString(),&si,&pi)) { @@ -218,6 +201,9 @@ 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 ; @@ -320,13 +306,15 @@ CString CGit::GetUserName(void) { CString UserName; Run(_T("git.exe config user.name"),&UserName,CP_UTF8); - return UserName; + int start = 0; + return UserName.Tokenize(_T("\n"),start); } CString CGit::GetUserEmail(void) { CString UserName; Run(_T("git.exe config user.email"),&UserName,CP_UTF8); - return UserName; + int start = 0; + return UserName.Tokenize(_T("\n"),start); } CString CGit::GetCurrentBranch(void) @@ -351,6 +339,52 @@ CString CGit::GetCurrentBranch(void) return CString(""); } +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; @@ -370,15 +404,16 @@ int CGit::BuildOutputFormat(CString &format,bool IsFull) format += log; log.Format(_T("#<%c>%%ci%%x00"),LOG_REV_COMMIT_DATE); format += log; - log.Format(_T("#<%c>%%s%%x00"),LOG_REV_COMMIT_SUBJECT); - 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) { @@ -388,14 +423,14 @@ int CGit::BuildOutputFormat(CString &format,bool IsFull) return 0; } -int CGit::GetLog(BYTE_VECTOR& logOut, CString &hash, CTGitPath *path ,int count,int mask) +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); + 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) +int CGit::GetLog(CGitCall* pgitCall, CString &hash, CTGitPath *path, int count, int mask,CString *from,CString *to) { CString cmd; @@ -442,6 +477,15 @@ int CGit::GetLog(CGitCall* pgitCall, CString &hash, CTGitPath *path, int count, if(mask& CGit::LOG_INFO_FOLLOW) param += _T(" --follow "); + if(mask& CGit::LOG_INFO_SHOW_MERGEDFILE) + param += _T(" -c "); + + 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:\""), @@ -559,13 +603,14 @@ int CGit::RunLogFile(CString cmd,CString &filename) // return 0; } -git_revnum_t CGit::GetHash(CString &friendname) +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.ReverseFind(_T('\n')); + int pos=out.FindOneOf(_T("\r\n")); if(pos>0) return out.Left(pos); return out; @@ -612,10 +657,16 @@ int CGit::GetBranchList(STRING_VECTOR &list,int *current,BRANCH_TYPE type) while( pos>=0 ) { one=output.Tokenize(_T("\n"),pos); - list.push_back(one.Right(one.GetLength()-2)); + 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++; } } @@ -649,6 +700,30 @@ int CGit::GetRemoteList(STRING_VECTOR &list) 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; @@ -688,29 +763,47 @@ BOOL CGit::CheckMsysGitDir() } TCHAR *oldpath,*home; - size_t size; + size_t homesize,size; // set HOME if not set already - _tgetenv_s(&size, NULL, 0, _T("HOME")); - if (!size) + _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 //setup ssh client - CRegString sshclient=CRegString(_T("Software\\TortoiseGit\\SSH")); - CString ssh=sshclient; + CString sshclient=CRegString(_T("Software\\TortoiseGit\\SSH")); - if(!ssh.IsEmpty()) + if(!sshclient.IsEmpty()) { - _tputenv_s(_T("GIT_SSH"),ssh); + _tputenv_s(_T("GIT_SSH"),sshclient); }else { - _tputenv_s(_T("GIT_SSH"),_T("")); + 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); + } } + { + 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() ) { @@ -720,8 +813,8 @@ BOOL CGit::CheckMsysGitDir() // add git/bin path to PATH - CRegString msysdir=CRegString(REG_MSYSGIT_PATH,_T(""),FALSE,HKEY_LOCAL_MACHINE); - CString str=msysdir; + CRegString msysdir=CRegString(REG_MSYSGIT_PATH,_T(""),FALSE); + str=msysdir; if(str.IsEmpty()) { CRegString msysinstalldir=CRegString(REG_MSYSGIT_INSTALL,_T(""),FALSE,HKEY_LOCAL_MACHINE); @@ -737,6 +830,7 @@ BOOL CGit::CheckMsysGitDir() return false; } } +#endif //CGit::m_MsysGitPath=str; //set path @@ -762,6 +856,10 @@ BOOL CGit::CheckMsysGitDir() 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; @@ -773,7 +871,7 @@ BOOL CGit::CheckMsysGitDir() class CGitCall_EnumFiles : public CGitCall { public: - CGitCall_EnumFiles(const char *pszProjectPath, const char *pszSubPath, unsigned int nFlags, WGENUMFILECB *pEnumCb, void *pUserData) + CGitCall_EnumFiles(const TCHAR *pszProjectPath, const TCHAR *pszSubPath, unsigned int nFlags, WGENUMFILECB *pEnumCb, void *pUserData) : m_pszProjectPath(pszProjectPath), m_pszSubPath(pszSubPath), m_nFlags(nFlags), @@ -784,8 +882,8 @@ public: typedef std::map TStrCharMap; - const char * m_pszProjectPath; - const char * m_pszSubPath; + const TCHAR * m_pszProjectPath; + const TCHAR * m_pszSubPath; unsigned int m_nFlags; WGENUMFILECB * m_pEnumCb; void * m_pUserData; @@ -810,7 +908,7 @@ public: { } - UINT HexChar(char ch) + BYTE HexChar(char ch) { if (ch >= '0' && ch <= '9') return (UINT)(ch - '0'); @@ -833,6 +931,9 @@ public: fileStatus.nFlags = 0; if (*line == 'D') fileStatus.nFlags |= WGFF_Directory; + else if (*line != 'F') + // parse error + return false; line += 2; // status @@ -849,6 +950,10 @@ public: 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; @@ -860,7 +965,9 @@ public: { for (int i=0; i<20; i++) { - sha1[i] = (HexChar(line[0]) << 8) | HexChar(line[1]); + sha1[i] = (HexChar(line[0])<<4)&0xF0; + sha1[i] |= HexChar(line[1])&0xF; + line += 2; } @@ -868,16 +975,23 @@ public: } // filename - fileStatus.sFileName = line; + 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 ( (*m_pEnumCb)(&fileStatus,m_pUserData) ) - return false; + if (*buf && (*m_pEnumCb)(&fileStatus,m_pUserData)) + return false; + } return true; } }; -BOOL CGit::EnumFiles(const char *pszProjectPath, const char *pszSubPath, unsigned int nFlags, WGENUMFILECB *pEnumCb, void *pUserData) +BOOL CGit::EnumFiles(const TCHAR *pszProjectPath, const TCHAR *pszSubPath, unsigned int nFlags, WGENUMFILECB *pEnumCb, void *pUserData) { if(!pszProjectPath || *pszProjectPath=='\0') return FALSE; @@ -893,7 +1007,7 @@ BOOL CGit::EnumFiles(const char *pszProjectPath, const char *pszSubPath, unsigne SetCurrentDirectoryA(W_szToDir); GetCurrentDirectoryA(sizeof(W_szToDir)-1,W_szToDir); */ - SetCurrentDir(CUnicodeUtils::GetUnicode(pszProjectPath)); + SetCurrentDir(pszProjectPath); CString sMode; if (nFlags) @@ -911,9 +1025,9 @@ BOOL CGit::EnumFiles(const char *pszProjectPath, const char *pszSubPath, unsigne } if (pszSubPath) - cmd.Format(_T("igit.exe %s status %s %s"), CUnicodeUtils::GetUnicode(pszProjectPath), sMode, CUnicodeUtils::GetUnicode(pszSubPath)); + cmd.Format(_T("igit.exe \"%s\" status %s \"%s\""), pszProjectPath, sMode, pszSubPath); else - cmd.Format(_T("igit.exe %s status %s"), CUnicodeUtils::GetUnicode(pszProjectPath), sMode); + cmd.Format(_T("igit.exe \"%s\" status %s"), pszProjectPath, sMode); W_GitCall.SetCmd(cmd); // NOTE: should igit get added as a part of msysgit then use below line instead of the above one @@ -924,3 +1038,85 @@ BOOL CGit::EnumFiles(const char *pszProjectPath, const char *pszSubPath, unsigne 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;iGetGitPathString()); + else + cmd=_T("git.exe ls-files -u -t -z"); + + if(g_Git.Run(cmd,&vector)) + { + return -1; + } + + list.ParserFromLsFile(vector); + + return 0; +} \ No newline at end of file