1 // GitLogList.cpp : implementation file
4 Description: qgit revision list view
6 Author: Marco Costalba (C) 2005-2007
8 Copyright: See COPYING file that comes with this distribution
12 #include "TortoiseProc.h"
13 #include "GitLogList.h"
15 //#include "VssStyle.h"
21 #include "SVNProgressDlg.h"
22 #include "ProgressDlg.h"
23 #include "SysProgressDlg.h"
24 //#include "RepositoryBrowser.h"
25 //#include "CopyDlg.h"
26 //#include "StatGraphDlg.h"
28 #include "MessageBox.h"
31 #include "PathUtils.h"
32 #include "StringUtils.h"
33 #include "UnicodeUtils.h"
35 //#include "GitInfo.h"
36 //#include "GitDiff.h"
38 //#include "RevisionRangeDlg.h"
39 //#include "BrowseFolder.h"
40 //#include "BlameDlg.h"
42 //#include "GitHelpers.h"
43 #include "GitStatus.h"
44 //#include "LogDlgHelper.h"
45 //#include "CachedLogInfo.h"
46 //#include "RepositoryInfo.h"
47 //#include "EditPropertiesDlg.h"
48 #include "FileDiffDlg.h"
49 #include "CommitDlg.h"
50 #include "RebaseDlg.h"
52 IMPLEMENT_DYNAMIC(CGitLogList
, CHintListCtrl
)
54 int CGitLogList::CherryPickFrom(CString from
, CString to
)
57 if(logs
.ParserFromLog(NULL
,-1,0,&from
,&to
))
63 CSysProgressDlg progress
;
64 if (progress
.IsValid())
66 progress
.SetTitle(_T("Cherry Pick"));
67 progress
.SetAnimation(IDR_MOVEANI
);
68 progress
.SetTime(true);
69 progress
.ShowModeless(this);
72 for(int i
=logs
.size()-1;i
>=0;i
--)
74 if (progress
.IsValid())
76 progress
.FormatPathLine(1, _T("Pick up %s"), logs
[i
].m_CommitHash
);
77 progress
.FormatPathLine(2, _T("%s"), logs
[i
].m_Subject
);
78 progress
.SetProgress(logs
.size()-i
, logs
.size());
80 if ((progress
.IsValid())&&(progress
.HasUserCancelled()))
82 //CMessageBox::Show(hwndExplorer, IDS_SVN_USERCANCELLED, IDS_APPNAME, MB_ICONINFORMATION);
83 throw std::exception(CUnicodeUtils::GetUTF8(_T("User canceled\r\n\r\n")));
87 cmd
.Format(_T("git.exe cherry-pick %s"),logs
[i
].m_CommitHash
);
89 if(g_Git
.Run(cmd
,&out
,CP_UTF8
))
91 throw std::exception(CUnicodeUtils::GetUTF8(CString(_T("Cherry Pick Failure\r\n\r\n"))+out
));
99 void CGitLogList::ContextMenuAction(int cmd
,int FirstSelect
, int LastSelect
)
101 POSITION pos
= GetFirstSelectedItemPosition();
102 int indexNext
= GetNextSelectedItem(pos
);
106 GitRev
* pSelLogEntry
= reinterpret_cast<GitRev
*>(m_arShownList
.GetAt(indexNext
));
108 theApp
.DoWaitCursor(1);
109 bool bOpenWith
= false;
114 CString tempfile
=GetTempFile();
116 GitRev
* r1
= reinterpret_cast<GitRev
*>(m_arShownList
.GetAt(FirstSelect
));
117 cmd
.Format(_T("git.exe diff-tree -r -p --stat %s"),r1
->m_CommitHash
);
118 g_Git
.RunLogFile(cmd
,tempfile
);
119 CAppUtils::StartUnifiedDiffViewer(tempfile
,r1
->m_CommitHash
.Left(6)+_T(":")+r1
->m_Subject
);
125 CString tempfile
=GetTempFile();
127 GitRev
* r1
= reinterpret_cast<GitRev
*>(m_arShownList
.GetAt(FirstSelect
));
128 GitRev
* r2
= reinterpret_cast<GitRev
*>(m_arShownList
.GetAt(LastSelect
));
129 cmd
.Format(_T("git.exe diff-tree -r -p --stat %s %s"),r1
->m_CommitHash
,r2
->m_CommitHash
);
130 g_Git
.RunLogFile(cmd
,tempfile
);
131 CAppUtils::StartUnifiedDiffViewer(tempfile
,r1
->m_CommitHash
.Left(6)+_T(":")+r2
->m_CommitHash
.Left(6));
138 GitRev
* r1
= reinterpret_cast<GitRev
*>(m_arShownList
.GetAt(FirstSelect
));
139 GitRev
* r2
= reinterpret_cast<GitRev
*>(m_arShownList
.GetAt(LastSelect
));
141 dlg
.SetDiff(NULL
,*r1
,*r2
);
150 GitRev
* r1
= &m_wcRev
;
151 GitRev
* r2
= pSelLogEntry
;
153 dlg
.SetDiff(NULL
,*r1
,*r2
);
156 //user clicked on the menu item "compare with working copy"
159 // GitDiff diff(this, m_hWnd, true);
160 // diff.SetAlternativeTool(!!(GetAsyncKeyState(VK_SHIFT) & 0x8000));
161 // diff.SetHEADPeg(m_LogRevision);
162 // diff.ShowCompare(m_path, GitRev::REV_WC, m_path, revSelected);
165 // CAppUtils::StartShowCompare(m_hWnd, m_path, GitRev::REV_WC, m_path, revSelected, GitRev(), m_LogRevision, !!(GetAsyncKeyState(VK_SHIFT) & 0x8000));
169 case ID_COMPAREWITHPREVIOUS
:
174 if(pSelLogEntry
->m_ParentHash
.size()>0)
175 //if(m_logEntries.m_HashMap[pSelLogEntry->m_ParentHash[0]]>=0)
177 dlg
.SetDiff(NULL
,pSelLogEntry
->m_CommitHash
,pSelLogEntry
->m_ParentHash
[0]);
181 CMessageBox::Show(NULL
,_T("No previous version"),_T("TortoiseGit"),MB_OK
);
185 // GitDiff diff(this, m_hWnd, true);
186 // diff.SetAlternativeTool(!!(GetAsyncKeyState(VK_SHIFT) & 0x8000));
187 // diff.SetHEADPeg(m_LogRevision);
188 // diff.ShowCompare(CTGitPath(pathURL), revPrevious, CTGitPath(pathURL), revSelected);
191 // CAppUtils::StartShowCompare(m_hWnd, CTGitPath(pathURL), revPrevious, CTGitPath(pathURL), revSelected, GitRev(), m_LogRevision, !!(GetAsyncKeyState(VK_SHIFT) & 0x8000));
194 case ID_COPYCLIPBOARD
:
196 CopySelectionToClipBoard();
201 CopySelectionToClipBoard(TRUE
);
205 CAppUtils::Export(&pSelLogEntry
->m_CommitHash
);
207 case ID_CREATE_BRANCH
:
208 CAppUtils::CreateBranchTag(FALSE
,&pSelLogEntry
->m_CommitHash
);
213 CAppUtils::CreateBranchTag(TRUE
,&pSelLogEntry
->m_CommitHash
);
218 CAppUtils::Switch(&pSelLogEntry
->m_CommitHash
);
223 CAppUtils::GitReset(&pSelLogEntry
->m_CommitHash
);
228 SetSelectedAction(CTGitPath::LOGACTIONS_REBASE_PICK
);
231 SetSelectedAction(CTGitPath::LOGACTIONS_REBASE_EDIT
);
233 case ID_REBASE_SQUASH
:
234 SetSelectedAction(CTGitPath::LOGACTIONS_REBASE_SQUASH
);
237 SetSelectedAction(CTGitPath::LOGACTIONS_REBASE_SKIP
);
239 case ID_COMBINE_COMMIT
:
243 CString hashFirst
,hashLast
;
245 int headindex
=GetHeadIndex();
246 if(headindex
>=0) //incase show all branch, head is not the first commits.
248 head
.Format(_T("HEAD~%d"),FirstSelect
-headindex
);
249 hashFirst
=g_Git
.GetHash(head
);
251 head
.Format(_T("HEAD~%d"),LastSelect
-headindex
);
252 hashLast
=g_Git
.GetHash(head
);
255 GitRev
* pFirstEntry
= reinterpret_cast<GitRev
*>(m_arShownList
.GetAt(FirstSelect
));
256 GitRev
* pLastEntry
= reinterpret_cast<GitRev
*>(m_arShownList
.GetAt(LastSelect
));
257 if(pFirstEntry
->m_CommitHash
!= hashFirst
|| pLastEntry
->m_CommitHash
!= hashLast
)
259 CMessageBox::Show(NULL
,_T(
260 "Cannot combine commits now.\r\n\
261 Make sure you are viewing the log of your current branch and \
262 no filters are applied."),_T("TortoiseGit"),MB_OK
);
266 headhash
=g_Git
.GetHash(CString(_T("HEAD")));
268 if(!g_Git
.CheckCleanWorkTree())
270 CMessageBox::Show(NULL
,_T("Combine needs a clean work tree"),_T("TortoiseGit"),MB_OK
);
275 //Use throw to abort this process (reset back to original HEAD)
278 cmd
.Format(_T("git.exe reset --hard %s"),pFirstEntry
->m_CommitHash
);
279 if(g_Git
.Run(cmd
,&out
,CP_UTF8
))
281 CMessageBox::Show(NULL
,out
,_T("TortoiseGit"),MB_OK
);
282 throw std::exception(CUnicodeUtils::GetUTF8(_T("Could not reset to first commit (first step) aborting...\r\n\r\n")+out
));
284 cmd
.Format(_T("git.exe reset --mixed %s"),hashLast
);
285 if(g_Git
.Run(cmd
,&out
,CP_UTF8
))
287 CMessageBox::Show(NULL
,out
,_T("TortoiseGit"),MB_OK
);
288 throw std::exception(CUnicodeUtils::GetUTF8(_T("Could not reset to last commit (second step) aborting...\r\n\r\n")+out
));
291 for(int i
=FirstSelect
;i
<=LastSelect
;i
++)
293 GitRev
* pRev
= reinterpret_cast<GitRev
*>(m_arShownList
.GetAt(i
));
294 dlg
.m_sLogMessage
+=pRev
->m_Subject
+_T("\n")+pRev
->m_Body
;
295 dlg
.m_sLogMessage
+=_T("\n");
297 dlg
.m_bWholeProject
=true;
298 dlg
.m_bSelectFilesForCommit
= true;
299 dlg
.m_bCommitAmend
=true;
300 dlg
.m_AmendStr
=dlg
.m_sLogMessage
;
303 if (dlg
.DoModal() == IDOK
)
305 if(pFirstEntry
->m_CommitHash
!=headhash
)
307 //Commitrange firstEntry..headhash (from top of combine to original head) needs to be 'cherry-picked'
308 //on top of new commit.
309 //Use the rebase --onto command for it.
311 //All this can be done in one step using the following command:
312 //cmd.Format(_T("git.exe format-patch --stdout --binary --full-index -k %s..%s | git am -k -3"),
313 // pFirstEntry->m_CommitHash,
315 //But I am not sure if a '|' is going to work in a CreateProcess() call.
317 //Later the progress dialog could be used to execute these steps.
319 if(CherryPickFrom(pFirstEntry
->m_CommitHash
,headhash
))
322 msg
.Format(_T("Error while cherry pick commits on top of combined commits. Aborting.\r\n\r\n"));
323 throw std::exception(CUnicodeUtils::GetUTF8(msg
));
326 CString currentBranch
=g_Git
.GetCurrentBranch();
327 cmd
.Format(_T("git.exe rebase --onto \"%s\" %s %s"),
329 pFirstEntry
->m_CommitHash
,
331 if(g_Git
.Run(cmd
,&out
,CP_UTF8
)!=0)
334 msg
.Format(_T("Error while rebasing commits on top of combined commits. Aborting.\r\n\r\n%s"),out
);
335 // CMessageBox::Show(NULL,msg,_T("TortoiseGit"),MB_OK);
336 g_Git
.Run(_T("git.exe rebase --abort"),&out
,CP_UTF8
);
337 throw std::exception(CUnicodeUtils::GetUTF8(msg
));
340 //HEAD is now on <no branch>.
341 //The following steps are to get HEAD back on the original branch and reset the branch to the new HEAD
342 //To avoid 2 working copy changes, we could use git branch -f <original branch> <hash new head>
343 //And then git checkout <original branch>
344 //But I don't know if 'git branch -f' removes tracking options. So for now, do a checkout and a reset.
347 CString newHead
=g_Git
.GetHash(CString(_T("HEAD")));
349 //Checkout working branch
350 cmd
.Format(_T("git.exe checkout -f \"%s\""),currentBranch
);
351 if(g_Git
.Run(cmd
,&out
,CP_UTF8
))
352 throw std::exception(CUnicodeUtils::GetUTF8(_T("Could not checkout original branch. Aborting...\r\n\r\n")+out
));
355 cmd
.Format(_T("git.exe reset --hard %s"),newHead
);
356 if(g_Git
.Run(cmd
,&out
,CP_UTF8
))
357 throw std::exception(CUnicodeUtils::GetUTF8(_T("Could not reset to new head. Aborting...\r\n\r\n")+out
));
362 throw std::exception("User aborted the combine process");
364 catch(std::exception
& e
)
366 CMessageBox::Show(NULL
,CUnicodeUtils::GetUnicode(CStringA(e
.what())),_T("TortoiseGit: Combine error"),MB_OK
|MB_ICONERROR
);
367 cmd
.Format(_T("git.exe reset --hard %s"),headhash
);
369 if(g_Git
.Run(cmd
,&out
,CP_UTF8
))
371 CMessageBox::Show(NULL
,_T("Could not reset to original HEAD\r\n\r\n")+out
,_T("TortoiseGit"),MB_OK
);
379 if(!g_Git
.CheckCleanWorkTree())
381 CMessageBox::Show(NULL
,_T("Cherry Pick Require Clean Working Tree"),_T("TortoiseGit"),MB_OK
);
386 dlg
.m_IsCherryPick
= TRUE
;
387 dlg
.m_Upstream
= this->m_CurrentBranch
;
388 POSITION pos
= GetFirstSelectedItemPosition();
391 int indexNext
= GetNextSelectedItem(pos
);
392 dlg
.m_CommitList
.m_logEntries
.push_back(*(GitRev
*)m_arShownList
[indexNext
]);
393 dlg
.m_CommitList
.m_logEntries
.at(dlg
.m_CommitList
.m_logEntries
.size()-1).m_Action
|= CTGitPath::LOGACTIONS_REBASE_PICK
;
396 if(dlg
.DoModal() == IDOK
)
402 case ID_REBASE_TO_VERSION
:
403 if(!g_Git
.CheckCleanWorkTree())
405 CMessageBox::Show(NULL
,_T("Rebase Require Clean Working Tree"),_T("TortoiseGit"),MB_OK
);
410 dlg
.m_Upstream
= pSelLogEntry
->m_CommitHash
;
412 if(dlg
.DoModal() == IDOK
)
421 CAppUtils::StashApply(pSelLogEntry
->m_Ref
);
427 str
.Format(_T("Warning: %s will be deleted. It can <ct=0x0000FF><b>NOT</b></ct> recovered,\r\n \r\n Are you sure delete these?"),pSelLogEntry
->m_Ref
);
428 if(CMessageBox::Show(NULL
,str
,_T("TortoiseGit"),MB_YESNO
|MB_ICONWARNING
) == IDYES
)
431 cmd
.Format(_T("git.exe reflog delete %s"),pSelLogEntry
->m_Ref
);
432 if(g_Git
.Run(cmd
,&out
,CP_ACP
))
434 CMessageBox::Show(NULL
,out
,_T("TortoiseGit"),MB_OK
);
436 ::PostMessage(this->GetParent()->m_hWnd
,MSG_REFLOG_CHANGED
,0,0);
440 case ID_CREATE_PATCH
:
442 int select
=this->GetSelectedCount();
444 cmd
= CPathUtils::GetAppDirectory()+_T("TortoiseProc.exe");
445 cmd
+= _T(" /command:formatpatch");
447 GitRev
* r1
= reinterpret_cast<GitRev
*>(m_arShownList
.GetAt(FirstSelect
));
451 cmd
+= _T(" /startrev:")+r1
->m_CommitHash
;
455 r2
= reinterpret_cast<GitRev
*>(m_arShownList
.GetAt(LastSelect
));
456 if( this->m_IsOldFirst
)
458 cmd
+= _T(" /startrev:")+r1
->m_CommitHash
;
459 cmd
+= _T(" /endrev:")+r2
->m_CommitHash
;
463 cmd
+= _T(" /startrev:")+r2
->m_CommitHash
;
464 cmd
+= _T(" /endrev:")+r1
->m_CommitHash
;
469 CAppUtils::LaunchApplication(cmd
,IDS_ERR_PROC
,false);
473 //CMessageBox::Show(NULL,_T("Have not implemented"),_T("TortoiseGit"),MB_OK);
479 // we need an URL to complete this command, so error out if we can't get an URL
480 if (pathURL
.IsEmpty())
483 strMessage
.Format(IDS_ERR_NOURLOFFILE
, (LPCTSTR
)(m_path
.GetUIPathString()));
484 CMessageBox::Show(this->m_hWnd
, strMessage
, _T("TortoiseGit"), MB_ICONERROR
);
485 TRACE(_T("could not retrieve the URL of the folder!\n"));
489 msg
.Format(IDS_LOG_REVERT_CONFIRM
, m_path
.GetWinPath());
490 if (CMessageBox::Show(this->m_hWnd
, msg
, _T("TortoiseGit"), MB_YESNO
| MB_ICONQUESTION
) == IDYES
)
493 dlg
.SetCommand(CGitProgressDlg::GitProgress_Merge
);
494 dlg
.SetPathList(CTGitPathList(m_path
));
496 dlg
.SetSecondUrl(pathURL
);
497 revisionRanges
.AdjustForMerge(true);
498 dlg
.SetRevisionRanges(revisionRanges
);
499 dlg
.SetPegRevision(m_LogRevision
);
506 // we need an URL to complete this command, so error out if we can't get an URL
507 if (pathURL
.IsEmpty())
510 strMessage
.Format(IDS_ERR_NOURLOFFILE
, (LPCTSTR
)(m_path
.GetUIPathString()));
511 CMessageBox::Show(this->m_hWnd
, strMessage
, _T("TortoiseGit"), MB_ICONERROR
);
512 TRACE(_T("could not retrieve the URL of the folder!\n"));
516 CString path
= m_path
.GetWinPathString();
517 bool bGotSavePath
= false;
518 if ((GetSelectedCount() == 1)&&(!m_path
.IsDirectory()))
520 bGotSavePath
= CAppUtils::FileOpenSave(path
, NULL
, IDS_LOG_MERGETO
, IDS_COMMONFILEFILTER
, true, GetSafeHwnd());
524 CBrowseFolder folderBrowser
;
525 folderBrowser
.SetInfo(CString(MAKEINTRESOURCE(IDS_LOG_MERGETO
)));
526 bGotSavePath
= (folderBrowser
.Show(GetSafeHwnd(), path
, path
) == CBrowseFolder::OK
);
531 dlg
.SetCommand(CGitProgressDlg::GitProgress_Merge
);
532 dlg
.SetPathList(CTGitPathList(CTGitPath(path
)));
534 dlg
.SetSecondUrl(pathURL
);
535 revisionRanges
.AdjustForMerge(false);
536 dlg
.SetRevisionRanges(revisionRanges
);
537 dlg
.SetPegRevision(m_LogRevision
);
544 // we need an URL to complete this command, so error out if we can't get an URL
545 if (pathURL
.IsEmpty())
548 strMessage
.Format(IDS_ERR_NOURLOFFILE
, (LPCTSTR
)(m_path
.GetUIPathString()));
549 CMessageBox::Show(this->m_hWnd
, strMessage
, _T("TortoiseGit"), MB_ICONERROR
);
550 TRACE(_T("could not retrieve the URL of the folder!\n"));
555 msg
.Format(IDS_LOG_REVERTTOREV_CONFIRM
, m_path
.GetWinPath());
556 if (CMessageBox::Show(this->m_hWnd
, msg
, _T("TortoiseGit"), MB_YESNO
| MB_ICONQUESTION
) == IDYES
)
559 dlg
.SetCommand(CGitProgressDlg::GitProgress_Merge
);
560 dlg
.SetPathList(CTGitPathList(m_path
));
562 dlg
.SetSecondUrl(pathURL
);
563 GitRevRangeArray revarray
;
564 revarray
.AddRevRange(GitRev::REV_HEAD
, revSelected
);
565 dlg
.SetRevisionRanges(revarray
);
566 dlg
.SetPegRevision(m_LogRevision
);
574 case ID_BLAMECOMPARE
:
576 //user clicked on the menu item "compare with working copy"
577 //now first get the revision which is selected
580 GitDiff
diff(this, this->m_hWnd
, true);
581 diff
.SetHEADPeg(m_LogRevision
);
582 diff
.ShowCompare(m_path
, GitRev::REV_BASE
, m_path
, revSelected
, GitRev(), false, true);
585 CAppUtils::StartShowCompare(m_hWnd
, m_path
, GitRev::REV_BASE
, m_path
, revSelected
, GitRev(), m_LogRevision
, false, false, true);
590 //user clicked on the menu item "compare and blame revisions"
593 GitDiff
diff(this, this->m_hWnd
, true);
594 diff
.SetHEADPeg(m_LogRevision
);
595 diff
.ShowCompare(CTGitPath(pathURL
), revSelected2
, CTGitPath(pathURL
), revSelected
, GitRev(), false, true);
598 CAppUtils::StartShowCompare(m_hWnd
, CTGitPath(pathURL
), revSelected2
, CTGitPath(pathURL
), revSelected
, GitRev(), m_LogRevision
, false, false, true);
601 case ID_BLAMEWITHPREVIOUS
:
603 //user clicked on the menu item "Compare and Blame with previous revision"
606 GitDiff
diff(this, this->m_hWnd
, true);
607 diff
.SetHEADPeg(m_LogRevision
);
608 diff
.ShowCompare(CTGitPath(pathURL
), revPrevious
, CTGitPath(pathURL
), revSelected
, GitRev(), false, true);
611 CAppUtils::StartShowCompare(m_hWnd
, CTGitPath(pathURL
), revPrevious
, CTGitPath(pathURL
), revSelected
, GitRev(), m_LogRevision
, false, false, true);
619 CProgressDlg progDlg
;
620 progDlg
.SetTitle(IDS_APPNAME
);
621 progDlg
.SetAnimation(IDR_DOWNLOAD
);
623 sInfoLine
.Format(IDS_PROGRESSGETFILEREVISION
, m_path
.GetWinPath(), (LPCTSTR
)revSelected
.ToString());
624 progDlg
.SetLine(1, sInfoLine
, true);
625 SetAndClearProgressInfo(&progDlg
);
626 progDlg
.ShowModeless(m_hWnd
);
627 CTGitPath tempfile
= CTempFiles::Instance().GetTempFilePath(false, m_path
, revSelected
);
628 bool bSuccess
= true;
629 if (!Cat(m_path
, GitRev(GitRev::REV_HEAD
), revSelected
, tempfile
))
632 // try again, but with the selected revision as the peg revision
633 if (!Cat(m_path
, revSelected
, revSelected
, tempfile
))
636 SetAndClearProgressInfo((HWND
)NULL
);
637 CMessageBox::Show(this->m_hWnd
, GetLastErrorMessage(), _T("TortoiseGit"), MB_ICONERROR
);
646 SetAndClearProgressInfo((HWND
)NULL
);
647 SetFileAttributes(tempfile
.GetWinPath(), FILE_ATTRIBUTE_READONLY
);
650 ret
= (int)ShellExecute(this->m_hWnd
, NULL
, tempfile
.GetWinPath(), NULL
, NULL
, SW_SHOWNORMAL
);
651 if ((ret
<= HINSTANCE_ERROR
)||bOpenWith
)
653 CString cmd
= _T("RUNDLL32 Shell32,OpenAs_RunDLL ");
654 cmd
+= tempfile
.GetWinPathString() + _T(" ");
655 CAppUtils::LaunchApplication(cmd
, NULL
, false);
663 dlg
.EndRev
= revSelected
;
664 if (dlg
.DoModal() == IDOK
)
669 tempfile
= blame
.BlameToTempFile(m_path
, dlg
.StartRev
, dlg
.EndRev
, dlg
.EndRev
, logfile
, _T(""), dlg
.m_bIncludeMerge
, TRUE
, TRUE
);
670 if (!tempfile
.IsEmpty())
674 //open the default text editor for the result file
675 CAppUtils::StartTextViewer(tempfile
);
679 CString sParams
= _T("/path:\"") + m_path
.GetGitPathString() + _T("\" ");
680 if(!CAppUtils::LaunchTortoiseBlame(tempfile
, logfile
, CPathUtils::GetFileNameFromPath(m_path
.GetFileOrDirectoryName()),sParams
))
688 CMessageBox::Show(this->m_hWnd
, blame
.GetLastErrorMessage(), _T("TortoiseGit"), MB_ICONERROR
);
696 CString url
= _T("tgit:")+pathURL
;
697 sCmd
.Format(_T("%s /command:update /path:\"%s\" /rev:%ld"),
698 (LPCTSTR
)(CPathUtils::GetAppDirectory()+_T("TortoiseProc.exe")),
699 (LPCTSTR
)m_path
.GetWinPath(), (LONG
)revSelected
);
700 CAppUtils::LaunchApplication(sCmd
, NULL
, false);
705 m_nSearchIndex
= GetSelectionMark();
706 if (m_nSearchIndex
< 0)
714 m_pFindDialog
= new CFindReplaceDialog();
715 m_pFindDialog
->Create(TRUE
, NULL
, NULL
, FR_HIDEUPDOWN
| FR_HIDEWHOLEWORD
, this);
722 sCmd
.Format(_T("%s /command:repobrowser /path:\"%s\" /rev:%s"),
723 (LPCTSTR
)(CPathUtils::GetAppDirectory()+_T("TortoiseProc.exe")),
724 (LPCTSTR
)pathURL
, (LPCTSTR
)revSelected
.ToString());
726 CAppUtils::LaunchApplication(sCmd
, NULL
, false);
731 EditLogMessage(selIndex
);
736 EditAuthor(selEntries
);
741 CEditPropertiesDlg dlg
;
742 dlg
.SetProjectProperties(&m_ProjectProperties
);
743 CTGitPathList escapedlist
;
744 dlg
.SetPathList(CTGitPathList(CTGitPath(pathURL
)));
745 dlg
.SetRevision(revSelected
);
754 sCmd
.Format(_T("%s /command:export /path:\"%s\" /revision:%ld"),
755 (LPCTSTR
)(CPathUtils::GetAppDirectory()+_T("TortoiseProc.exe")),
756 (LPCTSTR
)pathURL
, (LONG
)revSelected
);
757 CAppUtils::LaunchApplication(sCmd
, NULL
, false);
763 CString url
= _T("tgit:")+pathURL
;
764 sCmd
.Format(_T("%s /command:checkout /url:\"%s\" /revision:%ld"),
765 (LPCTSTR
)(CPathUtils::GetAppDirectory()+_T("TortoiseProc.exe")),
766 (LPCTSTR
)url
, (LONG
)revSelected
);
767 CAppUtils::LaunchApplication(sCmd
, NULL
, false);
772 CString url
= m_ProjectProperties
.sWebViewerRev
;
773 url
= GetAbsoluteUrlFromRelativeUrl(url
);
774 url
.Replace(_T("%REVISION%"), revSelected
.ToString());
776 ShellExecute(this->m_hWnd
, _T("open"), url
, NULL
, NULL
, SW_SHOWDEFAULT
);
781 CString relurl
= pathURL
;
782 CString sRoot
= GetRepositoryRoot(CTGitPath(relurl
));
783 relurl
= relurl
.Mid(sRoot
.GetLength());
784 CString url
= m_ProjectProperties
.sWebViewerPathRev
;
785 url
= GetAbsoluteUrlFromRelativeUrl(url
);
786 url
.Replace(_T("%REVISION%"), revSelected
.ToString());
787 url
.Replace(_T("%PATH%"), relurl
);
789 ShellExecute(this->m_hWnd
, _T("open"), url
, NULL
, NULL
, SW_SHOWDEFAULT
);
796 theApp
.DoWaitCursor(-1);
799 void CGitLogList::SetSelectedAction(int action
)
801 POSITION pos
= GetFirstSelectedItemPosition();
805 index
= GetNextSelectedItem(pos
);
806 ((GitRev
*)m_arShownList
[index
])->m_Action
= action
;
808 this->GetItemRect(index
,&rect
,LVIR_BOUNDS
);
809 this->InvalidateRect(rect
);