OSDN Git Service

merge original branch.
[tortoisegit/TortoiseGitJp.git] / src / Git / TGitPath.cpp
index 10a7ed7..0f59c32 100644 (file)
 #include "PathUtils.h"\r
 #include <regex>\r
 #include "git.h"\r
+#include "Globals.h"\r
+\r
 #if defined(_MFC_VER)\r
 //#include "MessageBox.h"\r
 //#include "AppUtils.h"\r
 #endif\r
 \r
+#ifndef ASSERT\r
+#define ASSERT()\r
+#endif\r
 using namespace std;\r
 extern CGit g_Git;\r
 \r
@@ -78,20 +83,29 @@ CTGitPath::CTGitPath(const CString& sUnknownPath) :
 {\r
        SetFromUnknown(sUnknownPath);\r
        m_Action=0;\r
+       m_Stage=0;\r
 }\r
 \r
-int CTGitPath::ParserAction(CString action)\r
+int CTGitPath::ParserAction(BYTE action)\r
 {\r
-       action=action.TrimLeft();\r
-       TCHAR c=action.GetAt(0);\r
-       if(c == _T('M'))\r
+       //action=action.TrimLeft();\r
+       //TCHAR c=action.GetAt(0);\r
+       if(action == 'M')\r
                m_Action|= LOGACTIONS_MODIFIED;\r
-       if(c == _T('R'))\r
+       if(action == 'R')\r
                m_Action|= LOGACTIONS_REPLACED;\r
-       if(c == _T('A'))\r
+       if(action == 'A')\r
                m_Action|= LOGACTIONS_ADDED;\r
-       if(c == _T('D'))\r
+       if(action == 'D')\r
+               m_Action|= LOGACTIONS_DELETED;\r
+       if(action == 'U')\r
+               m_Action|= LOGACTIONS_UNMERGED;\r
+       if(action == 'K')\r
                m_Action|= LOGACTIONS_DELETED;\r
+       if(action == 'H')\r
+               m_Action|= LOGACTIONS_CACHE;\r
+       if(action == 'C' )\r
+               m_Action|= LOGACTIONS_COPY;\r
 \r
        return m_Action;\r
 }\r
@@ -116,11 +130,25 @@ void CTGitPath::SetFromGit(const char* pPath, bool bIsDirectory)
        m_bIsDirectory = bIsDirectory;\r
 }\r
 \r
-void CTGitPath::SetFromGit(const CString& sPath)\r
+void CTGitPath::SetFromGit(const TCHAR* pPath, bool bIsDirectory)\r
+{\r
+       Reset();\r
+       if (pPath)\r
+       {\r
+               m_sFwdslashPath = pPath;\r
+               SanitizeRootPath(m_sFwdslashPath, true);\r
+       }\r
+       m_bDirectoryKnown = true;\r
+       m_bIsDirectory = bIsDirectory;\r
+}\r
+\r
+void CTGitPath::SetFromGit(const CString& sPath,CString *oldpath)\r
 {\r
        Reset();\r
        m_sFwdslashPath = sPath;\r
        SanitizeRootPath(m_sFwdslashPath, true);\r
+       if(oldpath)\r
+               m_sOldFwdslashPath = *oldpath;\r
 }\r
 \r
 void CTGitPath::SetFromWin(LPCTSTR pPath)\r
@@ -148,7 +176,12 @@ void CTGitPath::SetFromUnknown(const CString& sPath)
 {\r
        Reset();\r
        // Just set whichever path we think is most likely to be used\r
-       SetFwdslashPath(sPath);\r
+//     GitAdminDir admin;\r
+//     CString p;\r
+//     if(admin.HasAdminDir(sPath,&p))\r
+//             SetFwdslashPath(sPath.Right(sPath.GetLength()-p.GetLength()));\r
+//     else\r
+               SetFwdslashPath(sPath);\r
 }\r
 \r
 LPCTSTR CTGitPath::GetWinPath() const\r
