bool PrevDiffCommand::Execute() { bool bRet = false; //bool bAlternativeTool = !!parser.HasKey(_T("alternative")); if (this->orgCmdLinePath.IsDirectory()) { CFileDiffDlg dlg; dlg.m_strRev1 = GIT_REV_ZERO; dlg.m_strRev2 = _T("HEAD~1"); dlg.m_sFilter = this->cmdLinePath.GetGitPathString(); //dlg.m_pathList = CTGitPathList(cmdLinePath); dlg.DoModal(); bRet = true; } else { GitStatus st; st.GetStatus(cmdLinePath); if (1) { CString hash; CString logout; CLogDataVector revs; CLogCache cache; revs.m_pLogCache=&cache; revs.ParserFromLog(&cmdLinePath,2,CGit::LOG_INFO_ONLY_HASH); if( revs.size() != 2) { CMessageBox::Show(hWndExplorer, IDS_ERR_NOPREVREVISION, IDS_APPNAME, MB_ICONERROR); bRet = false; } else { CGitDiff diff; bRet = !!diff.Diff(&cmdLinePath,&cmdLinePath, GIT_REV_ZERO, revs.GetGitRevAt(1).m_CommitHash.ToString()); } } else { //if (st.GetLastErrorMsg().IsEmpty()) { CMessageBox::Show(hWndExplorer, IDS_ERR_NOPREVREVISION, IDS_APPNAME, MB_ICONERROR); } //else //{ // CMessageBox::Show(hWndExplorer, IDS_ERR_NOSTATUS, IDS_APPNAME, MB_ICONERROR); //s} } } return bRet; }
int _tmain(int argc, _TCHAR* argv[]) { CTGitPath path; CString root; TCHAR buff[256]; GetCurrentDirectory(256,buff); path.SetFromWin(buff); if(!path.HasAdminDir(&root)) { printf("not in git repository\n"); return -1; } CGitIndexList list; list.ReadIndex(root+_T("\\.git\\index")); CGitHeadFileList filelist; filelist.ReadHeadHash(buff); _tprintf(_T("update %d\n"), filelist.CheckHeadUpdate()); git_init(); // filelist.ReadTree(); WIN32_FIND_DATA data; CString str(buff); str+=_T("\\*.*"); GitStatus status; HANDLE handle = FindFirstFile(str,&data); while(FindNextFile(handle,&data)) { if( _tcsnccmp(data.cFileName, _T(".."),2) ==0) continue; if( _tcsnccmp(data.cFileName, _T("."),1) ==0 ) continue; CString spath(buff); spath += _T("\\"); spath += data.cFileName; CTGitPath path(spath); TCHAR name[100]; int t1,t2; t1 = ::GetCurrentTime(); status.GetStatusString(status.GetAllStatus(path), 100,name); t2 = ::GetCurrentTime(); _tprintf(_T("%s - %s - %d\n"),data.cFileName, name, t2-t1); } return 0; }
int CCachedDirectory::EnumFiles(CTGitPath *path , bool IsFull) { CString sProjectRoot; if(path) path->HasAdminDir(&sProjectRoot); else m_directoryPath.HasAdminDir(&sProjectRoot); ATLTRACE(_T("EnumFiles %s\n"), path->GetWinPath()); ATLASSERT( !m_directoryPath.IsEmpty() ); CString sSubPath; CString s; if(path) s=path->GetWinPath(); else s=m_directoryPath.GetDirectory().GetWinPathString(); if (s.GetLength() > sProjectRoot.GetLength()) { // skip initial slash if necessary if(s[sProjectRoot.GetLength()] == _T('\\')) sSubPath = s.Right(s.GetLength() - sProjectRoot.GetLength() -1); else sSubPath = s.Right(s.GetLength() - sProjectRoot.GetLength() ); } GitStatus *pStatus = &CGitStatusCache::Instance().m_GitStatus; UNREFERENCED_PARAMETER(pStatus); git_wc_status_kind status; if(!path->IsDirectory()) pStatus->GetFileStatus(sProjectRoot, sSubPath, &status, IsFull, false,true, GetStatusCallback,this); else { m_mostImportantFileStatus = git_wc_status_normal; pStatus->EnumDirStatus(sProjectRoot, sSubPath, &status, IsFull, false, true, GetStatusCallback,this); m_ownStatus = git_wc_status_normal; } m_mostImportantFileStatus = GitStatus::GetMoreImportant(m_mostImportantFileStatus, status); return 0; }
bool PasteMoveCommand::Execute() { CString sDroppath = parser.GetVal(_T("droptarget")); CTGitPath dropPath(sDroppath); if (dropPath.IsAdminDir()) return FALSE; if(!dropPath.HasAdminDir(&g_Git.m_CurrentDir)) return FALSE; GitStatus status; unsigned long count = 0; orgPathList.RemoveAdminPaths(); CString sNewName; CSysProgressDlg progress; progress.SetTitle(IDS_PROC_MOVING); progress.SetAnimation(IDR_MOVEANI); progress.SetTime(true); progress.ShowModeless(CWnd::FromHandle(hwndExplorer)); for (int nPath = 0; nPath < orgPathList.GetCount(); ++nPath) { CTGitPath destPath; if (sNewName.IsEmpty()) destPath = CTGitPath(sDroppath+_T("\\")+orgPathList[nPath].GetFileOrDirectoryName()); else destPath = CTGitPath(sDroppath+_T("\\")+sNewName); if (destPath.Exists()) { CString name = orgPathList[nPath].GetFileOrDirectoryName(); if (!sNewName.IsEmpty()) name = sNewName; progress.Stop(); CRenameDlg dlg; dlg.m_name = name; dlg.m_windowtitle.Format(IDS_PROC_NEWNAMEMOVE, (LPCTSTR)name); if (dlg.DoModal() != IDOK) { return FALSE; } destPath.SetFromWin(sDroppath+_T("\\")+dlg.m_name); } CString top; top.Empty(); orgPathList[nPath].HasAdminDir(&top); git_wc_status_kind s = status.GetAllStatus(orgPathList[nPath]); if ((s == git_wc_status_none)||(s == git_wc_status_unversioned)||(s == git_wc_status_ignored)||top != g_Git.m_CurrentDir) { // source file is unversioned: move the file to the target, then add it MoveFile(orgPathList[nPath].GetWinPath(), destPath.GetWinPath()); CString cmd,output; cmd.Format(_T("git.exe add -- \"%s\""),destPath.GetWinPath()); if (g_Git.Run(cmd, &output, CP_UTF8)) //if (!Git.Add(CTGitorgPathList(destPath), &props, Git_depth_infinity, true, false, true)) { TRACE(_T("%s\n"), output); CMessageBox::Show(hwndExplorer, output, _T("TortoiseGit"), MB_ICONERROR); return FALSE; //get out of here } CShellUpdater::Instance().AddPathForUpdate(destPath); } else { CString cmd,output; cmd.Format(_T("git.exe mv \"%s\" \"%s\""),orgPathList[nPath].GetGitPathString(),destPath.GetGitPathString()); if (g_Git.Run(cmd, &output, CP_UTF8)) //if (!Git.Move(CTGitorgPathList(orgPathList[nPath]), destPath, FALSE)) { #if 0 if (Git.Err && (Git.Err->apr_err == Git_ERR_UNVERSIONED_RESOURCE || Git.Err->apr_err == Git_ERR_CLIENT_MODIFIED)) { // file/folder seems to have local modifications. Ask the user if // a force is requested. CString temp = Git.GetLastErrorMessage(); CString sQuestion(MAKEINTRESOURCE(IDS_PROC_FORCEMOVE)); temp += _T("\n") + sQuestion; if (CMessageBox::Show(hwndExplorer, temp, _T("TortoiseGit"), MB_YESNO)==IDYES) { if (!Git.Move(CTGitPathList(pathList[nPath]), destPath, TRUE)) { CMessageBox::Show(hwndExplorer, Git.GetLastErrorMessage(), _T("TortoiseGit"), MB_ICONERROR); return FALSE; //get out of here } CShellUpdater::Instance().AddPathForUpdate(destPath); } } else #endif { TRACE(_T("%s\n"), (LPCTSTR)output); CMessageBox::Show(hwndExplorer, output, _T("TortoiseGit"), MB_ICONERROR); return FALSE; //get out of here } } else CShellUpdater::Instance().AddPathForUpdate(destPath); } ++count; if (progress.IsValid()) { progress.FormatPathLine(1, IDS_PROC_MOVINGPROG, orgPathList[nPath].GetWinPath()); progress.FormatPathLine(2, IDS_PROC_CPYMVPROG2, destPath.GetWinPath()); progress.SetProgress(count, orgPathList.GetCount()); } if ((progress.IsValid())&&(progress.HasUserCancelled())) { CMessageBox::Show(hwndExplorer, IDS_USERCANCELLED, IDS_APPNAME, MB_ICONINFORMATION); return FALSE; } } return true; }
int CCachedDirectory::EnumFiles(const CTGitPath &path , bool IsFull) { CString sProjectRoot; path.HasAdminDir(&sProjectRoot); CTraceToOutputDebugString::Instance()(_T(__FUNCTION__) _T(": EnumFiles %s\n"), path.GetWinPath()); ATLASSERT( !m_directoryPath.IsEmpty() ); CString sSubPath; CString s = path.GetWinPath(); if (s.GetLength() > sProjectRoot.GetLength()) { // skip initial slash if necessary if(s[sProjectRoot.GetLength()] == _T('\\')) sSubPath = s.Right(s.GetLength() - sProjectRoot.GetLength() -1); else sSubPath = s.Right(s.GetLength() - sProjectRoot.GetLength() ); } // strip "\" at the end, otherwise cache lookups for drives do not work correctly sProjectRoot.TrimRight(_T("\\")); GitStatus *pStatus = &CGitStatusCache::Instance().m_GitStatus; UNREFERENCED_PARAMETER(pStatus); git_wc_status_kind status = git_wc_status_none; if (!path.IsDirectory()) { bool assumeValid = false; bool skipWorktree = false; pStatus->GetFileStatus(sProjectRoot, sSubPath, &status, IsFull, false, true, GetStatusCallback, this, &assumeValid, &skipWorktree); if (status < m_mostImportantFileStatus) RefreshMostImportant(); } else { bool isSelf = path == m_directoryPath; if (isSelf) { AutoLocker lock(m_critSec); // clear subdirectory status cache m_childDirectories.clear(); // build new files status cache m_entryCache_tmp.clear(); } m_mostImportantFileStatus = git_wc_status_none; pStatus->EnumDirStatus(sProjectRoot, sSubPath, &status, IsFull, false, true, GetStatusCallback,this); m_mostImportantFileStatus = GitStatus::GetMoreImportant(m_mostImportantFileStatus, status); if (isSelf) { AutoLocker lock(m_critSec); // use a tmp files status cache so that we can still use the old cached values // for deciding whether we have to issue a shell notify m_entryCache = m_entryCache_tmp; m_entryCache_tmp.clear(); } // need to set/construct m_ownStatus (only unversioned and normal are valid values) m_ownStatus = git_wc_status_unversioned; m_ownStatus.SetKind(git_node_dir); if (m_mostImportantFileStatus > git_wc_status_unversioned) { git_wc_status2_t status2; status2.text_status = status2.prop_status = git_wc_status_normal; m_ownStatus.SetStatus(&status2); } else { if (::PathFileExists(m_directoryPath.GetWinPathString() + _T("\\.git"))) { git_wc_status2_t status2; status2.text_status = status2.prop_status = git_wc_status_normal; m_ownStatus.SetStatus(&status2); } else { git_wc_status2_t status2; status2.text_status = status2.prop_status = CalculateRecursiveStatus(); m_ownStatus.SetStatus(&status2); } } } return 0; }
CStatusCacheEntry CCachedDirectory::GetStatusFromGit(const CTGitPath &path, CString sProjectRoot) { CString subpaths = path.GetGitPathString(); if(subpaths.GetLength() >= sProjectRoot.GetLength()) { if(subpaths[sProjectRoot.GetLength()] == _T('/')) subpaths=subpaths.Right(subpaths.GetLength() - sProjectRoot.GetLength()-1); else subpaths=subpaths.Right(subpaths.GetLength() - sProjectRoot.GetLength()); } GitStatus *pGitStatus = &CGitStatusCache::Instance().m_GitStatus; UNREFERENCED_PARAMETER(pGitStatus); bool isVersion =true; pGitStatus->IsUnderVersionControl(sProjectRoot, subpaths, path.IsDirectory(), &isVersion); if(!isVersion) { //untracked file bool isDir = path.IsDirectory(); bool isIgnoreFileChanged = pGitStatus->HasIgnoreFilesChanged(sProjectRoot, subpaths, isDir); if( isIgnoreFileChanged) { pGitStatus->LoadIgnoreFile(sProjectRoot, subpaths, isDir); } if (isDir) { CCachedDirectory * dirEntry = CGitStatusCache::Instance().GetDirectoryCacheEntry(path, false); /* we needn't watch untracked directory*/ if(dirEntry) { AutoLocker lock(dirEntry->m_critSec); git_wc_status_kind dirstatus = dirEntry->GetCurrentFullStatus() ; if (CGitStatusCache::Instance().IsUnversionedAsModified() || dirstatus == git_wc_status_none || dirstatus >= git_wc_status_normal || isIgnoreFileChanged) {/* status have not initialized*/ bool isignore = false; pGitStatus->IsIgnore(sProjectRoot, subpaths, &isignore, isDir); if (!isignore && CGitStatusCache::Instance().IsUnversionedAsModified()) { dirEntry->EnumFiles(path, TRUE); dirEntry->UpdateCurrentStatus(); return CStatusCacheEntry(dirEntry->GetCurrentFullStatus()); } git_wc_status2_t status2; status2.text_status = status2.prop_status = (isignore? git_wc_status_ignored:git_wc_status_unversioned); // we do not know anything about files here, all we know is that there are not versioned files in this dir dirEntry->m_mostImportantFileStatus = git_wc_status_none; dirEntry->m_ownStatus.SetKind(git_node_dir); dirEntry->m_ownStatus.SetStatus(&status2); dirEntry->m_currentFullStatus = status2.text_status; } return dirEntry->m_ownStatus; } } else /* path is file */ { AutoLocker lock(m_critSec); CString strCacheKey = GetCacheKey(path); if (strCacheKey.IsEmpty()) return CStatusCacheEntry(); CacheEntryMap::iterator itMap = m_entryCache.find(strCacheKey); if(itMap == m_entryCache.end() || isIgnoreFileChanged) { git_wc_status2_t status2; bool isignore = false; pGitStatus->IsIgnore(sProjectRoot, subpaths, &isignore, isDir); status2.text_status = status2.prop_status = (isignore? git_wc_status_ignored:git_wc_status_unversioned); AddEntry(path, &status2); return m_entryCache[strCacheKey]; } else { return itMap->second; } } return CStatusCacheEntry(); } else { EnumFiles(path, TRUE); UpdateCurrentStatus(); if (!path.IsDirectory()) return GetCacheStatusForMember(path); return CStatusCacheEntry(m_ownStatus); } }
CStatusCacheEntry CCachedDirectory::GetStatusFromGit(const CTGitPath &path, CString sProjectRoot) { CString subpaths = path.GetGitPathString(); if(subpaths.GetLength() >= sProjectRoot.GetLength()) { if(subpaths[sProjectRoot.GetLength()] == _T('/')) subpaths=subpaths.Right(subpaths.GetLength() - sProjectRoot.GetLength()-1); else subpaths=subpaths.Right(subpaths.GetLength() - sProjectRoot.GetLength()); } GitStatus *pGitStatus = &CGitStatusCache::Instance().m_GitStatus; CGitHash head; pGitStatus->GetHeadHash(sProjectRoot,head); bool isVersion =true; pGitStatus->IsUnderVersionControl(sProjectRoot, subpaths, path.IsDirectory(), &isVersion); if(!isVersion) { //untracked file bool isIgnoreFileChanged=false; isIgnoreFileChanged = pGitStatus->IsGitReposChanged(sProjectRoot, subpaths, GIT_MODE_IGNORE); if( isIgnoreFileChanged) { pGitStatus->LoadIgnoreFile(sProjectRoot, subpaths); } if(path.IsDirectory()) { CCachedDirectory * dirEntry = CGitStatusCache::Instance().GetDirectoryCacheEntry(path, false); /* we needn't watch untracked directory*/ if(dirEntry) { AutoLocker lock(dirEntry->m_critSec); git_wc_status_kind dirstatus = dirEntry->GetCurrentFullStatus() ; if( dirstatus == git_wc_status_none || dirstatus >= git_wc_status_normal || isIgnoreFileChanged ) {/* status have not initialized*/ git_wc_status2_t status2; bool isignore = false; pGitStatus->IsIgnore(sProjectRoot,subpaths,&isignore); status2.text_status = status2.prop_status = (isignore? git_wc_status_ignored:git_wc_status_unversioned); dirEntry->m_ownStatus.SetStatus(&status2); dirEntry->m_ownStatus.SetKind(git_node_dir); } return dirEntry->m_ownStatus; } } else /* path is file */ { AutoLocker lock(m_critSec); CString strCacheKey = GetCacheKey(path); CacheEntryMap::iterator itMap = m_entryCache.find(strCacheKey); if(itMap == m_entryCache.end() || isIgnoreFileChanged) { git_wc_status2_t status2; bool isignore = false; pGitStatus->IsIgnore(sProjectRoot,subpaths,&isignore); status2.text_status = status2.prop_status = (isignore? git_wc_status_ignored:git_wc_status_unversioned); AddEntry(path, &status2); return m_entryCache[strCacheKey]; } else { return itMap->second; } } return CStatusCacheEntry(); } else { EnumFiles((CTGitPath*)&path, TRUE); UpdateCurrentStatus(); return CStatusCacheEntry(m_ownStatus); } }