int CGit::GetDiffPath(CTGitPathList *PathList, CGitHash *hash1, CGitHash *hash2, char *arg) { GIT_FILE file=0; int ret=0; GIT_DIFF diff=0; CAutoLocker lock(g_Git.m_critGitDllSec); if(arg == NULL) diff = GetGitDiff(); else git_open_diff(&diff, arg); if(diff ==NULL) return -1; bool isStat = 0; if(arg == NULL) isStat = true; else isStat = !!strstr(arg, "stat"); int count=0; if(hash2 == NULL) ret = git_root_diff(diff, hash1->m_hash, &file, &count,isStat); else ret = git_diff(diff,hash2->m_hash,hash1->m_hash,&file,&count,isStat); if(ret) return -1; CTGitPath path; CString strnewname; CString stroldname; for(int j=0;j<count;j++) { path.Reset(); char *newname; char *oldname; strnewname.Empty(); stroldname.Empty(); int mode=0,IsBin=0,inc=0,dec=0; git_get_diff_file(diff,file,j,&newname,&oldname, &mode,&IsBin,&inc,&dec); StringAppend(&strnewname, (BYTE*)newname, CP_UTF8); StringAppend(&stroldname, (BYTE*)oldname, CP_UTF8); path.SetFromGit(strnewname,&stroldname); path.ParserAction((BYTE)mode); if(IsBin) { path.m_StatAdd=_T("-"); path.m_StatDel=_T("-"); } else { path.m_StatAdd.Format(_T("%d"),inc); path.m_StatDel.Format(_T("%d"),dec); } PathList->AddPath(path); } git_diff_flush(diff); if(arg) git_close_diff(diff); return 0; }
int GitRev::SafeFetchFullInfo(CGit *git) { if(InterlockedExchange(&m_IsUpdateing,TRUE) == FALSE) { this->m_Files.Clear(); git->CheckAndInitDll(); GIT_COMMIT commit; GIT_COMMIT_LIST list; GIT_HASH parent; memset(&commit,0,sizeof(GIT_COMMIT)); CAutoLocker lock(g_Git.m_critGitDllSec); try { if (git_get_commit_from_hash(&commit, this->m_CommitHash.m_hash)) return -1; } catch (char *) { return -1; } int i=0; git_get_commit_first_parent(&commit,&list); bool isRoot = (list==NULL); while(git_get_commit_next_parent(&list,parent) == 0 || isRoot) { GIT_FILE file=0; int count=0; try { if (isRoot) git_root_diff(git->GetGitDiff(), this->m_CommitHash.m_hash, &file, &count, 1); else git_diff(git->GetGitDiff(), parent, commit.m_hash, &file, &count, 1); } catch (char *) { git_free_commit(&commit); return -1; } isRoot = false; CTGitPath path; CString strnewname; CString stroldname; for (int j = 0; j < count; ++j) { path.Reset(); char *newname; char *oldname; strnewname.Empty(); stroldname.Empty(); int mode,IsBin,inc,dec; git_get_diff_file(git->GetGitDiff(),file,j,&newname,&oldname, &mode,&IsBin,&inc,&dec); git->StringAppend(&strnewname, (BYTE*)newname, CP_UTF8); git->StringAppend(&stroldname, (BYTE*)oldname, CP_UTF8); path.SetFromGit(strnewname,&stroldname); path.ParserAction((BYTE)mode); path.m_ParentNo = i; this->m_Action|=path.m_Action; if(IsBin) { path.m_StatAdd=_T("-"); path.m_StatDel=_T("-"); } else { path.m_StatAdd.Format(_T("%d"),inc); path.m_StatDel.Format(_T("%d"),dec); } m_Files.AddPath(path); } git_diff_flush(git->GetGitDiff()); ++i; } InterlockedExchange(&m_IsUpdateing,FALSE); InterlockedExchange(&m_IsFull,TRUE); git_free_commit(&commit); } return 0; }
int CTGitPathList::ParserFromLog(BYTE_VECTOR &log, bool parseDeletes /*false*/) { this->Clear(); std::map<CString, size_t> duplicateMap; int pos=0; CTGitPath path; m_Action=0; int logend = (int)log.size(); while (pos >= 0 && pos < logend) { path.Reset(); if(log[pos]=='\n') ++pos; if (pos >= logend) return -1; if(log[pos]==':') { bool merged=false; if (pos + 1 >= logend) return -1; if(log[pos+1] ==':') { merged=true; } int end=log.find(0,pos); int actionstart=-1; int file1=-1,file2=-1; if( end>0 ) { actionstart=log.find(' ',end-6); pos=actionstart; } if( actionstart>0 ) { ++actionstart; if (actionstart >= logend) return -1; file1 = log.find(0,actionstart); if( file1>=0 ) { ++file1; pos=file1; } if( log[actionstart] == 'C' || log[actionstart] == 'R' ) { file2=file1; file1 = log.find(0,file1); if(file1>=0 ) { ++file1; pos=file1; } } } CString pathname1; CString pathname2; if( file1>=0 ) CGit::StringAppend(&pathname1, &log[file1], CP_UTF8); if( file2>=0 ) CGit::StringAppend(&pathname2, &log[file2], CP_UTF8); if (actionstart < 0) return -1; auto existing = duplicateMap.find(pathname1); if (existing != duplicateMap.end()) { CTGitPath& p = m_paths[existing->second]; p.ParserAction(log[actionstart]); if(merged) p.m_Action |= CTGitPath::LOGACTIONS_MERGED; m_Action |= p.m_Action; } else { int ac=path.ParserAction(log[actionstart] ); ac |= merged?CTGitPath::LOGACTIONS_MERGED:0; path.SetFromGit(pathname1,&pathname2); path.m_Action=ac; //action must be set after setfromgit. SetFromGit will clear all status. this->m_Action|=ac; AddPath(path); duplicateMap.insert(std::pair<CString, size_t>(path.GetGitPathString(), m_paths.size() - 1)); } } else { int tabstart=0; path.Reset(); CString StatAdd; CString StatDel; CString file1; CString file2; tabstart=log.find('\t',pos); if(tabstart >=0) { log[tabstart]=0; CGit::StringAppend(&StatAdd, &log[pos], CP_UTF8); pos=tabstart+1; } tabstart=log.find('\t',pos); if(tabstart >=0) { log[tabstart]=0; CGit::StringAppend(&StatDel, &log[pos], CP_UTF8); pos=tabstart+1; } if(log[pos] == 0) //rename { ++pos; CGit::StringAppend(&file2, &log[pos], CP_UTF8); int sec=log.find(0,pos); if(sec>=0) { ++sec; CGit::StringAppend(&file1, &log[sec], CP_UTF8); } pos=sec; } else { CGit::StringAppend(&file1, &log[pos], CP_UTF8); } path.SetFromGit(file1,&file2); auto existing = duplicateMap.find(path.GetGitPathString()); if (existing != duplicateMap.end()) { CTGitPath& p = m_paths[existing->second]; p.m_StatAdd = StatAdd; p.m_StatDel = StatDel; } else { //path.SetFromGit(pathname); if (parseDeletes) { path.m_StatAdd=_T("0"); path.m_StatDel=_T("0"); path.m_Action |= CTGitPath::LOGACTIONS_DELETED | CTGitPath::LOGACTIONS_MISSING; } else { path.m_StatAdd=StatAdd; path.m_StatDel=StatDel; } AddPath(path); duplicateMap.insert(std::pair<CString, size_t>(path.GetGitPathString(), m_paths.size() - 1)); } } pos=log.findNextString(pos); } return 0; }