int GitRev::AddMergeFiles() { std::map<CString, int> map; std::map<CString, int>::iterator it; for (int i = 0; i < m_Files.GetCount(); ++i) { if(map.find(m_Files[i].GetGitPathString()) == map.end()) { map[m_Files[i].GetGitPathString()]=0; } else { ++map[m_Files[i].GetGitPathString()]; } } for (it = map.begin(); it != map.end(); ++it) { if(it->second) { CTGitPath path; path.SetFromGit(it->first); path.m_ParentNo = MERGE_MASK; path.m_StatAdd=_T("-"); path.m_StatDel=_T("-"); path.m_Action = CTGitPath::LOGACTIONS_MERGED; m_Files.AddPath(path); } } return 0; }
int CTGitPathList::FillUnRev(unsigned int action, CTGitPathList *list, CString *err) { this->Clear(); CTGitPath path; int count; if(list==NULL) count=1; else count=list->GetCount(); for (int i = 0; i < count; ++i) { CString cmd; int pos = 0; CString ignored; if(action & CTGitPath::LOGACTIONS_IGNORE) ignored= _T(" -i"); if(list==NULL) { cmd=_T("git.exe ls-files --exclude-standard --full-name --others -z"); cmd+=ignored; } else { cmd.Format(_T("git.exe ls-files --exclude-standard --full-name --others -z%s -- \"%s\""), (LPCTSTR)ignored, (*list)[i].GetWinPath()); } BYTE_VECTOR out, errb; out.clear(); if (g_Git.Run(cmd, &out, &errb)) { if (err != nullptr) CGit::StringAppend(err, &errb[0], CP_UTF8, (int)errb.size()); return -1; } pos=0; CString one; while (pos >= 0 && pos < (int)out.size()) { one.Empty(); CGit::StringAppend(&one, &out[pos], CP_UTF8); if(!one.IsEmpty()) { //SetFromGit will clear all status path.SetFromGit(one); path.m_Action=action; AddPath(path); } pos=out.findNextString(pos); } } return 0; }
int COutputWnd::LoadHistory(CString filename, CString revision, bool follow) { CTGitPath path; path.SetFromGit(filename); m_LogList.Clear(); if (m_LogList.FillGitLog(&path, follow ? CGit::LOG_INFO_FOLLOW : 0, NULL, &revision)) return -1; m_LogList.UpdateProjectProperties(); return 0; }
int CTGitPathList::ParserFromLsFile(BYTE_VECTOR &out,bool /*staged*/) { int pos=0; CString one; CTGitPath path; CString part; this->Clear(); while (pos >= 0 && pos < (int)out.size()) { one.Empty(); path.Reset(); CGit::StringAppend(&one, &out[pos], CP_UTF8); int tabstart=0; // m_Action is never used and propably never worked (needs to be set after path.SetFromGit) // also dropped LOGACTIONS_CACHE for 'H' // path.m_Action=path.ParserAction(out[pos]); one.Tokenize(_T("\t"),tabstart); if(tabstart>=0) path.SetFromGit(one.Right(one.GetLength()-tabstart)); else return -1; tabstart=0; part=one.Tokenize(_T(" "),tabstart); //Tag if (tabstart < 0) return -1; part=one.Tokenize(_T(" "),tabstart); //Mode if (tabstart < 0) return -1; part=one.Tokenize(_T(" "),tabstart); //Hash if (tabstart < 0) return -1; part=one.Tokenize(_T("\t"),tabstart); //Stage if (tabstart < 0) return -1; path.m_Stage=_ttol(part); this->AddPath(path); pos=out.findNextString(pos); } return 0; }
bool RenameCommand::Execute() { bool bRet = true; CString filename = cmdLinePath.GetFileOrDirectoryName(); CString basePath = cmdLinePath.GetContainingDirectory().GetGitPathString(); // show the rename dialog until the user either cancels or enters a new // name (one that's different to the original name CString sNewName; do { CRenameDlg dlg; dlg.m_name = filename; if (dlg.DoModal() != IDOK) return FALSE; sNewName = dlg.m_name; } while(PathIsRelative(sNewName) && !PathIsURL(sNewName) && (sNewName.IsEmpty() || (sNewName.Compare(filename)==0))); if(!basePath.IsEmpty()) sNewName=basePath+"/"+sNewName; CString force; // if the filenames only differ in case, we have to pass "-f" if (sNewName.CompareNoCase(cmdLinePath.GetGitPathString()) == 0) force = _T("-f "); CString cmd; CString output; cmd.Format(_T("git.exe mv %s-- \"%s\" \"%s\""), force, cmdLinePath.GetGitPathString(), sNewName); if (g_Git.Run(cmd, &output, CP_UTF8)) { CMessageBox::Show(hwndExplorer, output, _T("TortoiseGit"), MB_OK); bRet = false; } CTGitPath newpath; newpath.SetFromGit(sNewName); CShellUpdater::Instance().AddPathForUpdate(newpath); CShellUpdater::Instance().Flush(); return bRet; }
int CTGitPathList::FillBasedOnIndexFlags(unsigned short flag, CTGitPathList* list /*nullptr*/) { Clear(); CTGitPath path; CAutoRepository repository(g_Git.GetGitRepository()); if (!repository) return -1; CAutoIndex index; if (git_repository_index(index.GetPointer(), repository)) return -1; int count; if (list == nullptr) count = 1; else count = list->GetCount(); for (int j = 0; j < count; ++j) { for (size_t i = 0, ecount = git_index_entrycount(index); i < ecount; ++i) { const git_index_entry *e = git_index_get_byindex(index, i); if (!e || !((e->flags | e->flags_extended) & flag) || !e->path) continue; CString one = CUnicodeUtils::GetUnicode(e->path); if (!(!list || (*list)[j].GetWinPathString().IsEmpty() || one == (*list)[j].GetGitPathString() || (PathIsDirectory(g_Git.CombinePath((*list)[j].GetWinPathString())) && one.Find((*list)[j].GetGitPathString() + _T("/")) == 0))) continue; //SetFromGit will clear all status path.SetFromGit(one); if ((e->flags | e->flags_extended) & GIT_IDXENTRY_SKIP_WORKTREE) path.m_Action = CTGitPath::LOGACTIONS_SKIPWORKTREE; else if ((e->flags | e->flags_extended) & GIT_IDXENTRY_VALID) path.m_Action = CTGitPath::LOGACTIONS_ASSUMEVALID; AddPath(path); } } RemoveDuplicates(); return 0; }
int CGitDiff::DiffNull(const CTGitPath *pPath, git_revnum_t rev1, bool bIsAdd, int jumpToLine) { CString temppath; GetTempPath(temppath); if (rev1 != GIT_REV_ZERO) { CGitHash rev1Hash; if (g_Git.GetHash(rev1Hash, rev1)) // make sure we have a HASH here, otherwise filenames might be invalid { MessageBox(NULL, g_Git.GetGitLastErr(_T("Could not get hash of \"") + rev1 + _T("\".")), _T("TortoiseGit"), MB_ICONERROR); return -1; } rev1 = rev1Hash.ToString(); } CString file1; CString nullfile; CString cmd; if(pPath->IsDirectory()) { int result; // refresh if result = 1 CTGitPath path = *pPath; while ((result = SubmoduleDiffNull(&path, rev1)) == 1) { path.SetFromGit(pPath->GetGitPathString()); } return result; } if(rev1 != GIT_REV_ZERO ) { TCHAR szTempName[MAX_PATH] = {0}; GetTempFileName(temppath, pPath->GetBaseFilename(), 0, szTempName); CString temp(szTempName); DeleteFile(szTempName); CreateDirectory(szTempName, NULL); file1.Format(_T("%s\\%s-%s%s"), temp, pPath->GetBaseFilename(), rev1.Left(g_Git.GetShortHASHLength()), pPath->GetFileExtension()); g_Git.GetOneFile(rev1,*pPath,file1); } else { file1=g_Git.m_CurrentDir+_T("\\")+pPath->GetWinPathString(); } // preserve FileExtension, needed especially for diffing deleted images (detection on new filename extension) CString tempfile=::GetTempFile() + pPath->GetFileExtension(); CStdioFile file(tempfile,CFile::modeReadWrite|CFile::modeCreate ); //file.WriteString(); file.Close(); ::SetFileAttributes(tempfile, FILE_ATTRIBUTE_READONLY); CAppUtils::DiffFlags flags; if(bIsAdd) CAppUtils::StartExtDiff(tempfile,file1, pPath->GetGitPathString(), pPath->GetGitPathString() + _T(":") + rev1.Left(g_Git.GetShortHASHLength()), g_Git.m_CurrentDir + _T("\\") + pPath->GetWinPathString(), g_Git.m_CurrentDir + _T("\\") + pPath->GetWinPathString(), git_revnum_t(GIT_REV_ZERO), rev1 , flags, jumpToLine); else CAppUtils::StartExtDiff(file1,tempfile, pPath->GetGitPathString() + _T(":") + rev1.Left(g_Git.GetShortHASHLength()), pPath->GetGitPathString(), g_Git.m_CurrentDir + _T("\\") + pPath->GetWinPathString(), g_Git.m_CurrentDir + _T("\\") + pPath->GetWinPathString(), rev1, git_revnum_t(GIT_REV_ZERO) , flags, jumpToLine); return 0; }
int CGitDiff::Diff(const CTGitPath * pPath, const CTGitPath * pPath2, git_revnum_t rev1, git_revnum_t rev2, bool /*blame*/, bool /*unified*/, int jumpToLine) { CString temppath; GetTempPath(temppath); // make sure we have HASHes here, otherwise filenames might be invalid if (rev1 != GIT_REV_ZERO) { CGitHash rev1Hash; if (g_Git.GetHash(rev1Hash, rev1)) { MessageBox(NULL, g_Git.GetGitLastErr(_T("Could not get hash of \"") + rev1 + _T("\".")), _T("TortoiseGit"), MB_ICONERROR); return -1; } rev1 = rev1Hash.ToString(); } if (rev2 != GIT_REV_ZERO) { CGitHash rev2Hash; if (g_Git.GetHash(rev2Hash, rev2)) { MessageBox(NULL, g_Git.GetGitLastErr(_T("Could not get hash of \"") + rev2 + _T("\".")), _T("TortoiseGit"), MB_ICONERROR); return -1; } rev2 = rev2Hash.ToString(); } CString file1; CString title1; CString cmd; if(pPath->IsDirectory() || pPath2->IsDirectory()) { int result; // refresh if result = 1 CTGitPath path = *pPath; CTGitPath path2 = *pPath2; while ((result = SubmoduleDiff(&path, &path2, rev1, rev2)) == 1) { path.SetFromGit(pPath->GetGitPathString()); path2.SetFromGit(pPath2->GetGitPathString()); } return result; } if(rev1 != GIT_REV_ZERO ) { TCHAR szTempName[MAX_PATH] = {0}; GetTempFileName(temppath, pPath->GetBaseFilename(), 0, szTempName); CString temp(szTempName); DeleteFile(szTempName); CreateDirectory(szTempName, NULL); // use original file extension, an external diff tool might need it file1.Format(_T("%s\\%s-%s-right%s"), temp, pPath->GetBaseFilename(), rev1.Left(g_Git.GetShortHASHLength()), pPath->GetFileExtension()); title1 = pPath->GetFileOrDirectoryName() + _T(":") + rev1.Left(g_Git.GetShortHASHLength()); g_Git.GetOneFile(rev1,*pPath,file1); ::SetFileAttributes(file1, FILE_ATTRIBUTE_READONLY); } else { file1=g_Git.m_CurrentDir+_T("\\")+pPath->GetWinPathString(); title1.Format( IDS_DIFF_WCNAME, pPath->GetFileOrDirectoryName() ); if (!PathFileExists(file1)) { CString sMsg; sMsg.Format(IDS_PROC_DIFFERROR_FILENOTINWORKINGTREE, file1); if (MessageBox(NULL, sMsg, _T("TortoiseGit"), MB_ICONEXCLAMATION | MB_YESNO) == IDNO) return 1; if (!CCommonAppUtils::FileOpenSave(file1, NULL, IDS_DIFF_WCNAME, IDS_COMMONFILEFILTER, true)) return 1; title1.Format(IDS_DIFF_WCNAME, CTGitPath(file1).GetUIFileOrDirectoryName()); } } CString file2; CString title2; if(rev2 != GIT_REV_ZERO) { TCHAR szTempName[MAX_PATH] = {0}; GetTempFileName(temppath, pPath2->GetBaseFilename(), 0, szTempName); CString temp(szTempName); DeleteFile(szTempName); CreateDirectory(szTempName, NULL); CTGitPath fileName = *pPath2; if (pPath2->m_Action & CTGitPath::LOGACTIONS_REPLACED) fileName = CTGitPath(pPath2->GetGitOldPathString()); // use original file extension, an external diff tool might need it file2.Format(_T("%s\\%s-%s-left%s"), temp, fileName.GetBaseFilename(), rev2.Left(g_Git.GetShortHASHLength()), fileName.GetFileExtension()); title2 = fileName.GetFileOrDirectoryName() + _T(":") + rev2.Left(g_Git.GetShortHASHLength()); g_Git.GetOneFile(rev2, fileName, file2); ::SetFileAttributes(file2, FILE_ATTRIBUTE_READONLY); } else { file2=g_Git.m_CurrentDir+_T("\\")+pPath2->GetWinPathString(); title2.Format( IDS_DIFF_WCNAME, pPath2->GetFileOrDirectoryName() ); } if (pPath->m_Action == pPath->LOGACTIONS_ADDED) { CGitDiff::DiffNull(pPath, rev1, true, jumpToLine); } else if (pPath->m_Action == pPath->LOGACTIONS_DELETED) { CGitDiff::DiffNull(pPath, rev2, false, jumpToLine); } else { CAppUtils::DiffFlags flags; CAppUtils::StartExtDiff(file2,file1, title2, title1, g_Git.m_CurrentDir + _T("\\") + pPath2->GetWinPathString(), g_Git.m_CurrentDir + _T("\\") + pPath->GetWinPathString(), rev2, rev1, flags, jumpToLine); } 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 CLogCache::LoadOneItem(GitRev &Rev,ULONGLONG offset) { if(m_pCacheData == NULL) return -1; if (offset + sizeof(SLogCacheRevItemHeader) > m_DataFileLength) return -2; SLogCacheRevItemHeader *header; header = (SLogCacheRevItemHeader *)(this->m_pCacheData + offset); if( !CheckHeader(header)) return -2; Rev.m_Action = 0; SLogCacheRevFileHeader *fileheader; offset += sizeof(SLogCacheRevItemHeader); fileheader =(SLogCacheRevFileHeader *)(this->m_pCacheData + offset); for (DWORD i = 0; i < header->m_FileCount; ++i) { CTGitPath path; CString oldfile; path.Reset(); if (offset + sizeof(SLogCacheRevFileHeader) > m_DataFileLength) return -2; if(!CheckHeader(fileheader)) return -2; CString file(fileheader->m_FileName, fileheader->m_FileNameSize); if(fileheader->m_OldFileNameSize) { oldfile = CString(fileheader->m_FileName + fileheader->m_FileNameSize, fileheader->m_OldFileNameSize); } path.SetFromGit(file,&oldfile); path.m_ParentNo = fileheader ->m_ParentNo; path.m_Stage = fileheader ->m_Stage; path.m_Action = fileheader ->m_Action; Rev.m_Action |= path.m_Action; if(fileheader->m_Add == 0xFFFFFFFF) path.m_StatAdd=_T("-"); else path.m_StatAdd.Format(_T("%d"),fileheader->m_Add); if(fileheader->m_Del == 0xFFFFFFFF) path.m_StatDel=_T("-"); else path.m_StatDel.Format(_T("%d"), fileheader->m_Del); Rev.m_Files.AddPath(path); offset += sizeof(*fileheader) + fileheader->m_OldFileNameSize*sizeof(TCHAR) + fileheader->m_FileNameSize*sizeof(TCHAR) - sizeof(TCHAR); fileheader = (SLogCacheRevFileHeader *) (this->m_pCacheData + offset); } return 0; }
bool RenameCommand::Execute() { bool bRet = false; CString filename = cmdLinePath.GetFileOrDirectoryName(); CString basePath = cmdLinePath.GetContainingDirectory().GetGitPathString(); //::SetCurrentDirectory(basePath); // show the rename dialog until the user either cancels or enters a new // name (one that's different to the original name CString sNewName; do { CRenameDlg dlg; dlg.m_name = filename; if (dlg.DoModal() != IDOK) return FALSE; sNewName = dlg.m_name; } while(PathIsRelative(sNewName) && !PathIsURL(sNewName) && (sNewName.IsEmpty() || (sNewName.Compare(filename)==0))); if(!basePath.IsEmpty()) sNewName=basePath+"/"+sNewName; CString cmd; CString output; cmd.Format(_T("git.exe mv -- \"%s\" \"%s\""), cmdLinePath.GetGitPathString(), sNewName); if(g_Git.Run(cmd,&output,CP_ACP)) { CMessageBox::Show(hwndExplorer, output, _T("TortoiseGit"), MB_OK); } CTGitPath newpath; newpath.SetFromGit(sNewName); CShellUpdater::Instance().AddPathForUpdate(newpath); #if 0 TRACE(_T("rename file %s to %s\n"), (LPCTSTR)cmdLinePath.GetWinPathString(), (LPCTSTR)sNewName); CTSVNPath destinationPath(basePath); if (PathIsRelative(sNewName) && !PathIsURL(sNewName)) destinationPath.AppendPathString(sNewName); else destinationPath.SetFromWin(sNewName); // check if a rename just with case is requested: that's not possible on windows file systems // and we have to show an error. if (cmdLinePath.GetWinPathString().CompareNoCase(destinationPath.GetWinPathString())==0) { //rename to the same file! CString sHelpPath = theApp.m_pszHelpFilePath; sHelpPath += _T("::/tsvn-dug-rename.html#tsvn-dug-renameincase"); CMessageBox::Show(hwndExplorer, IDS_PROC_CASERENAME, IDS_APPNAME, MB_OK|MB_HELP, sHelpPath); } else { CString sMsg; if (SVN::PathIsURL(cmdLinePath)) { // rename an URL. // Ask for a commit message, then rename directly in // the repository CInputLogDlg input; CString sUUID; SVN svn; svn.GetRepositoryRootAndUUID(cmdLinePath, sUUID); input.SetUUID(sUUID); CString sHint; sHint.Format(IDS_INPUT_MOVE, (LPCTSTR)cmdLinePath.GetSVNPathString(), (LPCTSTR)destinationPath.GetSVNPathString()); input.SetActionText(sHint); if (input.DoModal() == IDOK) { sMsg = input.GetLogMessage(); } else { return FALSE; } } if ((cmdLinePath.IsDirectory())||(pathList.GetCount() > 1)) { // renaming a directory can take a while: use the // progress dialog to show the progress of the renaming // operation. CSVNProgressDlg progDlg; progDlg.SetCommand(CSVNProgressDlg::SVNProgress_Rename); if (parser.HasVal(_T("closeonend"))) progDlg.SetAutoClose(parser.GetLongVal(_T("closeonend"))); progDlg.SetPathList(pathList); progDlg.SetUrl(destinationPath.GetWinPathString()); progDlg.SetCommitMessage(sMsg); progDlg.SetRevision(SVNRev::REV_WC); progDlg.DoModal(); bRet = !progDlg.DidErrorsOccur(); } else { SVN svn; CString sFilemask = cmdLinePath.GetFilename(); if (sFilemask.ReverseFind('.')>=0) { sFilemask = sFilemask.Left(sFilemask.ReverseFind('.')); } else sFilemask.Empty(); CString sNewMask = sNewName; if (sNewMask.ReverseFind('.'>=0)) { sNewMask = sNewMask.Left(sNewMask.ReverseFind('.')); } else sNewMask.Empty(); if (((!sFilemask.IsEmpty()) && (parser.HasKey(_T("noquestion")))) || (cmdLinePath.GetFileExtension().Compare(destinationPath.GetFileExtension())!=0)) { if (!svn.Move(CTSVNPathList(cmdLinePath), destinationPath, TRUE, sMsg)) { TRACE(_T("%s\n"), (LPCTSTR)svn.GetLastErrorMessage()); CMessageBox::Show(hwndExplorer, svn.GetLastErrorMessage(), _T("TortoiseGit"), MB_ICONERROR); } else bRet = true; } else { // when refactoring, multiple files have to be renamed // at once because those files belong together. // e.g. file.aspx, file.aspx.cs, file.aspx.resx CTSVNPathList renlist; CSimpleFileFind filefind(cmdLinePath.GetDirectory().GetWinPathString(), sFilemask+_T(".*")); while (filefind.FindNextFileNoDots()) { if (!filefind.IsDirectory()) renlist.AddPath(CTSVNPath(filefind.GetFilePath())); } if (renlist.GetCount()<=1) { // we couldn't find any other matching files // just do the default... if (!svn.Move(CTSVNPathList(cmdLinePath), destinationPath, TRUE, sMsg)) { TRACE(_T("%s\n"), (LPCTSTR)svn.GetLastErrorMessage()); CMessageBox::Show(hwndExplorer, svn.GetLastErrorMessage(), _T("TortoiseGit"), MB_ICONERROR); } else { bRet = true; CShellUpdater::Instance().AddPathForUpdate(destinationPath); } } else { std::map<CString, CString> renmap; CString sTemp; CString sRenList; for (int i=0; i<renlist.GetCount(); ++i) { CString sFilename = renlist[i].GetFilename(); CString sNewFilename = sNewMask + sFilename.Mid(sFilemask.GetLength()); sTemp.Format(_T("\n%s -> %s"), (LPCTSTR)sFilename, (LPCTSTR)sNewFilename); if (!renlist[i].IsEquivalentTo(cmdLinePath)) sRenList += sTemp; renmap[renlist[i].GetWinPathString()] = renlist[i].GetContainingDirectory().GetWinPathString()+_T("\\")+sNewFilename; } CString sRenameMultipleQuestion; sRenameMultipleQuestion.Format(IDS_PROC_MULTIRENAME, (LPCTSTR)sRenList); UINT idret = CMessageBox::Show(hwndExplorer, sRenameMultipleQuestion, _T("TortoiseGit"), MB_ICONQUESTION|MB_YESNOCANCEL); if (idret == IDYES) { CProgressDlg progress; progress.SetTitle(IDS_PROC_MOVING); progress.SetAnimation(IDR_MOVEANI); progress.SetTime(true); progress.ShowModeless(CWnd::FromHandle(hwndExplorer)); DWORD count = 1; for (std::map<CString, CString>::iterator it=renmap.begin(); it != renmap.end(); ++it) { progress.FormatPathLine(1, IDS_PROC_MOVINGPROG, (LPCTSTR)it->first); progress.FormatPathLine(2, IDS_PROC_CPYMVPROG2, (LPCTSTR)it->second); progress.SetProgress(count, renmap.size()); if (!svn.Move(CTSVNPathList(CTSVNPath(it->first)), CTSVNPath(it->second), TRUE, sMsg)) { if (svn.Err->apr_err == SVN_ERR_ENTRY_NOT_FOUND) { bRet = !!MoveFile(it->first, it->second); } else { TRACE(_T("%s\n"), (LPCTSTR)svn.GetLastErrorMessage()); CMessageBox::Show(hwndExplorer, svn.GetLastErrorMessage(), _T("TortoiseGit"), MB_ICONERROR); bRet = false; } } else { bRet = true; CShellUpdater::Instance().AddPathForUpdate(CTSVNPath(it->second)); } } progress.Stop(); } else if (idret == IDNO) { // no, user wants to just rename the file he selected if (!svn.Move(CTSVNPathList(cmdLinePath), destinationPath, TRUE, sMsg)) { TRACE(_T("%s\n"), (LPCTSTR)svn.GetLastErrorMessage()); CMessageBox::Show(hwndExplorer, svn.GetLastErrorMessage(), _T("TortoiseGit"), MB_ICONERROR); } else { bRet = true; CShellUpdater::Instance().AddPathForUpdate(destinationPath); } } else if (idret == IDCANCEL) { // nothing } } } } } #endif CShellUpdater::Instance().Flush(); return bRet; }
void CPatchListCtrl::OnContextMenu(CWnd* /*pWnd*/, CPoint point) { int selected=this->GetSelectedCount(); int index=0; POSITION pos=this->GetFirstSelectedItemPosition(); index=this->GetNextSelectedItem(pos); CIconMenu popup; if (popup.CreatePopupMenu()) { if(selected == 1) { if( m_ContextMenuMask&GetMenuMask(MENU_VIEWPATCH)) popup.AppendMenuIcon(MENU_VIEWPATCH, IDS_MENU_VIEWPATCH, 0); if( m_ContextMenuMask&GetMenuMask(MENU_VIEWWITHMERGE)) popup.AppendMenuIcon(MENU_VIEWWITHMERGE, IDS_MENU_VIEWWITHMERGE, 0); popup.SetDefaultItem(MENU_VIEWPATCH, FALSE); } if(selected >= 1) { if( m_ContextMenuMask&GetMenuMask(MENU_SENDMAIL)) popup.AppendMenuIcon(MENU_SENDMAIL, IDS_MENU_SENDMAIL, IDI_MENUSENDMAIL); if( m_ContextMenuMask&GetMenuMask(MENU_APPLY)) popup.AppendMenuIcon(MENU_APPLY, IDS_MENU_APPLY, 0); } int cmd = popup.TrackPopupMenu(TPM_RETURNCMD | TPM_LEFTALIGN | TPM_NONOTIFY, point.x, point.y, this, 0); switch (cmd) { case MENU_VIEWPATCH: { CString path=GetItemText(index,0); CTGitPath gitpath; gitpath.SetFromWin(path); CAppUtils::StartUnifiedDiffViewer(path,gitpath.GetFilename()); break; } case MENU_VIEWWITHMERGE: { CString path=GetItemText(index,0); CTGitPath gitpath; gitpath.SetFromWin(path); CTGitPath dir; dir.SetFromGit(g_Git.m_CurrentDir); CAppUtils::StartExtPatch(gitpath,dir); break; } case MENU_SENDMAIL: { LaunchProc(_T("sendmail")); break; } case MENU_APPLY: { LaunchProc(_T("importpatch")); break; } default: break; } } }
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 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; }
int CGitDiff::DiffNull(const CTGitPath *pPath, git_revnum_t rev1, bool bIsAdd, int jumpToLine, bool bAlternative) { if (rev1 != GIT_REV_ZERO) { CGitHash rev1Hash; if (g_Git.GetHash(rev1Hash, rev1)) // make sure we have a HASH here, otherwise filenames might be invalid { MessageBox(nullptr, g_Git.GetGitLastErr(L"Could not get hash of \"" + rev1 + L"\"."), L"TortoiseGit", MB_ICONERROR); return -1; } rev1 = rev1Hash.ToString(); } CString file1; CString nullfile; CString cmd; if(pPath->IsDirectory()) { int result; // refresh if result = 1 CTGitPath path = *pPath; while ((result = SubmoduleDiffNull(&path, rev1)) == 1) path.SetFromGit(pPath->GetGitPathString()); return result; } if(rev1 != GIT_REV_ZERO ) { file1 = CTempFiles::Instance().GetTempFilePath(false, *pPath, rev1).GetWinPathString(); if (g_Git.GetOneFile(rev1, *pPath, file1)) { CString out; out.Format(IDS_STATUSLIST_CHECKOUTFILEFAILED, (LPCTSTR)pPath->GetGitPathString(), (LPCTSTR)rev1, (LPCTSTR)file1); CMessageBox::Show(nullptr, g_Git.GetGitLastErr(out, CGit::GIT_CMD_GETONEFILE), L"TortoiseGit", MB_OK); return -1; } ::SetFileAttributes(file1, FILE_ATTRIBUTE_READONLY); } else file1 = g_Git.CombinePath(pPath); CString tempfile = CTempFiles::Instance().GetTempFilePath(false, *pPath, rev1).GetWinPathString(); ::SetFileAttributes(tempfile, FILE_ATTRIBUTE_READONLY); CAppUtils::DiffFlags flags; flags.bAlternativeTool = bAlternative; if(bIsAdd) CAppUtils::StartExtDiff(tempfile,file1, pPath->GetGitPathString(), pPath->GetGitPathString() + L':' + rev1.Left(g_Git.GetShortHASHLength()), g_Git.CombinePath(pPath), g_Git.CombinePath(pPath), git_revnum_t(GIT_REV_ZERO), rev1 , flags, jumpToLine); else CAppUtils::StartExtDiff(file1,tempfile, pPath->GetGitPathString() + L':' + rev1.Left(g_Git.GetShortHASHLength()), pPath->GetGitPathString(), g_Git.CombinePath(pPath), g_Git.CombinePath(pPath), rev1, git_revnum_t(GIT_REV_ZERO) , flags, jumpToLine); return 0; }
int CGitDiff::Diff(const CTGitPath* pPath, const CTGitPath* pPath2, git_revnum_t rev1, git_revnum_t rev2, bool /*blame*/, bool /*unified*/, int jumpToLine, bool bAlternativeTool) { // make sure we have HASHes here, otherwise filenames might be invalid if (rev1 != GIT_REV_ZERO) { CGitHash rev1Hash; if (g_Git.GetHash(rev1Hash, rev1)) { MessageBox(nullptr, g_Git.GetGitLastErr(L"Could not get hash of \"" + rev1 + L"\"."), L"TortoiseGit", MB_ICONERROR); return -1; } rev1 = rev1Hash.ToString(); } if (rev2 != GIT_REV_ZERO) { CGitHash rev2Hash; if (g_Git.GetHash(rev2Hash, rev2)) { MessageBox(nullptr, g_Git.GetGitLastErr(L"Could not get hash of \"" + rev2 + L"\"."), L"TortoiseGit", MB_ICONERROR); return -1; } rev2 = rev2Hash.ToString(); } CString file1; CString title1; CString cmd; if(pPath->IsDirectory() || pPath2->IsDirectory()) { int result; // refresh if result = 1 CTGitPath path = *pPath; CTGitPath path2 = *pPath2; while ((result = SubmoduleDiff(&path, &path2, rev1, rev2)) == 1) { path.SetFromGit(pPath->GetGitPathString()); path2.SetFromGit(pPath2->GetGitPathString()); } return result; } if(rev1 != GIT_REV_ZERO ) { // use original file extension, an external diff tool might need it file1 = CTempFiles::Instance().GetTempFilePath(false, *pPath, rev1).GetWinPathString(); title1 = pPath->GetGitPathString() + L": " + rev1.Left(g_Git.GetShortHASHLength()); if (g_Git.GetOneFile(rev1, *pPath, file1)) { CString out; out.Format(IDS_STATUSLIST_CHECKOUTFILEFAILED, (LPCTSTR)pPath->GetGitPathString(), (LPCTSTR)rev1, (LPCTSTR)file1); CMessageBox::Show(nullptr, g_Git.GetGitLastErr(out, CGit::GIT_CMD_GETONEFILE), L"TortoiseGit", MB_OK); return -1; } ::SetFileAttributes(file1, FILE_ATTRIBUTE_READONLY); } else { file1 = g_Git.CombinePath(pPath); title1.Format(IDS_DIFF_WCNAME, (LPCTSTR)pPath->GetGitPathString()); if (!PathFileExists(file1)) { CString sMsg; sMsg.Format(IDS_PROC_DIFFERROR_FILENOTINWORKINGTREE, (LPCTSTR)file1); if (MessageBox(nullptr, sMsg, L"TortoiseGit", MB_ICONEXCLAMATION | MB_YESNO) != IDYES) return 1; if (!CCommonAppUtils::FileOpenSave(file1, nullptr, IDS_SELECTFILE, IDS_COMMONFILEFILTER, true)) return 1; title1 = file1; } } CString file2; CString title2; if(rev2 != GIT_REV_ZERO) { CTGitPath fileName = *pPath2; if (pPath2->m_Action & CTGitPath::LOGACTIONS_REPLACED) fileName = CTGitPath(pPath2->GetGitOldPathString()); file2 = CTempFiles::Instance().GetTempFilePath(false, fileName, rev2).GetWinPathString(); title2 = fileName.GetGitPathString() + L": " + rev2.Left(g_Git.GetShortHASHLength()); if (g_Git.GetOneFile(rev2, fileName, file2)) { CString out; out.Format(IDS_STATUSLIST_CHECKOUTFILEFAILED, (LPCTSTR)pPath2->GetGitPathString(), (LPCTSTR)rev2, (LPCTSTR)file2); CMessageBox::Show(nullptr, g_Git.GetGitLastErr(out, CGit::GIT_CMD_GETONEFILE), L"TortoiseGit", MB_OK); return -1; } ::SetFileAttributes(file2, FILE_ATTRIBUTE_READONLY); } else { file2 = g_Git.CombinePath(pPath2); title2.Format(IDS_DIFF_WCNAME, pPath2->GetGitPathString()); } CAppUtils::DiffFlags flags; flags.bAlternativeTool = bAlternativeTool; CAppUtils::StartExtDiff(file2,file1, title2, title1, g_Git.CombinePath(pPath2), g_Git.CombinePath(pPath), rev2, rev1, flags, jumpToLine); return 0; }