int GitRev::GetParentFromHash(const CGitHash& hash) { CAutoLocker lock(g_Git.m_critGitDllSec); GIT_COMMIT commit; try { g_Git.CheckAndInitDll(); if (git_get_commit_from_hash(&commit, hash.m_hash)) { m_sErr = L"git_get_commit_from_hash failed for " + hash.ToString(); return -1; } } catch (char* msg) { m_sErr = L"Could not get parents of commit \"" + hash.ToString() + L"\".\nlibgit reports:\n" + CString(msg); return -1; } this->ParserParentFromCommit(&commit); git_free_commit(&commit); this->m_CommitHash=hash; return 0; }
int CLogDataVector::Fill(std::set<CGitHash>& hashes) { ATLASSERT(m_pLogCache); try { [] { git_init(); } (); } catch (const char* msg) { MessageBox(nullptr, _T("Could not initialize libgit.\nlibgit reports:\n") + CString(msg), _T("TortoiseGit"), MB_ICONERROR); return -1; } std::set<GitRevLoglist*, SortByParentDate> revs; for (auto it = hashes.begin(); it != hashes.end(); ++it) { CGitHash hash = *it; GIT_COMMIT commit; try { CAutoLocker lock(g_Git.m_critGitDllSec); if (git_get_commit_from_hash(&commit, hash.m_hash)) { return -1; } } catch (char * msg) { MessageBox(nullptr, _T("Could not get commit \"") + hash.ToString() + _T("\".\nlibgit reports:\n") + CString(msg), _T("TortoiseGit"), MB_ICONERROR); return -1; } GitRevLoglist* pRev = this->m_pLogCache->GetCacheData(hash); // right now this code is only used by TortoiseGitBlame, // as such git notes are not needed to be loaded pRev->ParserFromCommit(&commit); pRev->ParserParentFromCommit(&commit); git_free_commit(&commit); revs.insert(pRev); } for (auto it = revs.begin(); it != revs.end(); ++it) { GitRev *pRev = *it; this->push_back(pRev->m_CommitHash); m_HashMap[pRev->m_CommitHash] = (int)size() - 1; } return 0; }
int GitRev::GetCommitFromHash_withoutLock(CGitHash &hash) { GIT_COMMIT commit; if(git_get_commit_from_hash( &commit, hash.m_hash)) return -1; this->ParserFromCommit(&commit); git_free_commit(&commit); return 0; }
int CLogDataVector::Fill(std::unordered_set<CGitHash>& hashes) { ATLASSERT(m_pLogCache); try { [] { git_init(); } (); } catch (const char* msg) { MessageBox(nullptr, L"Could not initialize libgit.\nlibgit reports:\n" + CString(msg), L"TortoiseGit", MB_ICONERROR); return -1; } std::set<GitRevLoglist*, SortByParentDate> revs; for (const auto& hash : hashes) { GIT_COMMIT commit; try { CAutoLocker lock(g_Git.m_critGitDllSec); if (git_get_commit_from_hash(&commit, hash.ToRaw())) return -1; } catch (char * msg) { MessageBox(nullptr, L"Could not get commit \"" + hash.ToString() + L"\".\nlibgit reports:\n" + CString(msg), L"TortoiseGit", MB_ICONERROR); return -1; } GitRevLoglist* pRev = this->m_pLogCache->GetCacheData(hash); // right now this code is only used by TortoiseGitBlame, // as such git notes are not needed to be loaded pRev->ParserFromCommit(&commit); pRev->ParserParentFromCommit(&commit); git_free_commit(&commit); revs.insert(pRev); } for (const auto& pRev : revs) { this->push_back(pRev->m_CommitHash); m_HashMap[pRev->m_CommitHash] = static_cast<int>(size()) - 1; } return 0; }
int GitRev::GetParentFromHash(CGitHash &hash) { CAutoLocker lock(g_Git.m_critGitDllSec); g_Git.CheckAndInitDll(); GIT_COMMIT commit; if(git_get_commit_from_hash( &commit, hash.m_hash)) return -1; this->ParserParentFromCommit(&commit); git_free_commit(&commit); this->m_CommitHash=hash; return 0; }
int GitRev::GetCommitFromHash_withoutLock(CGitHash &hash) { GIT_COMMIT commit; try { if (git_get_commit_from_hash(&commit, hash.m_hash)) return -1; } catch (char * msg) { MessageBox(NULL, _T("Could not get commit \"") + hash.ToString() + _T("\".\nlibgit reports:\n") + CString(msg), _T("TortoiseGit"), MB_ICONERROR); return -1; } this->ParserFromCommit(&commit); git_free_commit(&commit); return 0; }
int GitRev::GetCommitFromHash_withoutLock(const CGitHash& hash) { GIT_COMMIT commit; try { if (git_get_commit_from_hash(&commit, hash.m_hash)) { m_sErr = L"git_get_commit_from_hash failed for " + hash.ToString(); return -1; } } catch (char * msg) { m_sErr = L"Could not get commit \"" + hash.ToString() + L"\".\nlibgit reports:\n" + CString(msg); return -1; } this->ParserFromCommit(&commit); git_free_commit(&commit); m_sErr.Empty(); 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 GitRev::SafeGetSimpleList(CGit *git) { if(InterlockedExchange(&m_IsUpdateing,TRUE) == FALSE) { m_SimpleFileList.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; bool isRoot = this->m_ParentHash.empty(); git_get_commit_first_parent(&commit,&list); while(git_get_commit_next_parent(&list,parent) == 0 || isRoot) { GIT_FILE file=0; int count=0; try { if(isRoot) git_root_diff(git->GetGitSimpleListDiff(), commit.m_hash, &file, &count, 0); else git_diff(git->GetGitSimpleListDiff(), parent, commit.m_hash, &file, &count, 0); } catch (char *) { 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; try { git_get_diff_file(git->GetGitSimpleListDiff(), file, j, &newname, &oldname, &mode, &IsBin, &inc, &dec); } catch (char *) { return -1; } git->StringAppend(&strnewname, (BYTE*)newname, CP_UTF8); m_SimpleFileList.push_back(strnewname); } git_diff_flush(git->GetGitSimpleListDiff()); ++i; } InterlockedExchange(&m_IsUpdateing,FALSE); InterlockedExchange(&m_IsSimpleListReady, TRUE); git_free_commit(&commit); } return 0; }
//CLogDataVector Class int CLogDataVector::ParserFromLog(CTGitPath *path ,int count ,int infomask,CString *from,CString *to) { // only enable --follow on files if ((path == NULL || path->IsDirectory()) && (infomask & CGit::LOG_INFO_FOLLOW)) infomask = infomask ^ CGit::LOG_INFO_FOLLOW; CString hash; CString cmd=g_Git.GetLogCmd(hash,path,count,infomask,from,to,true); if(g_Git.IsInitRepos()) return 0; git_init(); GIT_LOG handle; if(git_open_log(&handle,CUnicodeUtils::GetMulti(cmd,CP_ACP).GetBuffer())) { return -1; } git_get_log_firstcommit(handle); GIT_COMMIT commit; GitRev rev; while (git_get_log_nextcommit(handle, &commit, infomask & CGit::LOG_INFO_FOLLOW) == 0) { if (commit.m_ignore == 1) { git_free_commit(&commit); continue; } CGitHash hash = (char*)commit.m_hash ; rev.Clear(); GitRev *pRev = this->m_pLogCache->GetCacheData(hash); char *note=NULL; git_get_notes(commit.m_hash,¬e); if(note) { pRev->m_Notes.Empty(); g_Git.StringAppend(&pRev->m_Notes,(BYTE*)note); } if(pRev == NULL || !pRev->m_IsFull) { pRev->ParserFromCommit(&commit); pRev->ParserParentFromCommit(&commit); git_free_commit(&commit); //Must call free commit before SafeFetchFullInfo, commit parent is rewrite by log. //file list will wrong if parent rewrite. pRev->SafeFetchFullInfo(&g_Git); } else { ASSERT(pRev->m_CommitHash == hash); pRev->ParserParentFromCommit(&commit); git_free_commit(&commit); } this->push_back(pRev->m_CommitHash); m_HashMap[rev.m_CommitHash]=size()-1; } git_close_log(handle); return 0; }
//CLogDataVector Class int CLogDataVector::ParserFromLog(CTGitPath* path, DWORD count, DWORD infomask, CString* range) { ATLASSERT(m_pLogCache); // only enable --follow on files if ((!path || path->IsDirectory()) && (infomask & CGit::LOG_INFO_FOLLOW)) infomask = infomask ^ CGit::LOG_INFO_FOLLOW; CString gitrange = L"HEAD"; if (range != nullptr) gitrange = *range; CFilterData filter; if (count == 0) filter.m_NumberOfLogsScale = CFilterData::SHOW_NO_LIMIT; else { filter.m_NumberOfLogs = count; filter.m_NumberOfLogsScale = CFilterData::SHOW_LAST_N_COMMITS; } CString cmd = g_Git.GetLogCmd(gitrange, path, infomask, &filter, m_logOrderBy); if (!g_Git.CanParseRev(gitrange)) return -1; try { [] { git_init(); } (); } catch (const char* msg) { MessageBox(nullptr, L"Could not initialize libgit.\nlibgit reports:\n" + CString(msg), L"TortoiseGit", MB_ICONERROR); return -1; } GIT_LOG handle; try { CAutoLocker lock(g_Git.m_critGitDllSec); if (git_open_log(&handle, CUnicodeUtils::GetMulti(cmd, CP_UTF8))) return -1; } catch (char* msg) { MessageBox(nullptr, L"Could not open log.\nlibgit reports:\n" + CString(msg), L"TortoiseGit", MB_ICONERROR); return -1; } try { CAutoLocker lock(g_Git.m_critGitDllSec); [&]{ git_get_log_firstcommit(handle); }(); } catch (char* msg) { MessageBox(nullptr, L"Could not get first commit.\nlibgit reports:\n" + CString(msg), L"TortoiseGit", MB_ICONERROR); return -1; } int ret = 0; while (ret == 0) { GIT_COMMIT commit; try { CAutoLocker lock(g_Git.m_critGitDllSec); [&]{ ret = git_get_log_nextcommit(handle, &commit, infomask & CGit::LOG_INFO_FOLLOW); }(); } catch (char* msg) { MessageBox(nullptr, L"Could not get next commit.\nlibgit reports:\n" + CString(msg), L"TortoiseGit", MB_ICONERROR); break; } if (ret) { if (ret != -2) // other than end of revision walking MessageBox(nullptr, (L"Could not get next commit.\nlibgit returns:" + std::to_wstring(ret)).c_str(), L"TortoiseGit", MB_ICONERROR); break; } if (commit.m_ignore == 1) { git_free_commit(&commit); continue; } CGitHash hash = CGitHash::FromRaw(commit.m_hash); GitRevLoglist* pRev = this->m_pLogCache->GetCacheData(hash); char *pNote = nullptr; { CAutoLocker lock(g_Git.m_critGitDllSec); git_get_notes(commit.m_hash, &pNote); } if (pNote) { pRev->m_Notes = CUnicodeUtils::GetUnicode(pNote); free(pNote); pNote = nullptr; } pRev->ParserFromCommit(&commit); pRev->ParserParentFromCommit(&commit); git_free_commit(&commit); // Must call free commit before SafeFetchFullInfo, commit parent is rewrite by log. // file list will wrong if parent rewrite. if (!pRev->m_IsFull && (infomask & CGit::LOG_INFO_FULL_DIFF)) { if (pRev->SafeFetchFullInfo(&g_Git)) { MessageBox(nullptr, pRev->GetLastErr(), L"TortoiseGit", MB_ICONERROR); return -1; } } this->push_back(pRev->m_CommitHash); m_HashMap[pRev->m_CommitHash] = static_cast<int>(size()) - 1; } { CAutoLocker lock(g_Git.m_critGitDllSec); git_close_log(handle); } return 0; }
//CLogDataVector Class int CLogDataVector::ParserFromLog(CTGitPath *path, int count, int infomask, CString *range) { // only enable --follow on files if ((path == NULL || path->IsDirectory()) && (infomask & CGit::LOG_INFO_FOLLOW)) infomask = infomask ^ CGit::LOG_INFO_FOLLOW; CString gitrange = _T("HEAD"); if (range != nullptr) gitrange = *range; CString cmd = g_Git.GetLogCmd(gitrange, path, count, infomask, true); if (!g_Git.CanParseRev(gitrange)) return 0; try { [] { git_init(); } (); } catch (const char* msg) { MessageBox(NULL, _T("Could not initialize libgit.\nlibgit reports:\n") + CString(msg), _T("TortoiseGit"), MB_ICONERROR); return -1; } GIT_LOG handle; try { CAutoLocker lock(g_Git.m_critGitDllSec); if (git_open_log(&handle,CUnicodeUtils::GetMulti(cmd, CP_UTF8).GetBuffer())) { return -1; } } catch (char* msg) { MessageBox(NULL, _T("Could not open log.\nlibgit reports:\n") + CString(msg), _T("TortoiseGit"), MB_ICONERROR); return -1; } try { CAutoLocker lock(g_Git.m_critGitDllSec); [&]{ git_get_log_firstcommit(handle); }(); } catch (char* msg) { MessageBox(NULL, _T("Could not get first commit.\nlibgit reports:\n") + CString(msg), _T("TortoiseGit"), MB_ICONERROR); return -1; } int ret = 0; while (ret == 0) { GIT_COMMIT commit; try { CAutoLocker lock(g_Git.m_critGitDllSec); [&]{ ret = git_get_log_nextcommit(handle, &commit, infomask & CGit::LOG_INFO_FOLLOW); }(); } catch (char* msg) { MessageBox(NULL, _T("Could not get next commit.\nlibgit reports:\n") + CString(msg), _T("TortoiseGit"), MB_ICONERROR); break; } if (ret) { if (ret != -2) // other than end of revision walking MessageBox(nullptr, (_T("Could not get next commit.\nlibgit returns:") + std::to_wstring(ret)).c_str(), _T("TortoiseGit"), MB_ICONERROR); break; } if (commit.m_ignore == 1) { git_free_commit(&commit); continue; } CGitHash hash = (char*)commit.m_hash ; GitRevLoglist* pRev = this->m_pLogCache->GetCacheData(hash); char *pNote = nullptr; { CAutoLocker lock(g_Git.m_critGitDllSec); git_get_notes(commit.m_hash, &pNote); } if (pNote) { pRev->m_Notes = CUnicodeUtils::GetUnicode(pNote); free(pNote); pNote = nullptr; } ASSERT(pRev->m_CommitHash == hash); pRev->ParserFromCommit(&commit); pRev->ParserParentFromCommit(&commit); git_free_commit(&commit); // Must call free commit before SafeFetchFullInfo, commit parent is rewrite by log. // file list will wrong if parent rewrite. if (!pRev->m_IsFull && (infomask & CGit::LOG_INFO_FULL_DIFF)) { if (pRev->SafeFetchFullInfo(&g_Git)) { MessageBox(nullptr, pRev->GetLastErr(), _T("TortoiseGit"), MB_ICONERROR); return -1; } } this->push_back(pRev->m_CommitHash); m_HashMap[pRev->m_CommitHash] = (int)size() - 1; } { CAutoLocker lock(g_Git.m_critGitDllSec); git_close_log(handle); } return 0; }