git_revnum_t GitStatus::GetStatus(const CTGitPath& path, bool update /* = false */, bool noignore /* = false */, bool noexternals /* = false */) { // NOTE: unlike the SVN version this one does not cache the enumerated files, because in practice no code in all of // Tortoise uses this, all places that call GetStatus create a temp GitStatus object which gets destroyed right // after the call again // apr_hash_t * statushash; // apr_hash_t * exthash; // apr_array_header_t * statusarray; // const sort_item* item; // git_error_clear(m_err); // statushash = apr_hash_make(m_pool); // exthash = apr_hash_make(m_pool); git_revnum_t youngest = GIT_INVALID_REVNUM; // git_opt_revision_t rev; // rev.kind = git_opt_revision_unspecified; CString sProjectRoot; if ( !path.HasAdminDir(&sProjectRoot) ) return youngest; struct hashbaton_t hashbaton; // hashbaton.hash = statushash; // hashbaton.exthash = exthash; hashbaton.pThis = this; #ifdef _TORTOISESHELL if (g_ShellCache.GetCacheType() == ShellCache::dll) #else if ((DWORD)CRegStdWORD(_T("Software\\TortoiseGit\\CacheType"), GetSystemMetrics(SM_REMOTESESSION) ? 2 : 1) == 2) #endif { // gitindex.h based status CString sSubPath; CString s = path.GetWinPathString(); if (s.GetLength() > sProjectRoot.GetLength()) { sSubPath = CString(s.Right(s.GetLength() - sProjectRoot.GetLength() - 1/*otherwise it gets initial slash*/)); } m_status.prop_status = m_status.text_status = git_wc_status_none; m_err = g_IndexFileMap.GetFileStatus(sProjectRoot,sSubPath,&m_status.text_status); } else { LPCTSTR lpszSubPath = NULL; CString sSubPath; CString s = path.GetWinPathString(); if (s.GetLength() > sProjectRoot.GetLength()) { sSubPath = s.Right(s.GetLength() - sProjectRoot.GetLength() - 1/*otherwise it gets initial slash*/); lpszSubPath = sSubPath; } // when recursion enabled, let wingit determine the recursive status for folders instead of enumerating all files here UINT nFlags = WGEFF_SingleFile | WGEFF_NoRecurse; if (!lpszSubPath) // report root dir as normal (otherwise it could be considered git_wc_status_unversioned, which would be wrong?) nFlags |= WGEFF_EmptyAsNormal; m_status.prop_status = m_status.text_status = git_wc_status_none; // NOTE: currently wgEnumFiles will not enumerate file if it isn't versioned (so status will be git_wc_status_none) m_err = !wgEnumFiles(sProjectRoot, lpszSubPath, nFlags, &getstatus, &m_status); /*m_err = git_client_status4 (&youngest, path.GetGitApiPath(m_pool), &rev, getstatushash, &hashbaton, git_depth_empty, //depth TRUE, //getall update, //update noignore, //noignore noexternals, NULL, ctx, m_pool);*/ } // Error present if function is not under version control if (m_err) /*|| (apr_hash_count(statushash) == 0)*/ { status = NULL; // return -2; return GIT_INVALID_REVNUM; } // Convert the unordered hash to an ordered, sorted array /*statusarray = sort_hash (statushash, sort_compare_items_as_paths, m_pool);*/ // only the first entry is needed (no recurse) // item = &APR_ARRAY_IDX (statusarray, 0, const sort_item); // status = (git_wc_status2_t *) item->value; status = &m_status; if (update) { // done to match TSVN functionality of this function (not sure if any code uses the reutrn val) // if TGit does not need this, then change the return type of function youngest = g_Git.GetHash(CString(_T("HEAD"))); } return youngest; }
int GitStatus::GetFileStatus(const CString &gitdir, const CString &pathParam, git_wc_status_kind * status,BOOL IsFull, BOOL /*IsRecursive*/,BOOL IsIgnore, FILL_STATUS_CALLBACK callback, void *pData, bool * assumeValid, bool * skipWorktree) { try { CString path = pathParam; path.Replace(_T('\\'),_T('/')); CString lowcasepath =path; lowcasepath.MakeLower(); if(status) { git_wc_status_kind st = git_wc_status_none; CGitHash hash; g_IndexFileMap.GetFileStatus(gitdir, path, &st, IsFull, false, callback, pData, &hash, true, assumeValid, skipWorktree); if( st == git_wc_status_conflicted ) { *status =st; if (callback && assumeValid && skipWorktree) callback(gitdir + _T("/") + path, st, false, pData, *assumeValid, *skipWorktree); return 0; } if( st == git_wc_status_unversioned ) { if(!IsIgnore) { *status = git_wc_status_unversioned; if (callback && assumeValid && skipWorktree) callback(gitdir + _T("/") + path, *status, false, pData, *assumeValid, *skipWorktree); return 0; } if (g_IgnoreList.CheckIgnoreChanged(gitdir, path, false)) { g_IgnoreList.LoadAllIgnoreFile(gitdir, path, false); } if (g_IgnoreList.IsIgnore(path, gitdir, false)) { st = git_wc_status_ignored; } *status = st; if (callback && assumeValid && skipWorktree) callback(gitdir + _T("/") + path, st, false, pData, *assumeValid, *skipWorktree); return 0; } if ((st == git_wc_status_normal || st == git_wc_status_modified) && IsFull) { { g_HeadFileMap.CheckHeadAndUpdate(gitdir); SHARED_TREE_PTR treeptr = g_HeadFileMap.SafeGet(gitdir); // Check Head Tree Hash; { //add item int start = SearchInSortVector(*treeptr, lowcasepath, -1); if(start<0) { *status =st=git_wc_status_added; CTraceToOutputDebugString::Instance()(_T(__FUNCTION__) _T(": File miss in head tree %s"), path); if (callback && assumeValid && skipWorktree) callback(gitdir + _T("/") + path, st, false, pData, *assumeValid, *skipWorktree); return 0; } //staged and not commit if( treeptr->at(start).m_Hash != hash ) { *status =st=git_wc_status_modified; if (callback && assumeValid && skipWorktree) callback(gitdir + _T("/") + path, st, false, pData, *assumeValid, *skipWorktree); return 0; } } } } *status =st; if (callback && assumeValid && skipWorktree) callback(gitdir + _T("/") + path, st, false, pData, *assumeValid, *skipWorktree); return 0; } } catch(...) { if(status) *status = git_wc_status_none; return -1; } return 0; }
// static method git_wc_status_kind GitStatus::GetAllStatus(const CTGitPath& path, git_depth_t depth) { git_wc_status_kind statuskind; // git_client_ctx_t * ctx; // apr_pool_t * pool; // git_error_t * err; BOOL err; BOOL isDir; CString sProjectRoot; isDir = path.IsDirectory(); if (!path.HasAdminDir(&sProjectRoot)) return git_wc_status_none; // pool = git_pool_create (NULL); // create the memory pool // git_error_clear(git_client_create_context(&ctx, pool)); // git_revnum_t youngest = Git_INVALID_REVNUM; // git_opt_revision_t rev; // rev.kind = git_opt_revision_unspecified; statuskind = git_wc_status_none; const BOOL bIsRecursive = (depth == git_depth_infinity || depth == git_depth_unknown); // taken from SVN source #ifdef _TORTOISESHELL if (g_ShellCache.GetCacheType() == ShellCache::dll) #else if ((DWORD)CRegStdWORD(_T("Software\\TortoiseGit\\CacheType"), GetSystemMetrics(SM_REMOTESESSION) ? 2 : 1) == 2) #endif { // gitindex.h based status CString sSubPath; CString s = path.GetWinPathString(); if (s.GetLength() > sProjectRoot.GetLength()) { sSubPath = CStringA(s.Right(s.GetLength() - sProjectRoot.GetLength() - 1/*otherwise it gets initial slash*/)); } err = g_IndexFileMap.GetFileStatus(sProjectRoot,sSubPath,&statuskind); } else { LPCTSTR lpszSubPath = NULL; CString sSubPath; CString s = path.GetWinPathString(); if (s.GetLength() > sProjectRoot.GetLength()) { sSubPath = s.Right(s.GetLength() - sProjectRoot.GetLength() - 1/*otherwise it gets initial slash*/); lpszSubPath = sSubPath; } #if 1 // when recursion enabled, let wingit determine the recursive status for folders instead of enumerating all files here UINT nFlags = WGEFF_SingleFile; if (!bIsRecursive) nFlags |= WGEFF_NoRecurse; if (!lpszSubPath) // report root dir as normal (otherwise it could be considered git_wc_status_unversioned, which would be wrong?) nFlags |= WGEFF_EmptyAsNormal; #else // enumerate all files, recursively if requested UINT nFlags = 0; if (!bIsRecursive) nFlags |= WGEFF_NoRecurse; #endif err = !wgEnumFiles(sProjectRoot, lpszSubPath, nFlags, &getallstatus, &statuskind); /*err = git_client_status4 (&youngest, path.GetSVNApiPath(pool), &rev, getallstatus, &statuskind, depth, TRUE, //getall FALSE, //update TRUE, //noignore FALSE, //ignore externals NULL, ctx, pool);*/ } // Error present if (err != NULL) { // git_error_clear(err); // git_pool_destroy (pool); //free allocated memory return git_wc_status_none; } // git_pool_destroy (pool); //free allocated memory return statuskind; }