@@ -183,6 +216,10 @@ const CString& CTGitPath::GetGitPathString() const
        return m_sFwdslashPath;\r
 }\r
 \r
+const CString &CTGitPath::GetGitOldPathString() const\r
+{\r
+       return m_sOldFwdslashPath;\r
+}\r
 #if 0\r
 const char* CTGitPath::GetGitApiPath(apr_pool_t *pool) const\r
 {\r
@@ -393,6 +430,17 @@ void CTGitPath::UpdateAttributes() const
        m_bExistsKnown = true;\r
 }\r
 \r
+CTGitPath CTGitPath::GetSubPath(CTGitPath &root)\r
+{\r
+       CTGitPath path;\r
+       \r
+       if(GetWinPathString().Left(root.GetWinPathString().GetLength()) == root.GetWinPathString())\r
+       {\r
+               CString str=GetWinPathString();\r
+               path.SetFromWin(str.Right(str.GetLength()-root.GetWinPathString().GetLength()-1));\r
+       }\r
+       return path;\r
+}\r
 \r
 void CTGitPath::EnsureBackslashPathSet() const\r
 {\r
@@ -481,7 +529,7 @@ CString CTGitPath::GetRootPathString() const
 \r
 CString CTGitPath::GetFilename() const\r
 {\r
-       ATLASSERT(!IsDirectory());\r
+       //ATLASSERT(!IsDirectory());\r
        return GetFileOrDirectoryName();\r
 }\r
 \r
@@ -515,7 +563,7 @@ CString CTGitPath::GetBaseFilename() const
        CString filename=GetFilename();\r
        dot = filename.ReverseFind(_T('.'));\r
        if(dot>0)\r
-               return filename.Left(dot-1);\r
+               return filename.Left(dot);\r
        else\r
                return filename;\r
 }\r
@@ -709,11 +757,90 @@ bool CTGitPath::HasAdminDir() const
                return m_bHasAdminDir;\r
 \r
        EnsureBackslashPathSet();\r
-       m_bHasAdminDir = g_GitAdminDir.HasAdminDir(m_sBackslashPath, IsDirectory());\r
+       m_bHasAdminDir = g_GitAdminDir.HasAdminDir(m_sBackslashPath, IsDirectory(), &m_sProjectRoot);\r
        m_bHasAdminDirKnown = true;\r
        return m_bHasAdminDir;\r
 }\r
 \r
