int CGitHeadFileMap::IsUnderVersionControl(const CString &gitdir, const CString &path, bool isDir, bool *isVersion) { try { if (path.IsEmpty()) { *isVersion = true; return 0; } CString subpath = path; subpath.Replace(_T('\\'), _T('/')); if(isDir) subpath += _T('/'); subpath.MakeLower(); CheckHeadAndUpdate(gitdir); SHARED_TREE_PTR treeptr = SafeGet(gitdir); // Init Repository if (treeptr->HeadFileIsEmpty()) { *isVersion = false; return 0; } else if (treeptr->empty()) { *isVersion = false; return 1; } if(isDir) *isVersion = (SearchInSortVector(*treeptr, subpath, subpath.GetLength()) >= 0); else *isVersion = (SearchInSortVector(*treeptr, subpath, -1) >= 0); } catch(...) { return -1; } return 0; }
int GitStatus::GetDirStatus(const CString &gitdir, const CString &subpath, git_wc_status_kind * status, BOOL IsFul, BOOL IsRecursive, BOOL IsIgnore, FILL_STATUS_CALLBACK callback, void *pData) { try { CString path =subpath; path.Replace(_T('\\'),_T('/')); if(!path.IsEmpty()) if(path[path.GetLength()-1] != _T('/')) path += _T('/'); //Add trail / to show it is directory, not file name. CString lowcasepath = path; lowcasepath.MakeLower(); if(status) { g_IndexFileMap.CheckAndUpdate(gitdir, true); SHARED_INDEX_PTR indexptr = g_IndexFileMap.SafeGet(gitdir); if (indexptr == NULL) { *status = git_wc_status_unversioned; return 0; } int pos = SearchInSortVector(*indexptr, lowcasepath, lowcasepath.GetLength()); //Not In Version Contorl if(pos<0) { if(!IsIgnore) { *status = git_wc_status_unversioned; if(callback) callback(gitdir + _T("/") + path, *status, false, pData, false, false); return 0; } //Check ignore always. { if (g_IgnoreList.CheckIgnoreChanged(gitdir, path, true)) g_IgnoreList.LoadAllIgnoreFile(gitdir, path, true); if (g_IgnoreList.IsIgnore(path, gitdir, true)) *status = git_wc_status_ignored; else *status = git_wc_status_unversioned; g_HeadFileMap.CheckHeadAndUpdate(gitdir, false); SHARED_TREE_PTR treeptr = g_HeadFileMap.SafeGet(gitdir); //Check init repository if (treeptr->HeadIsEmpty() && path.IsEmpty()) *status = git_wc_status_normal; } } else // In version control { *status = git_wc_status_normal; int start=0; int end=0; if(path.IsEmpty()) { start=0; end = (int)indexptr->size() - 1; } GetRangeInSortVector(*indexptr, lowcasepath, lowcasepath.GetLength(), &start, &end, pos); CGitIndexList::iterator it; it = indexptr->begin()+start; // Check Conflict; for (int i = start; i <= end; ++i) { if (((*it).m_Flags & GIT_IDXENTRY_STAGEMASK) !=0) { *status = git_wc_status_conflicted; if(callback) { int dirpos = (*it).m_FileName.Find(_T('/'), path.GetLength()); if(dirpos<0 || IsRecursive) callback(gitdir + _T("\\") + it->m_FileName, git_wc_status_conflicted, false, pData, false, false); } else break; } ++it; } if( IsFul && (*status != git_wc_status_conflicted)) { *status = git_wc_status_normal; g_HeadFileMap.CheckHeadAndUpdate(gitdir); //Check Add it = indexptr->begin()+start; { //Check if new init repository SHARED_TREE_PTR treeptr = g_HeadFileMap.SafeGet(gitdir); if (!treeptr->empty() || treeptr->HeadIsEmpty()) { for (int i = start; i<= end; ++i) { pos = SearchInSortVector(*treeptr, (*it).m_FileName, -1); if(pos < 0) { *status = max(git_wc_status_added, *status); // added file found if(callback) { int dirpos = (*it).m_FileName.Find(_T('/'), path.GetLength()); if(dirpos<0 || IsRecursive) callback(gitdir + _T("\\") + it->m_FileName, git_wc_status_added, false, pData, false, false); } else break; } if( pos>=0 && treeptr->at(pos).m_Hash != (*it).m_IndexHash) { *status = max(git_wc_status_modified, *status); // modified file found if(callback) { int dirpos = (*it).m_FileName.Find(_T('/'), path.GetLength()); if(dirpos<0 || IsRecursive) callback(gitdir + _T("\\") + it->m_FileName, git_wc_status_modified, false, pData, ((*it).m_Flags & GIT_IDXENTRY_VALID) && !((*it).m_Flags & GIT_IDXENTRY_SKIP_WORKTREE), ((*it).m_Flags & GIT_IDXENTRY_SKIP_WORKTREE) != 0); } else break; } ++it; } //Check Delete if( *status == git_wc_status_normal ) { pos = SearchInSortVector(*treeptr, lowcasepath, lowcasepath.GetLength()); if(pos <0) { *status = max(git_wc_status_added, *status); // added file found } else { int hstart,hend; GetRangeInSortVector(*treeptr, lowcasepath, lowcasepath.GetLength(), &hstart, &hend, pos); CGitHeadFileList::iterator hit; hit = treeptr->begin() + hstart; CGitHeadFileList::iterator lastElement = treeptr->end(); for (int i = hstart; i <= hend && hit != lastElement; ++i) { if (SearchInSortVector(*indexptr, (*hit).m_FileName, -1) < 0) { *status = max(git_wc_status_deleted, *status); // deleted file found break; } ++hit; } } } } }/* End lock*/ } // If define callback, it need update each file status. // If not define callback, status == git_wc_status_conflicted, needn't check each file status // because git_wc_status_conflicted is highest.s if(callback || (*status != git_wc_status_conflicted)) { //Check File Time; //if(IsRecursive) { CString sub, currentPath; it = indexptr->begin()+start; for (int i = start; i <= end; ++i, ++it) { if( !IsRecursive ) { //skip child directory int pos = (*it).m_FileName.Find(_T('/'), path.GetLength()); if( pos > 0) { currentPath = (*it).m_FileName.Left(pos); if( callback && (sub != currentPath) ) { sub = currentPath; CTraceToOutputDebugString::Instance()(_T(__FUNCTION__) _T(": index subdir %s\n"),sub); if(callback) callback(gitdir + _T("\\") + sub, git_wc_status_normal, true, pData, false, false); } continue; } } git_wc_status_kind filestatus = git_wc_status_none; bool assumeValid = false; bool skipWorktree = false; GetFileStatus(gitdir, (*it).m_FileName, &filestatus, IsFul, IsRecursive, IsIgnore, callback, pData, &assumeValid, &skipWorktree); } } } } if(callback) callback(gitdir + _T("/") + subpath, *status, true, pData, false, false); } }catch(...) { if(status) *status = git_wc_status_none; return -1; } return 0; }
int GitStatus::GetDirStatus(const CString& gitdir, const CString& subpath, git_wc_status_kind* status, BOOL IsFul, BOOL IsRecursive, BOOL IsIgnore) { if (!status) return 0; CString path = subpath; path.Replace(_T('\\'), _T('/')); if (!path.IsEmpty() && path[path.GetLength() - 1] != _T('/')) path += _T('/'); //Add trail / to show it is directory, not file name. g_IndexFileMap.CheckAndUpdate(gitdir, true); SHARED_INDEX_PTR indexptr = g_IndexFileMap.SafeGet(gitdir); if (!indexptr) { *status = git_wc_status_unversioned; return 0; } CString lowcasepath = path; lowcasepath.MakeLower(); int pos = SearchInSortVector(*indexptr, lowcasepath, lowcasepath.GetLength()); // Not In Version Contorl if (pos < 0) { if (!IsIgnore) { *status = git_wc_status_unversioned; return 0; } // Check ignore always. if (g_IgnoreList.CheckIgnoreChanged(gitdir, path, true)) g_IgnoreList.LoadAllIgnoreFile(gitdir, path, true); if (g_IgnoreList.IsIgnore(path, gitdir, true)) *status = git_wc_status_ignored; else *status = git_wc_status_unversioned; g_HeadFileMap.CheckHeadAndUpdate(gitdir); SHARED_TREE_PTR treeptr = g_HeadFileMap.SafeGet(gitdir); // Check init repository if (treeptr->HeadIsEmpty() && path.IsEmpty()) *status = git_wc_status_normal; // check if only one file in repository is deleted in index else if (path.IsEmpty() && !treeptr->empty()) *status = git_wc_status_deleted; return 0; } // In version control *status = git_wc_status_normal; int start = 0; int end = 0; GetRangeInSortVector(*indexptr, lowcasepath, lowcasepath.GetLength(), &start, &end, pos); // Check Conflict; for (auto it = indexptr->cbegin() + start, itlast = indexptr->cbegin() + end; indexptr->m_bHasConflicts && it <= itlast; ++it) { if (((*it).m_Flags & GIT_IDXENTRY_STAGEMASK) != 0) { *status = git_wc_status_conflicted; break; } } if (IsFul && (*status != git_wc_status_conflicted)) { *status = git_wc_status_normal; g_HeadFileMap.CheckHeadAndUpdate(gitdir); // Check Add { // Check if new init repository SHARED_TREE_PTR treeptr = g_HeadFileMap.SafeGet(gitdir); if (!treeptr->empty() || treeptr->HeadIsEmpty()) { for (auto it = indexptr->cbegin() + start, itlast = indexptr->cbegin() + end; it <= itlast; ++it) { pos = SearchInSortVector(*treeptr, (*it).m_FileName, -1); if (pos < 0) { *status = max(git_wc_status_added, *status); // added file found break; } if (pos >= 0 && treeptr->at(pos).m_Hash != (*it).m_IndexHash) { *status = max(git_wc_status_modified, *status); // modified file found break; } } // Check Delete if (*status == git_wc_status_normal) { pos = SearchInSortVector(*treeptr, lowcasepath, lowcasepath.GetLength()); if (pos < 0) *status = max(git_wc_status_added, *status); // added file found else { int hstart, hend; GetRangeInSortVector(*treeptr, lowcasepath, lowcasepath.GetLength(), &hstart, &hend, pos); for (auto hit = treeptr->cbegin() + hstart, lastElement = treeptr->cbegin() + hend; hit <= lastElement; ++hit) { if (SearchInSortVector(*indexptr, (*hit).m_FileName, -1) < 0) { *status = max(git_wc_status_deleted, *status); // deleted file found break; } } } } } } /* End lock*/ } // When status == git_wc_status_conflicted, needn't check each file status // because git_wc_status_conflicted is highest.s if (*status == git_wc_status_conflicted) return 0; for (auto it = indexptr->cbegin() + start, itlast = indexptr->cbegin() + end; it <= itlast; ++it) { //skip child directory if (!IsRecursive && (*it).m_FileName.Find(_T('/'), path.GetLength()) > 0) continue; git_wc_status_kind filestatus = git_wc_status_none; bool assumeValid = false; bool skipWorktree = false; GetFileStatus(gitdir, (*it).m_FileName, &filestatus, IsFul, IsRecursive, IsIgnore, nullptr, nullptr, &assumeValid, &skipWorktree); switch (filestatus) { case git_wc_status_added: case git_wc_status_modified: case git_wc_status_deleted: case git_wc_status_conflicted: *status = GetMoreImportant(filestatus, *status); } } return 0; }