OSDN Git Service

Add Git submodule update and fix ProgressDlg show Okay when command still running.
[tortoisegit/TortoiseGitJp.git] / src / Git / Git.cpp
index 024d6bd..cdc7c0c 100644 (file)
@@ -171,6 +171,9 @@ int CGit::RunAsync(CString cmd,PROCESS_INFORMATION *piOut,HANDLE *hReadOut,CStri
 \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; \r
 \r
        if(!CreateProcess(NULL,(LPWSTR)cmd.GetString(), NULL,NULL,TRUE,dwFlags,pEnv,(LPWSTR)m_CurrentDir.GetString(),&si,&pi))\r
        {\r
@@ -333,6 +336,52 @@ CString CGit::GetCurrentBranch(void)
        return CString("");\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
@@ -553,7 +602,8 @@ git_revnum_t CGit::GetHash(CString &friendname)
        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.ReverseFind(_T('\n'));\r
+       int pos=out.FindOneOf(_T("\r\n"));\r
        if(pos>0)\r
                return out.Left(pos);\r
        return out;\r
@@ -637,6 +687,30 @@ int CGit::GetRemoteList(STRING_VECTOR &list)
        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
@@ -688,17 +762,33 @@ BOOL CGit::CheckMsysGitDir()
        }\r
 \r
        //setup ssh client\r
-       CRegString sshclient=CRegString(_T("Software\\TortoiseGit\\SSH"));\r
-       CString ssh=sshclient;\r
+       CString sshclient=CRegString(_T("Software\\TortoiseGit\\SSH"));\r
 \r
-       if(!ssh.IsEmpty())\r
+       if(!sshclient.IsEmpty())\r
        {\r
-               _tputenv_s(_T("GIT_SSH"),ssh);\r
+               _tputenv_s(_T("GIT_SSH"),sshclient);\r
        }else\r
        {\r
-               _tputenv_s(_T("GIT_SSH"),_T(""));\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
        }\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
@@ -761,7 +851,7 @@ BOOL CGit::CheckMsysGitDir()
 class CGitCall_EnumFiles : public CGitCall\r
 {\r
 public:\r
-       CGitCall_EnumFiles(const char *pszProjectPath, const char *pszSubPath, unsigned int nFlags, WGENUMFILECB *pEnumCb, void *pUserData)\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
@@ -772,8 +862,8 @@ public:
 \r
        typedef std::map<CStringA,char> TStrCharMap;\r
 \r
-       const char *    m_pszProjectPath;\r
-       const char *    m_pszSubPath;\r
+       const TCHAR *   m_pszProjectPath;\r
+       const TCHAR *   m_pszSubPath;\r
        unsigned int    m_nFlags;\r
        WGENUMFILECB *  m_pEnumCb;\r
        void *                  m_pUserData;\r
@@ -821,6 +911,9 @@ public:
                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
@@ -837,6 +930,10 @@ public:
                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
@@ -848,7 +945,7 @@ public:
                {\r
                        for (int i=0; i<20; i++)\r
                        {\r
-                               sha1[i] = (HexChar(line[0]) << 8) | HexChar(line[1]);\r
+                               sha1[i] = (BYTE)((HexChar(line[0]) << 8) | HexChar(line[1]));\r
                                line += 2;\r
                        }\r
 \r
@@ -856,16 +953,23 @@ public:
                }\r
 \r
                // filename\r
-               fileStatus.sFileName = line;\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 ( (*m_pEnumCb)(&fileStatus,m_pUserData) )\r
-                       return false;\r
+                       if (*buf && (*m_pEnumCb)(&fileStatus,m_pUserData))\r
+                               return false;\r
+               }\r
 \r
                return true;\r
        }\r
 };\r
 \r
-BOOL CGit::EnumFiles(const char *pszProjectPath, const char *pszSubPath, unsigned int nFlags, WGENUMFILECB *pEnumCb, void *pUserData)\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
@@ -881,7 +985,7 @@ BOOL CGit::EnumFiles(const char *pszProjectPath, const char *pszSubPath, unsigne
        SetCurrentDirectoryA(W_szToDir);\r
        GetCurrentDirectoryA(sizeof(W_szToDir)-1,W_szToDir);\r
 */\r
-       SetCurrentDir(CUnicodeUtils::GetUnicode(pszProjectPath));\r
+       SetCurrentDir(pszProjectPath);\r
 \r
        CString sMode;\r
        if (nFlags)\r
@@ -899,9 +1003,9 @@ BOOL CGit::EnumFiles(const char *pszProjectPath, const char *pszSubPath, unsigne
        }\r
 \r
        if (pszSubPath)\r
-               cmd.Format(_T("igit.exe \"%s\" status %s \"%s\""), CUnicodeUtils::GetUnicode(pszProjectPath), sMode, CUnicodeUtils::GetUnicode(pszSubPath));\r
+               cmd.Format(_T("igit.exe \"%s\" status %s \"%s\""), pszProjectPath, sMode, pszSubPath);\r
        else\r
-               cmd.Format(_T("igit.exe \"%s\" status %s"), CUnicodeUtils::GetUnicode(pszProjectPath), sMode);\r
+               cmd.Format(_T("igit.exe \"%s\" status %s"), pszProjectPath, sMode);\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
@@ -962,13 +1066,13 @@ int CGit::Revert(CTGitPath &path,bool keep)
                if(g_Git.Run(cmd,&out,CP_OEMCP))\r
                        return -1;\r
                \r
-               cmd.Format(_T("git.exe checkout -f -- \"%s\""),path.GetGitOldPathString());\r
+               cmd.Format(_T("git.exe checkout HEAD -f -- \"%s\""),path.GetGitOldPathString());\r
                if(g_Git.Run(cmd,&out,CP_OEMCP))\r
                        return -1;\r
        }\r
        else\r
        {\r
-               cmd.Format(_T("git.exe checkout -f -- \"%s\""),path.GetGitPathString());\r
+               cmd.Format(_T("git.exe checkout HEAD -f -- \"%s\""),path.GetGitPathString());\r
                if(g_Git.Run(cmd,&out,CP_OEMCP))\r
                        return -1;\r
        }\r