+bool CTGitPath::HasSubmodules() const\r
+{\r
+       return !g_GitAdminDir.GetSuperProjectRoot(GetWinPathString()).IsEmpty();\r
+}\r
+\r
+int CTGitPath::GetAdminDirMask() const\r
+{\r
+       int status = 0;\r
+       CString topdir,path;\r
+       if(!g_GitAdminDir.HasAdminDir(GetWinPathString(),&topdir))\r
+       {\r
+               return status;\r
+       }\r
+\r
+       status |= ITEMIS_INSVN|ITEMIS_FOLDERINSVN;\r
+\r
+       path=topdir;\r
+       path+=_T("\\");\r
+       path+=g_GitAdminDir.GetAdminDirName();\r
+       path+=_T("\\refs\\stash");\r
+       if( PathFileExists(path) )\r
+               status |= ITEMIS_STASH;\r
+       \r
+       path=topdir;\r
+       path+=_T("\\");\r
+       path+=g_GitAdminDir.GetAdminDirName();\r
+       path+=_T("\\svn");\r
+       if( PathFileExists(path) )\r
+               status |= ITEMIS_GITSVN;\r
+\r
+       path=topdir;\r
+       path+=_T("\\.gitmodules");\r
+       if( PathFileExists(path) )\r
+               status |= ITEMIS_SUBMODULE;\r
+\r
+       return status;\r
+}\r
+\r
+bool CTGitPath::HasStashDir() const\r
+{\r
+       CString topdir;\r
+       if(!g_GitAdminDir.HasAdminDir(GetWinPathString(),&topdir))\r
+       {\r
+               return false;\r
+       }\r
+       topdir+=_T("\\");\r
+       topdir+=g_GitAdminDir.GetAdminDirName();\r
+       topdir+=_T("\\refs\stash");\r
+       return PathFileExists(topdir);\r
+}\r
+bool CTGitPath::HasGitSVNDir() const\r
+{\r
+       CString topdir;\r
+       if(!g_GitAdminDir.HasAdminDir(GetWinPathString(),&topdir))\r
+       {\r
+               return false;\r
+       }\r
+       topdir+=_T("\\");\r
+       topdir+=g_GitAdminDir.GetAdminDirName();\r
+       topdir+=_T("\\svn");\r
+       return PathFileExists(topdir);\r
+}\r
+bool CTGitPath::HasAdminDir(CString *ProjectTopDir) const\r
+{\r
+       if (m_bHasAdminDirKnown)\r
+       {\r
+               if (ProjectTopDir)\r
+                       *ProjectTopDir = m_sProjectRoot;\r
+               return m_bHasAdminDir;\r
+       }\r
+\r
+       EnsureBackslashPathSet();\r
+       m_bHasAdminDir = g_GitAdminDir.HasAdminDir(m_sBackslashPath, IsDirectory(), &m_sProjectRoot);\r
+       m_bHasAdminDirKnown = true;\r
+       if (ProjectTopDir)\r
+               *ProjectTopDir = m_sProjectRoot;\r
+       return m_bHasAdminDir;\r
+}\r
+\r
 bool CTGitPath::IsAdminDir() const\r
 {\r
        if (m_bIsAdminDirKnown)\r
@@ -811,83 +938,234 @@ CTGitPathList::CTGitPathList(const CTGitPath& firstEntry)
 {\r
        AddPath(firstEntry);\r
 }\r
-int CTGitPathList::FillUnRev(int action)\r
+int CTGitPathList::ParserFromLsFile(BYTE_VECTOR &out,bool staged)\r
 {\r
        int pos=0;\r
-       this->Clear();\r
+       CString one;\r
        CTGitPath path;\r
-       \r
-       CString cmd(_T("git.cmd ls-files --exclude-standard --full-name --others"));\r
-       if(action & CTGitPath::LOGACTIONS_IGNORE)\r
-               cmd += _T(" --ignored");\r
-       CString out;\r
-       g_Git.Run(cmd,&out);\r
+       CString part;\r
+       this->Clear();\r
 \r
-       CString one;\r
-       while( pos>=0 )\r
+       while(pos>=0 && pos<out.size())\r
        {\r
-               one=out.Tokenize(_T("\n"),pos);\r
+               one.Empty();\r
+               path.Reset();\r
+\r
+               g_Git.StringAppend(&one,&out[pos],CP_ACP);\r
+               int tabstart=0;\r
+               path.m_Action=path.ParserAction(out[pos]);\r
+               one.Tokenize(_T("\t"),tabstart); \r
+\r
+               if(tabstart>=0)\r
+                       path.SetFromGit(one.Right(one.GetLength()-tabstart));\r
+\r
+               tabstart=0;\r
+\r
+               part=one.Tokenize(_T(" "),tabstart); //Tag\r
+\r
+               part=one.Tokenize(_T(" "),tabstart); //Mode\r
+               \r
+               part=one.Tokenize(_T(" "),tabstart); //Hash\r
+\r
+               part=one.Tokenize(_T("\t"),tabstart); //Stage\r
+\r
+               path.m_Stage=_ttol(part);\r
+\r
+               this->AddPath(path);\r
+\r
+               pos=out.findNextString(pos);\r
+       }\r
+       return pos;\r
+}\r
+int CTGitPathList::FillUnRev(int action,CTGitPathList *list)\r
+{\r
+       int pos=0;\r
+       this->Clear();\r
+       CTGitPath path;\r
+\r
+       int count;\r
+       if(list==NULL)\r
+               count=1;\r
+       else\r
+               count=list->GetCount();\r
+       for(int i=0;i<count;i++)\r
+       {       \r
+               CString cmd;\r
+               pos=0;\r
+               \r
+               CString ignored;\r
+               if(action & CTGitPath::LOGACTIONS_IGNORE)\r
+                       ignored= _T(" --ignored");\r
+               \r
+               if(list==NULL)\r
+               {\r
+                       cmd=_T("git.exe ls-files --exclude-standard --full-name --others -z");\r
+                       cmd+=ignored;\r
+                       \r
+               }\r
+               else\r
+               {       cmd.Format(_T("git.exe ls-files --exclude-standard --full-name --others -z %s-- \"%s\""),\r
+                                       ignored,\r
+                                       (*list)[i].GetWinPathString());\r
+               }\r
+\r
+               BYTE_VECTOR out;\r
+               out.clear();\r
+               g_Git.Run(cmd,&out);\r
+               \r
+               pos=0;\r
+               CString one;\r
+               while( pos>=0 && pos<out.size())\r
+               {\r
+                       one.Empty();\r
+                       g_Git.StringAppend(&one,&out[pos],CP_ACP);\r
+                       if(!one.IsEmpty())\r
+                       {\r
+                               //SetFromGit will clear all status\r
+                               path.SetFromGit(one);\r
+                               path.m_Action=action;\r
+                               AddPath(path);\r
+                       }\r
+                       pos=out.findNextString(pos);\r
+               }\r
 \r
-               //SetFromGit will clear all status\r
-               path.SetFromGit(one);\r
-               path.m_Action=action;\r
-               AddPath(path);\r
        }\r
        return 0;\r
 }\r
-int CTGitPathList::ParserFromLog(CString &log)\r
+int CTGitPathList::ParserFromLog(BYTE_VECTOR &log)\r
 {\r
        this->Clear();\r
        int pos=0;\r
-       CString one;\r
+       //BYTE *p=&log[0];\r
+       //CString one;\r
        CTGitPath path;\r
        m_Action=0;\r
-       while( pos>=0 )\r
+       while( pos>=0 && pos<log.size())\r
        {\r
-               one=log.Tokenize(_T("\n"),pos);\r
-               if(one[0]==_T(':'))\r
+               //one=log.Tokenize(_T("\n"),pos);\r
+               path.Reset();\r
+               if(log[pos]=='\n')\r
+                       pos++;\r
+\r
+               if(log[pos]==':')\r
                {\r
-                       int tabstart=0;\r
-                       int actionstart=0;\r
-                       CString pathname;\r
-                       CString action;\r
-                       one.Tokenize(_T("\t"),tabstart);\r
-                       if(tabstart >0)\r
+                       bool merged=false;\r
+                       if(log[pos+1] ==':')\r
                        {\r
-                               action=one.Left(tabstart);\r
-                               actionstart=action.ReverseFind(_T(' '));\r
-                               if(actionstart>0)\r
+                               merged=true;\r
+                       }\r
+                       int end=log.find(0,pos);\r
+                       int actionstart=-1;\r
+                       int numfile=1;\r
+                       int file1=-1,file2=-1;\r
+                       if( end>0 )\r
+                       {\r
+                               actionstart=log.find(' ',end-6);\r
+                               pos=actionstart;\r
+                       }\r
+                       if( actionstart>0 )\r
+                       {\r
+                               actionstart++;\r
+\r
+                               file1 = log.find(0,actionstart);\r
+                               if( file1>=0 )\r
                                {\r
-                                       action=action.Right(action.GetLength()-actionstart);\r
+                                       file1++;\r
+                                       pos=file1;\r
                                }\r
-                               pathname=one.Right(one.GetLength()-tabstart);\r
-                                               \r
-                               CTGitPath *GitPath=LookForGitPath(pathname);\r
-                                               \r
-                               if(GitPath)\r
+                               if( log[actionstart] == 'C' || log[actionstart] == 'R' )\r
                                {\r
-                                       this->m_Action|=GitPath->ParserAction(action);  \r
-                                                       \r
-                               }else\r
-                               {       \r
-                                       path.SetFromGit(pathname);\r
-                                       //action must be set after setfromgit. SetFromGit will clear all status. \r
-                                       this->m_Action|=path.ParserAction(action);\r
-                                       AddPath(path);\r
+                                       file2=file1;\r
+                                       numfile=2;\r
+                                       file1 = log.find(0,file1);\r
+                                       if(file1>=0 )\r
+                                       {\r
+                                               file1++;\r
+                                               pos=file1;\r
+                                       }\r
+\r
                                }\r
                        }\r
-                                       \r
+                       \r
+                       CString pathname1;\r
+                       CString pathname2;\r
+\r
+                       if( file1>=0 )\r
+                               g_Git.StringAppend(&pathname1,&log[file1],CP_ACP);\r
+                       if( file2>=0 )\r
+                               g_Git.StringAppend(&pathname2,&log[file2],CP_ACP);\r
+\r
+                       CTGitPath *GitPath=LookForGitPath(pathname1);\r
+\r
+                       if(GitPath)\r
+                       {\r
+                               GitPath->ParserAction( log[actionstart] );      \r
+                               \r
+                               if(merged)\r
+                               {\r
+                                       GitPath->m_Action |= CTGitPath::LOGACTIONS_MERGED;\r
+                                       GitPath->m_Action &= ~CTGitPath::LOGACTIONS_FORWORD;\r
+                               }\r
+                               m_Action |=GitPath->m_Action;\r
+\r
+                       }else\r
+                       {       \r
+                               int ac=path.ParserAction(log[actionstart] );\r
+                               ac |= merged?CTGitPath::LOGACTIONS_MERGED:0;    \r
+\r
+                               path.SetFromGit(pathname1,&pathname2);\r
+                               path.m_Action=ac;\r
+                                       //action must be set after setfromgit. SetFromGit will clear all status. \r
+                               this->m_Action|=ac;\r
+                               \r
+                               AddPath(path);\r
+                               \r
+                       }\r
+       \r
                }else\r
-               {\r
+               {                       \r
                        int tabstart=0;\r
                        path.Reset();\r
-                       CString StatAdd=(one.Tokenize(_T("\t"),tabstart));\r
-                       if( tabstart< 0)\r
-                               break;\r
-                       CString StatDel=(one.Tokenize(_T("\t"),tabstart));\r
-                       //SetFromGit will reset all context of GitRev\r
-                       path.SetFromGit(one.Right(one.GetLength()-tabstart));\r
+                       CString StatAdd;\r
+                       CString StatDel;\r
+                       CString file1;\r
+                       CString file2;\r
+\r
+                       tabstart=log.find('\t',pos);\r
+                       if(tabstart >=0)\r
+                       {\r
+                               log[tabstart]=0;\r
+                               g_Git.StringAppend(&StatAdd,&log[pos],CP_UTF8);\r
+                               pos=tabstart+1;\r
+                       }\r
+\r
+                       tabstart=log.find('\t',pos);\r
+                       if(tabstart >=0)\r
+                       {\r
+                               log[tabstart]=0;\r
                                \r
+                               g_Git.StringAppend(&StatDel,&log[pos],CP_UTF8);\r
+                               pos=tabstart+1;\r
+                       }\r
+                       \r
+                       if(log[pos] == 0) //rename\r
+                       {\r
+                               pos++;\r
+                               g_Git.StringAppend(&file2,&log[pos],CP_ACP);\r
+                               int sec=log.find(0,pos);\r
+                               if(sec>=0)\r
+                               {\r
+                                       sec++;\r
+                                       g_Git.StringAppend(&file1,&log[sec],CP_ACP);\r
+                               }\r
+                               pos=sec;\r
+\r
+                       }else\r
+                       {\r
+                               g_Git.StringAppend(&file1,&log[pos],CP_ACP);\r
+                       }\r
+                       path.SetFromGit(file1,&file2);\r
+       \r
                        CTGitPath *GitPath=LookForGitPath(path.GetGitPathString());\r
                        if(GitPath)\r
                        {\r
@@ -898,9 +1176,12 @@ int CTGitPathList::ParserFromLog(CString &log)
                                //path.SetFromGit(pathname);\r
                                path.m_StatAdd=StatAdd;\r
                                path.m_StatDel=StatDel;\r
+                               path.m_Action |= CTGitPath::LOGACTIONS_FORWORD;\r
                                AddPath(path);\r
                        }\r
+\r
                }\r
+               pos=log.findNextString(pos);\r
        }\r
        return pos;\r
 }\r
@@ -1103,6 +1384,9 @@ CTGitPath CTGitPathList::GetCommonRoot() const
        int searchStartPos = 0;\r
        while (bEqual)\r
        {\r
+               if(m_paths.empty())\r
+                       break;\r
+\r
                for (it = m_paths.begin(); it != m_paths.end(); ++it)\r
                {\r
                        if (backSlashPos == 0)\r
@@ -1688,21 +1972,45 @@ CTGitPath * CTGitPathList::LookForGitPath(CString path)
        }\r
        return NULL;\r
 }\r
-\r
-CString CTGitPath::GetActionName()\r
+CString CTGitPath::GetActionName(int action)\r
 {\r
-       if(m_Action  & CTGitPath::LOGACTIONS_ADDED)\r
+       if(action  & CTGitPath::LOGACTIONS_UNMERGED)\r
+               return _T("Conflict");\r
+       if(action  & CTGitPath::LOGACTIONS_ADDED)\r
                return _T("Added");\r
-       if(m_Action  & CTGitPath::LOGACTIONS_DELETED)\r
+       if(action  & CTGitPath::LOGACTIONS_DELETED)\r
                return _T("Deleted");\r
-       if(m_Action  & CTGitPath::LOGACTIONS_MODIFIED)\r
+       if(action  & CTGitPath::LOGACTIONS_MERGED )\r
+               return _T("Merged");\r
+\r
+       if(action  & CTGitPath::LOGACTIONS_MODIFIED)\r
                return _T("Modified");\r
-       if(m_Action  & CTGitPath::LOGACTIONS_REPLACED)\r
+       if(action  & CTGitPath::LOGACTIONS_REPLACED)\r
                return _T("Rename");\r
+       if(action  & CTGitPath::LOGACTIONS_COPY)\r
+               return _T("Copy");\r
+\r
+       if(action  & CTGitPath::LOGACTIONS_FORWORD )\r
+               return _T("Forward");\r
+\r
+       if(action & CTGitPath::LOGACTIONS_REBASE_EDIT)\r
+               return _T("Edit");\r
+       if(action & CTGitPath::LOGACTIONS_REBASE_SQUASH)\r
+               return _T("Squash");\r
+       if(action & CTGitPath::LOGACTIONS_REBASE_PICK)\r
+               return _T("Pick");\r
+       if(action & CTGitPath::LOGACTIONS_REBASE_SKIP)\r
+               return _T("Skip");\r
+\r
        return _T("Unknown");\r
 }\r
+CString CTGitPath::GetActionName()\r
+{\r
+       return GetActionName(m_Action);\r
+}\r
 \r
 int CTGitPathList::GetAction()\r
 {\r
        return m_Action;\r
 }\r
+\r