Enable security checks and features
[TortoiseGit.git] / src / TortoiseProc / RebaseDlg.cpp
blob20a4c5f172c9689b3764081051ebb125a8cdf949
1 // TortoiseGit - a Windows shell extension for easy version control
3 // Copyright (C) 2008-2011 - TortoiseGit
5 // This program is free software; you can redistribute it and/or
6 // modify it under the terms of the GNU General Public License
7 // as published by the Free Software Foundation; either version 2
8 // of the License, or (at your option) any later version.
10 // This program is distributed in the hope that it will be useful,
11 // but WITHOUT ANY WARRANTY; without even the implied warranty of
12 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 // GNU General Public License for more details.
15 // You should have received a copy of the GNU General Public License
16 // along with this program; if not, write to the Free Software Foundation,
17 // 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
20 // RebaseDlg.cpp : implementation file
23 #include "stdafx.h"
24 #include "TortoiseProc.h"
25 #include "RebaseDlg.h"
26 #include "AppUtils.h"
27 #include "MessageBox.h"
28 #include "UnicodeUtils.h"
29 #include "BrowseRefsDlg.h"
30 #include "ProgressDlg.h"
31 // CRebaseDlg dialog
33 IMPLEMENT_DYNAMIC(CRebaseDlg, CResizableStandAloneDialog)
35 CRebaseDlg::CRebaseDlg(CWnd* pParent /*=NULL*/)
36 : CResizableStandAloneDialog(CRebaseDlg::IDD, pParent)
37 , m_bPickAll(FALSE)
38 , m_bSquashAll(FALSE)
39 , m_bEditAll(FALSE)
41 m_RebaseStage=CHOOSE_BRANCH;
42 m_CurrentRebaseIndex=-1;
43 m_bThreadRunning =FALSE;
44 this->m_IsCherryPick = FALSE;
45 m_bForce=FALSE;
46 m_IsFastForward=FALSE;
49 CRebaseDlg::~CRebaseDlg()
53 void CRebaseDlg::DoDataExchange(CDataExchange* pDX)
55 CDialog::DoDataExchange(pDX);
56 DDX_Control(pDX, IDC_REBASE_PROGRESS, m_ProgressBar);
57 DDX_Control(pDX, IDC_STATUS_STATIC, m_CtrlStatusText);
58 DDX_Check(pDX, IDC_PICK_ALL, m_bPickAll);
59 DDX_Check(pDX, IDC_SQUASH_ALL, m_bSquashAll);
60 DDX_Check(pDX, IDC_EDIT_ALL, m_bEditAll);
61 DDX_Control(pDX, IDC_REBASE_SPLIT, m_wndSplitter);
62 DDX_Control(pDX,IDC_COMMIT_LIST,m_CommitList);
63 DDX_Control(pDX,IDC_REBASE_COMBOXEX_BRANCH, this->m_BranchCtrl);
64 DDX_Control(pDX,IDC_REBASE_COMBOXEX_UPSTREAM, this->m_UpstreamCtrl);
65 DDX_Check(pDX, IDC_REBASE_CHECK_FORCE,m_bForce);
66 DDX_Control(pDX,IDC_REBASE_POST_BUTTON,m_PostButton);
70 BEGIN_MESSAGE_MAP(CRebaseDlg, CResizableStandAloneDialog)
71 ON_BN_CLICKED(IDC_PICK_ALL, &CRebaseDlg::OnBnClickedPickAll)
72 ON_BN_CLICKED(IDC_SQUASH_ALL, &CRebaseDlg::OnBnClickedSquashAll)
73 ON_BN_CLICKED(IDC_EDIT_ALL, &CRebaseDlg::OnBnClickedEditAll)
74 ON_BN_CLICKED(IDC_REBASE_SPLIT, &CRebaseDlg::OnBnClickedRebaseSplit)
75 ON_BN_CLICKED(IDC_REBASE_CONTINUE,OnBnClickedContinue)
76 ON_BN_CLICKED(IDC_REBASE_ABORT, OnBnClickedAbort)
77 ON_WM_SIZE()
78 ON_CBN_SELCHANGE(IDC_REBASE_COMBOXEX_BRANCH, &CRebaseDlg::OnCbnSelchangeBranch)
79 ON_CBN_SELCHANGE(IDC_REBASE_COMBOXEX_UPSTREAM, &CRebaseDlg::OnCbnSelchangeUpstream)
80 ON_MESSAGE(MSG_REBASE_UPDATE_UI, OnRebaseUpdateUI)
81 ON_BN_CLICKED(IDC_BUTTON_BROWSE, &CRebaseDlg::OnBnClickedButtonBrowse)
82 ON_BN_CLICKED(IDC_REBASE_CHECK_FORCE, &CRebaseDlg::OnBnClickedRebaseCheckForce)
83 ON_BN_CLICKED(IDC_REBASE_POST_BUTTON, &CRebaseDlg::OnBnClickedRebasePostButton)
84 ON_BN_CLICKED(IDC_BUTTON_UP2, &CRebaseDlg::OnBnClickedButtonUp2)
85 ON_BN_CLICKED(IDC_BUTTON_DOWN2, &CRebaseDlg::OnBnClickedButtonDown2)
86 END_MESSAGE_MAP()
88 void CRebaseDlg::AddRebaseAnchor()
90 AddAnchor(IDC_REBASE_TAB,TOP_LEFT,BOTTOM_RIGHT);
91 AddAnchor(IDC_COMMIT_LIST,TOP_LEFT, TOP_RIGHT);
92 AddAnchor(IDC_REBASE_SPLIT,TOP_LEFT, TOP_RIGHT);
93 AddAnchor(IDC_STATUS_STATIC, BOTTOM_LEFT,BOTTOM_RIGHT);
94 AddAnchor(IDC_REBASE_CONTINUE,BOTTOM_RIGHT);
95 AddAnchor(IDC_REBASE_ABORT, BOTTOM_RIGHT);
96 AddAnchor(IDC_REBASE_PROGRESS,BOTTOM_LEFT, BOTTOM_RIGHT);
97 AddAnchor(IDC_PICK_ALL,TOP_LEFT);
98 AddAnchor(IDC_SQUASH_ALL,TOP_LEFT);
99 AddAnchor(IDC_EDIT_ALL,TOP_LEFT);
100 AddAnchor(IDC_BUTTON_UP2,TOP_LEFT);
101 AddAnchor(IDC_BUTTON_DOWN2,TOP_LEFT);
102 AddAnchor(IDC_REBASE_COMBOXEX_UPSTREAM,TOP_LEFT);
103 AddAnchor(IDC_REBASE_COMBOXEX_BRANCH,TOP_LEFT);
104 AddAnchor(IDC_REBASE_STATIC_UPSTREAM,TOP_LEFT);
105 AddAnchor(IDC_REBASE_STATIC_BRANCH,TOP_LEFT);
106 AddAnchor(IDHELP, BOTTOM_RIGHT);
107 AddAnchor(IDC_REBASE_CHECK_FORCE,TOP_RIGHT);
108 AddAnchor(IDC_REBASE_POST_BUTTON,BOTTOM_LEFT);
110 this->AddOthersToAnchor();
113 BOOL CRebaseDlg::OnInitDialog()
115 CResizableStandAloneDialog::OnInitDialog();
117 CRect rectDummy;
118 //IDC_REBASE_DUMY_TAB
120 GetClientRect(m_DlgOrigRect);
121 m_CommitList.GetClientRect(m_CommitListOrigRect);
123 CWnd *pwnd=this->GetDlgItem(IDC_REBASE_DUMY_TAB);
124 pwnd->GetWindowRect(&rectDummy);
125 this->ScreenToClient(rectDummy);
127 if (!m_ctrlTabCtrl.Create(CMFCTabCtrl::STYLE_FLAT, rectDummy, this, IDC_REBASE_TAB))
129 TRACE0("Failed to create output tab window\n");
130 return FALSE; // fail to create
132 m_ctrlTabCtrl.SetResizeMode(CMFCTabCtrl::RESIZE_NO);
133 // Create output panes:
134 //const DWORD dwStyle = LBS_NOINTEGRALHEIGHT | WS_CHILD | WS_VISIBLE | WS_HSCROLL | WS_VSCROLL;
135 DWORD dwStyle =LVS_REPORT | LVS_SHOWSELALWAYS | LVS_ALIGNLEFT | WS_BORDER | WS_TABSTOP |LVS_SINGLESEL |WS_CHILD | WS_VISIBLE;
137 if (! this->m_FileListCtrl.Create(dwStyle,rectDummy,&this->m_ctrlTabCtrl,0) )
139 TRACE0("Failed to create output windows\n");
140 return FALSE; // fail to create
143 if( ! this->m_LogMessageCtrl.Create(_T("Scintilla"),_T("source"),0,rectDummy,&m_ctrlTabCtrl,0,0) )
145 TRACE0("Failed to create log message control");
146 return FALSE;
148 m_LogMessageCtrl.Init(0);
150 dwStyle = LBS_NOINTEGRALHEIGHT | WS_CHILD | WS_VISIBLE | WS_HSCROLL | WS_VSCROLL;
152 if (!m_wndOutputRebase.Create(_T("Scintilla"),_T("source"),0,rectDummy, &m_ctrlTabCtrl, 0,0) )
154 TRACE0("Failed to create output windows\n");
155 return -1; // fail to create
157 m_wndOutputRebase.Init(0);
158 m_wndOutputRebase.Call(SCI_SETREADONLY, TRUE);
160 m_tooltips.Create(this);
162 m_tooltips.AddTool(IDC_REBASE_CHECK_FORCE,IDS_REBASE_FORCE_TT);
163 m_tooltips.AddTool(IDC_REBASE_ABORT,IDS_REBASE_ABORT_TT);
167 m_FileListCtrl.Init(SVNSLC_COLEXT | SVNSLC_COLSTATUS |SVNSLC_COLADD|SVNSLC_COLDEL , _T("RebaseDlg"),(SVNSLC_POPALL ^ SVNSLC_POPCOMMIT),false);
169 m_ctrlTabCtrl.AddTab(&m_FileListCtrl,_T("Conflict File"));
170 m_ctrlTabCtrl.AddTab(&m_LogMessageCtrl,_T("Commit Message"),1);
171 m_ctrlTabCtrl.AddTab(&m_wndOutputRebase,_T("Log"),2);
172 AddRebaseAnchor();
175 EnableSaveRestore(_T("RebaseDlg"));
177 DWORD yPos = CRegDWORD(_T("Software\\TortoiseGit\\TortoiseProc\\ResizableState\\RebaseDlgSizer"));
178 RECT rcDlg, rcLogMsg, rcFileList;
179 GetClientRect(&rcDlg);
180 m_CommitList.GetWindowRect(&rcLogMsg);
181 ScreenToClient(&rcLogMsg);
182 this->m_ctrlTabCtrl.GetWindowRect(&rcFileList);
183 ScreenToClient(&rcFileList);
184 if (yPos)
186 RECT rectSplitter;
187 m_wndSplitter.GetWindowRect(&rectSplitter);
188 ScreenToClient(&rectSplitter);
189 int delta = yPos - rectSplitter.top;
190 if ((rcLogMsg.bottom + delta > rcLogMsg.top)&&(rcLogMsg.bottom + delta < rcFileList.bottom - 30))
192 m_wndSplitter.SetWindowPos(NULL, 0, yPos, 0, 0, SWP_NOSIZE);
193 DoSize(delta);
197 if( this->m_RebaseStage == CHOOSE_BRANCH)
199 this->LoadBranchInfo();
201 }else
203 this->m_BranchCtrl.EnableWindow(FALSE);
204 this->m_UpstreamCtrl.EnableWindow(FALSE);
207 m_CommitList.m_ColumnRegKey = _T("Rebase");
208 m_CommitList.m_IsIDReplaceAction = TRUE;
209 // m_CommitList.m_IsOldFirst = TRUE;
210 m_CommitList.m_IsRebaseReplaceGraph = TRUE;
212 m_CommitList.InsertGitColumn();
214 this->SetControlEnable();
216 if(!this->m_PreCmd.IsEmpty())
218 CProgressDlg progress;
219 progress.m_GitCmd=m_PreCmd;
220 progress.m_bAutoCloseOnSuccess=true;
221 progress.DoModal();
224 if(m_IsCherryPick)
226 this->m_BranchCtrl.SetCurSel(-1);
227 this->m_BranchCtrl.EnableWindow(FALSE);
228 this->m_UpstreamCtrl.EnableWindow(FALSE);
229 this->SetWindowText(_T("Cherry Pick"));
230 this->m_CommitList.StartFilter();
232 }else
234 SetContinueButtonText();
235 m_CommitList.DeleteAllItems();
236 FetchLogList();
239 m_CommitList.m_ContextMenuMask &= ~(m_CommitList.GetContextMenuBit(CGitLogListBase::ID_CHERRY_PICK)|
240 m_CommitList.GetContextMenuBit(CGitLogListBase::ID_SWITCHTOREV)|
241 m_CommitList.GetContextMenuBit(CGitLogListBase::ID_RESET)|
242 m_CommitList.GetContextMenuBit(CGitLogListBase::ID_REVERTREV)|
243 m_CommitList.GetContextMenuBit(CGitLogListBase::ID_REBASE_TO_VERSION)|
244 m_CommitList.GetContextMenuBit(CGitLogListBase::ID_REVERTTOREV)|
245 m_CommitList.GetContextMenuBit(CGitLogListBase::ID_COMBINE_COMMIT));
247 if(m_CommitList.m_IsOldFirst)
248 this->m_CurrentRebaseIndex = -1;
249 else
250 this->m_CurrentRebaseIndex = m_CommitList.m_logEntries.size();
253 if(this->CheckRebaseCondition())
255 /* Disable Start Rebase */
256 this->GetDlgItem(IDC_REBASE_CONTINUE)->EnableWindow(FALSE);
259 return TRUE;
261 // CRebaseDlg message handlers
263 void CRebaseDlg::OnBnClickedPickAll()
265 this->UpdateData();
266 if(this->m_bPickAll)
267 this->SetAllRebaseAction(CTGitPath::LOGACTIONS_REBASE_PICK);
269 this->m_bEditAll=FALSE;
270 this->m_bSquashAll=FALSE;
271 this->UpdateData(FALSE);
274 void CRebaseDlg::OnBnClickedSquashAll()
276 this->UpdateData();
277 if(this->m_bSquashAll)
278 this->SetAllRebaseAction(CTGitPath::LOGACTIONS_REBASE_SQUASH);
280 this->m_bEditAll=FALSE;
281 this->m_bPickAll=FALSE;
282 this->UpdateData(FALSE);
285 void CRebaseDlg::OnBnClickedEditAll()
287 this->UpdateData();
288 if( this->m_bEditAll )
289 this->SetAllRebaseAction(CTGitPath::LOGACTIONS_REBASE_EDIT);
291 this->m_bPickAll=FALSE;
292 this->m_bSquashAll=FALSE;
293 this->UpdateData(FALSE);
296 void CRebaseDlg::SetAllRebaseAction(int action)
298 for(int i=0;i<this->m_CommitList.m_logEntries.size();i++)
300 m_CommitList.m_logEntries.GetGitRevAt(i).GetAction(&m_CommitList)=action;
302 m_CommitList.Invalidate();
305 void CRebaseDlg::OnBnClickedRebaseSplit()
307 this->UpdateData();
310 LRESULT CRebaseDlg::DefWindowProc(UINT message, WPARAM wParam, LPARAM lParam)
312 switch (message) {
313 case WM_NOTIFY:
314 if (wParam == IDC_REBASE_SPLIT)
316 SPC_NMHDR* pHdr = (SPC_NMHDR*) lParam;
317 DoSize(pHdr->delta);
319 break;
322 return __super::DefWindowProc(message, wParam, lParam);
325 void CRebaseDlg::DoSize(int delta)
327 this->RemoveAllAnchors();
329 CSplitterControl::ChangeHeight(GetDlgItem(IDC_COMMIT_LIST), delta, CW_TOPALIGN);
330 //CSplitterControl::ChangeHeight(GetDlgItem(), delta, CW_TOPALIGN);
331 CSplitterControl::ChangeHeight(GetDlgItem(IDC_REBASE_TAB), -delta, CW_BOTTOMALIGN);
332 //CSplitterControl::ChangeHeight(GetDlgItem(), -delta, CW_BOTTOMALIGN);
333 CSplitterControl::ChangePos(GetDlgItem(IDC_SQUASH_ALL),0,delta);
334 CSplitterControl::ChangePos(GetDlgItem(IDC_PICK_ALL),0,delta);
335 CSplitterControl::ChangePos(GetDlgItem(IDC_EDIT_ALL),0,delta);
336 CSplitterControl::ChangePos(GetDlgItem(IDC_BUTTON_UP2),0,delta);
337 CSplitterControl::ChangePos(GetDlgItem(IDC_BUTTON_DOWN2),0,delta);
338 CSplitterControl::ChangePos(GetDlgItem(IDC_REBASE_CHECK_FORCE),0,delta);
340 this->AddRebaseAnchor();
341 // adjust the minimum size of the dialog to prevent the resizing from
342 // moving the list control too far down.
343 CRect rcLogMsg;
344 m_CommitList.GetClientRect(rcLogMsg);
345 SetMinTrackSize(CSize(m_DlgOrigRect.Width(), m_DlgOrigRect.Height()-m_CommitListOrigRect.Height()+rcLogMsg.Height()));
347 SetSplitterRange();
348 // m_CommitList.Invalidate();
350 // GetDlgItem(IDC_LOGMESSAGE)->Invalidate();
352 this->m_ctrlTabCtrl.Invalidate();
353 this->m_CommitList.Invalidate();
354 this->m_FileListCtrl.Invalidate();
355 this->m_LogMessageCtrl.Invalidate();
359 void CRebaseDlg::SetSplitterRange()
361 if ((m_CommitList)&&(m_ctrlTabCtrl))
363 CRect rcTop;
364 m_CommitList.GetWindowRect(rcTop);
365 ScreenToClient(rcTop);
366 CRect rcMiddle;
367 m_ctrlTabCtrl.GetWindowRect(rcMiddle);
368 ScreenToClient(rcMiddle);
369 if (rcMiddle.Height() && rcMiddle.Width())
370 m_wndSplitter.SetRange(rcTop.top+60, rcMiddle.bottom-80);
374 void CRebaseDlg::OnSize(UINT nType,int cx, int cy)
376 // first, let the resizing take place
377 __super::OnSize(nType, cx, cy);
379 //set range
380 SetSplitterRange();
383 void CRebaseDlg::SaveSplitterPos()
385 if (!IsIconic())
387 CRegDWORD regPos = CRegDWORD(_T("Software\\TortoiseGit\\TortoiseProc\\ResizableState\\RebaseDlgSizer"));
388 RECT rectSplitter;
389 m_wndSplitter.GetWindowRect(&rectSplitter);
390 ScreenToClient(&rectSplitter);
391 regPos = rectSplitter.top;
395 void CRebaseDlg::LoadBranchInfo()
397 m_BranchCtrl.SetMaxHistoryItems(0x7FFFFFFF);
398 m_UpstreamCtrl.SetMaxHistoryItems(0x7FFFFFFF);
400 STRING_VECTOR list;
401 list.clear();
402 int current;
403 g_Git.GetBranchList(list,&current,CGit::BRANCH_ALL);
404 m_BranchCtrl.AddString(list);
405 m_UpstreamCtrl.AddString(list);
407 m_BranchCtrl.SetCurSel(current);
409 AddBranchToolTips(&m_BranchCtrl);
410 AddBranchToolTips(&m_UpstreamCtrl);
412 if(!m_Upstream.IsEmpty())
414 m_UpstreamCtrl.AddString(m_Upstream);
415 m_UpstreamCtrl.SetCurSel(m_UpstreamCtrl.GetCount()-1);
417 else
419 //Select pull-remote from current branch
420 CString currentBranch = g_Git.GetSymbolicRef();
421 CString configName;
422 configName.Format(L"branch.%s.remote", currentBranch);
423 CString pullRemote = g_Git.GetConfigValue(configName);
425 //Select pull-branch from current branch
426 configName.Format(L"branch.%s.merge", currentBranch);
427 CString pullBranch = CGit::StripRefName(g_Git.GetConfigValue(configName));
429 CString defaultUpstream;
430 defaultUpstream.Format(L"remotes/%s/%s", pullRemote, pullBranch);
431 int found = m_UpstreamCtrl.FindStringExact(0, defaultUpstream);
432 if(found >= 0)
433 m_UpstreamCtrl.SetCurSel(found);
437 void CRebaseDlg::OnCbnSelchangeBranch()
439 FetchLogList();
442 void CRebaseDlg::OnCbnSelchangeUpstream()
444 FetchLogList();
447 void CRebaseDlg::FetchLogList()
449 CGitHash base,hash;
450 CString basestr;
451 CString cmd;
452 m_IsFastForward=FALSE;
453 cmd.Format(_T("git.exe merge-base %s %s"), m_UpstreamCtrl.GetString(),m_BranchCtrl.GetString());
454 if(g_Git.Run(cmd,&basestr,CP_ACP))
456 CMessageBox::Show(NULL,basestr,_T("TortoiseGit"),MB_OK|MB_ICONERROR);
457 return;
459 base=basestr;
461 hash=g_Git.GetHash(m_BranchCtrl.GetString());
463 if(hash == g_Git.GetHash(this->m_UpstreamCtrl.GetString()))
465 m_CommitList.Clear();
466 CString text,fmt;
467 fmt.LoadString(IDS_REBASE_EQUAL_FMT);
468 text.Format(fmt,m_BranchCtrl.GetString(),this->m_UpstreamCtrl.GetString());
470 m_CommitList.ShowText(text);
471 this->GetDlgItem(IDC_REBASE_CONTINUE)->EnableWindow(false);
472 return;
475 if(hash == base )
477 //fast forword
478 this->m_IsFastForward=TRUE;
480 m_CommitList.Clear();
481 CString text,fmt;
482 fmt.LoadString(IDS_REBASE_FASTFORWARD_FMT);
483 text.Format(fmt,m_BranchCtrl.GetString(),this->m_UpstreamCtrl.GetString(),
484 m_BranchCtrl.GetString(),this->m_UpstreamCtrl.GetString());
486 m_CommitList.ShowText(text);
487 this->GetDlgItem(IDC_REBASE_CONTINUE)->EnableWindow(true);
488 SetContinueButtonText();
490 return ;
493 hash.Empty();
495 if(!this->m_bForce)
497 hash=g_Git.GetHash(m_UpstreamCtrl.GetString());
499 if( base == hash )
501 m_CommitList.Clear();
502 CString text,fmt;
503 fmt.LoadString(IDS_REBASE_UPTODATE_FMT);
504 text.Format(fmt,m_BranchCtrl.GetString());
505 m_CommitList.ShowText(text);
506 this->GetDlgItem(IDC_REBASE_CONTINUE)->EnableWindow(m_CommitList.GetItemCount());
507 SetContinueButtonText();
508 return;
512 m_CommitList.Clear();
513 CString from,to;
514 from = m_UpstreamCtrl.GetString();
515 to = m_BranchCtrl.GetString();
516 this->m_CommitList.FillGitLog(NULL,0,&from,&to);
518 if( m_CommitList.GetItemCount() == 0 )
519 m_CommitList.ShowText(_T("Nothing to Rebase"));
521 hash=g_Git.GetHash(m_UpstreamCtrl.GetString());
523 #if 0
524 if(m_CommitList.m_logEntries[m_CommitList.m_logEntries.size()-1].m_ParentHash.size() >=0 )
526 if(hash == m_CommitList.m_logEntries[m_CommitList.m_logEntries.size()-1].m_ParentHash[0])
528 m_CommitList.Clear();
529 m_CommitList.ShowText(_T("Nothing Rebase"));
532 #endif
534 m_tooltips.Pop();
535 AddBranchToolTips(&this->m_BranchCtrl);
536 AddBranchToolTips(&this->m_UpstreamCtrl);
538 for(int i=0;i<m_CommitList.m_logEntries.size();i++)
540 m_CommitList.m_logEntries.GetGitRevAt(i).GetAction(&m_CommitList) = CTGitPath::LOGACTIONS_REBASE_PICK;
543 m_CommitList.Invalidate();
545 if(m_CommitList.m_IsOldFirst)
546 this->m_CurrentRebaseIndex = -1;
547 else
548 this->m_CurrentRebaseIndex = m_CommitList.m_logEntries.size();
550 this->GetDlgItem(IDC_REBASE_CONTINUE)->EnableWindow(m_CommitList.GetItemCount());
551 SetContinueButtonText();
554 void CRebaseDlg::AddBranchToolTips(CHistoryCombo *pBranch)
556 if(pBranch)
558 CString text=pBranch->GetString();
559 CString tooltip;
561 GitRev rev;
562 rev.GetCommit(text);
564 tooltip.Format(_T("CommitHash:%s\nCommit by: %s %s\n <b>%s</b> \n %s"),
565 rev.m_CommitHash.ToString(),
566 rev.GetAuthorName(),
567 CAppUtils::FormatDateAndTime(rev.GetAuthorDate(),DATE_LONGDATE),
568 rev.GetSubject(),
569 rev.GetBody());
571 pBranch->DisableTooltip();
572 this->m_tooltips.AddTool(pBranch->GetComboBoxCtrl(),tooltip);
576 BOOL CRebaseDlg::PreTranslateMessage(MSG*pMsg)
578 if (pMsg->message == WM_KEYDOWN)
580 switch (pMsg->wParam)
583 case VK_F5:
585 Refresh();
586 return TRUE;
588 break;
589 /* Avoid TAB control destroy but dialog exist*/
590 case VK_ESCAPE:
591 case VK_CANCEL:
593 TCHAR buff[128];
594 ::GetClassName(pMsg->hwnd,buff,128);
597 if(_tcsnicmp(buff,_T("RichEdit20W"),128)==0 ||
598 _tcsnicmp(buff,_T("Scintilla"),128)==0 ||
599 _tcsnicmp(buff,_T("SysListView32"),128)==0||
600 ::GetParent(pMsg->hwnd) == this->m_ctrlTabCtrl.m_hWnd)
602 this->PostMessage(WM_KEYDOWN,VK_ESCAPE,0);
603 return TRUE;
608 m_tooltips.RelayEvent(pMsg);
609 return CResizableStandAloneDialog::PreTranslateMessage(pMsg);
611 int CRebaseDlg::CheckRebaseCondition()
613 this->m_ctrlTabCtrl.SetActiveTab(REBASE_TAB_LOG);
615 if( !g_Git.CheckCleanWorkTree() )
617 if(CMessageBox::Show(NULL, IDS_ERROR_NOCLEAN_STASH,IDS_APPNAME,MB_YESNO|MB_ICONINFORMATION)==IDYES)
619 CString cmd,out;
620 cmd=_T("git.exe stash");
621 this->AddLogString(cmd);
622 if(g_Git.Run(cmd,&out,CP_ACP))
624 CMessageBox::Show(NULL,out,_T("TortoiseGit"),MB_OK);
625 return -1;
628 }else
629 return -1;
631 //Todo Check $REBASE_ROOT
632 //Todo Check $DOTEST
634 CString cmd;
635 cmd=_T("git.exe var GIT_COMMITTER_IDENT");
636 if(g_Git.Run(cmd,NULL,CP_UTF8))
637 return -1;
639 //Todo call pre_rebase_hook
640 return 0;
642 int CRebaseDlg::StartRebase()
644 CString cmd,out;
645 m_FileListCtrl.m_bIsRevertTheirMy = !m_IsCherryPick;
646 if(!this->m_IsCherryPick)
648 //Todo call comment_for_reflog
649 cmd.Format(_T("git.exe checkout %s"),this->m_BranchCtrl.GetString());
650 this->AddLogString(cmd);
652 if(g_Git.Run(cmd,&out,CP_UTF8))
653 return -1;
655 this->AddLogString(out);
658 cmd=_T("git.exe rev-parse --verify HEAD");
659 if(g_Git.Run(cmd,&out,CP_UTF8))
661 AddLogString(_T("No Head"));
662 return -1;
664 //Todo
665 //git symbolic-ref HEAD > "$DOTEST"/head-name 2> /dev/null ||
666 // echo "detached HEAD" > "$DOTEST"/head-name
668 cmd.Format(_T("git.exe update-ref ORIG_HEAD HEAD"));
669 if(g_Git.Run(cmd,&out,CP_UTF8))
671 AddLogString(_T("update ORIG_HEAD Fail"));
672 return -1;
675 m_OrigUpstreamHash.Empty();
676 m_OrigUpstreamHash= g_Git.GetHash(this->m_UpstreamCtrl.GetString());
677 if(m_OrigUpstreamHash.IsEmpty())
679 this->AddLogString(m_OrigUpstreamHash);
680 return -1;
683 if( !this->m_IsCherryPick )
685 cmd.Format(_T("git.exe checkout -f %s"), m_OrigUpstreamHash.ToString());
686 this->AddLogString(cmd);
688 out.Empty();
689 if(g_Git.Run(cmd,&out,CP_UTF8))
691 this->AddLogString(out);
692 return -1;
696 if( !this->m_IsCherryPick )
698 m_OrigBranchHash = g_Git.GetHash(this->m_BranchCtrl.GetString());
699 if(m_OrigBranchHash.IsEmpty())
701 this->AddLogString(m_OrigBranchHash.ToString());
702 return -1;
704 this->AddLogString(_T("Start Rebase\r\n"));
706 }else
707 this->AddLogString(_T("Start Cherry-pick\r\n"));
709 return 0;
711 int CRebaseDlg::VerifyNoConflict()
713 CTGitPathList list;
714 if(g_Git.ListConflictFile(list))
716 AddLogString(_T("Get conflict files fail"));
717 return -1;
719 if( list.GetCount() != 0 )
721 CMessageBox::Show(NULL,_T("There are conflict file, you should mark it resolve"),_T("TortoiseGit"),MB_OK);
722 return -1;
724 return 0;
727 int CRebaseDlg::FinishRebase()
729 if(this->m_IsCherryPick) //cherry pick mode no "branch", working at upstream branch
730 return 0;
732 git_revnum_t head = g_Git.GetHash(_T("HEAD"));
733 CString out,cmd;
735 out.Empty();
736 cmd.Format(_T("git.exe checkout -f %s"),this->m_BranchCtrl.GetString());
737 AddLogString(cmd);
738 if(g_Git.Run(cmd,&out,CP_UTF8))
740 AddLogString(out);
741 return -1;
743 AddLogString(out);
745 out.Empty();
746 cmd.Format(_T("git.exe reset --hard %s"),head);
747 AddLogString(cmd);
748 if(g_Git.Run(cmd,&out,CP_UTF8))
750 AddLogString(out);
751 return -1;
753 AddLogString(out);
755 return 0;
757 void CRebaseDlg::OnBnClickedContinue()
759 if( m_RebaseStage == REBASE_DONE)
761 OnOK();
762 return;
765 if( this->m_IsFastForward )
767 CString cmd,out;
768 CString oldbranch = g_Git.GetCurrentBranch();
769 if( oldbranch != m_BranchCtrl.GetString() )
771 cmd.Format(_T("git.exe checkout %s"),m_BranchCtrl.GetString());
772 AddLogString(cmd);
773 if( g_Git.Run(cmd,&out,CP_ACP) )
775 this->m_ctrlTabCtrl.SetActiveTab(REBASE_TAB_LOG);
776 AddLogString(out);
777 return;
780 AddLogString(out);
781 out.Empty();
782 m_OrigBranchHash = g_Git.GetHash(m_BranchCtrl.GetString());
783 m_OrigUpstreamHash = g_Git.GetHash(this->m_UpstreamCtrl.GetString());
785 if(!g_Git.IsFastForward(this->m_BranchCtrl.GetString(),this->m_UpstreamCtrl.GetString()))
787 this->m_ctrlTabCtrl.SetActiveTab(REBASE_TAB_LOG);
788 AddLogString(_T("No fast forward\r\nMaybe repository changed"));
789 return;
792 cmd.Format(_T("git.exe reset --hard %s"),this->m_UpstreamCtrl.GetString());
793 this->AddLogString(CString(_T("Fast forward to "))+m_UpstreamCtrl.GetString());
795 AddLogString(cmd);
796 this->m_ctrlTabCtrl.SetActiveTab(REBASE_TAB_LOG);
797 if(g_Git.Run(cmd,&out,CP_ACP))
799 AddLogString(_T("Fail"));
800 AddLogString(out);
801 return;
803 AddLogString(out);
804 AddLogString(_T("Done"));
805 m_RebaseStage = REBASE_DONE;
806 UpdateCurrentStatus();
807 return;
810 if( m_RebaseStage == CHOOSE_BRANCH|| m_RebaseStage == CHOOSE_COMMIT_PICK_MODE )
812 if(CheckRebaseCondition())
813 return ;
814 m_RebaseStage = REBASE_START;
817 if( m_RebaseStage == REBASE_FINISH )
819 if(FinishRebase())
820 return ;
822 OnOK();
825 if( m_RebaseStage == REBASE_SQUASH_CONFLICT)
827 if(VerifyNoConflict())
828 return;
829 GitRev *curRev=(GitRev*)m_CommitList.m_arShownList[m_CurrentRebaseIndex];
830 if(this->CheckNextCommitIsSquash())
831 {//next commit is not squash;
832 m_RebaseStage = REBASE_SQUASH_EDIT;
833 this->OnRebaseUpdateUI(0,0);
834 this->UpdateCurrentStatus();
835 return ;
838 m_RebaseStage=REBASE_CONTINUE;
839 curRev->GetAction(&m_CommitList)|=CTGitPath::LOGACTIONS_REBASE_DONE;
840 this->UpdateCurrentStatus();
844 if( m_RebaseStage == REBASE_CONFLICT )
846 if(VerifyNoConflict())
847 return;
849 GitRev *curRev=(GitRev*)m_CommitList.m_arShownList[m_CurrentRebaseIndex];
851 CString out =_T("");
852 CString cmd;
853 cmd.Format(_T("git.exe commit -C %s"), curRev->m_CommitHash.ToString());
855 AddLogString(cmd);
857 if(g_Git.Run(cmd,&out,CP_UTF8))
859 AddLogString(out);
860 if(!g_Git.CheckCleanWorkTree())
862 CMessageBox::Show(NULL,out,_T("TortoiseGit"),MB_OK|MB_ICONERROR);
863 return;
867 AddLogString(out);
868 this->m_ctrlTabCtrl.SetActiveTab(REBASE_TAB_LOG);
869 if( curRev->GetAction(&m_CommitList) & CTGitPath::LOGACTIONS_REBASE_EDIT)
871 m_RebaseStage=REBASE_EDIT;
872 this->m_ctrlTabCtrl.SetActiveTab(REBASE_TAB_MESSAGE);
873 this->UpdateCurrentStatus();
874 return;
876 else
878 m_RebaseStage=REBASE_CONTINUE;
879 curRev->GetAction(&m_CommitList)|=CTGitPath::LOGACTIONS_REBASE_DONE;
880 this->UpdateCurrentStatus();
884 if( m_RebaseStage == REBASE_EDIT || m_RebaseStage == REBASE_SQUASH_EDIT )
886 CString str;
887 GitRev *curRev=(GitRev*)m_CommitList.m_arShownList[m_CurrentRebaseIndex];
889 str=this->m_LogMessageCtrl.GetText();
890 if(str.Trim().IsEmpty())
892 CMessageBox::Show(NULL,_T("Commit Message Is Empty"),_T("TortoiseGit"),MB_OK|MB_ICONERROR);
893 return;
896 CString tempfile=::GetTempFile();
897 CFile file(tempfile,CFile::modeReadWrite|CFile::modeCreate );
898 CStringA log=CUnicodeUtils::GetUTF8( str);
899 file.Write(log,log.GetLength());
900 //file.WriteString(m_sLogMessage);
901 file.Close();
903 CString out,cmd;
905 if( m_RebaseStage == REBASE_SQUASH_EDIT )
906 cmd.Format(_T("git.exe commit -F \"%s\""), tempfile);
907 else
908 cmd.Format(_T("git.exe commit --amend -F \"%s\""), tempfile);
910 if(g_Git.Run(cmd,&out,CP_UTF8))
912 if(!g_Git.CheckCleanWorkTree())
914 CMessageBox::Show(NULL,out,_T("TortoiseGit"),MB_OK|MB_ICONERROR);
915 return;
919 CFile::Remove(tempfile);
920 AddLogString(out);
921 this->m_ctrlTabCtrl.SetActiveTab(REBASE_TAB_LOG);
922 m_RebaseStage=REBASE_CONTINUE;
923 curRev->GetAction(&m_CommitList)|=CTGitPath::LOGACTIONS_REBASE_DONE;
924 this->UpdateCurrentStatus();
928 InterlockedExchange(&m_bThreadRunning, TRUE);
929 SetControlEnable();
931 if (AfxBeginThread(RebaseThreadEntry, this)==NULL)
933 InterlockedExchange(&m_bThreadRunning, FALSE);
934 CMessageBox::Show(NULL, _T("Create Rebase Thread Fail"), _T("TortoiseGit"), MB_OK | MB_ICONERROR);
935 SetControlEnable();
938 int CRebaseDlg::CheckNextCommitIsSquash()
940 int index;
941 if(m_CommitList.m_IsOldFirst)
942 index=m_CurrentRebaseIndex+1;
943 else
944 index=m_CurrentRebaseIndex-1;
946 GitRev *curRev;
949 if(index<0)
950 return -1;
951 if(index>= m_CommitList.GetItemCount())
952 return -1;
954 curRev=(GitRev*)m_CommitList.m_arShownList[index];
956 if( curRev->GetAction(&m_CommitList)&CTGitPath::LOGACTIONS_REBASE_SQUASH )
957 return 0;
958 if( curRev->GetAction(&m_CommitList)&CTGitPath::LOGACTIONS_REBASE_SKIP)
960 if(m_CommitList.m_IsOldFirst)
961 index++;
962 else
963 index--;
964 }else
965 return -1;
967 }while(curRev->GetAction(&m_CommitList)&CTGitPath::LOGACTIONS_REBASE_SKIP);
969 return -1;
972 int CRebaseDlg::GoNext()
974 if(m_CommitList.m_IsOldFirst)
975 m_CurrentRebaseIndex++;
976 else
977 m_CurrentRebaseIndex--;
978 return 0;
981 int CRebaseDlg::StateAction()
983 switch(this->m_RebaseStage)
985 case CHOOSE_BRANCH:
986 case CHOOSE_COMMIT_PICK_MODE:
987 if(StartRebase())
988 return -1;
989 m_RebaseStage = REBASE_START;
990 GoNext();
991 break;
994 return 0;
996 void CRebaseDlg::SetContinueButtonText()
998 CString Text;
999 switch(this->m_RebaseStage)
1001 case CHOOSE_BRANCH:
1002 case CHOOSE_COMMIT_PICK_MODE:
1003 if(this->m_IsFastForward)
1004 Text = _T("Start(FastFwd)");
1005 else
1006 Text = _T("Start");
1007 break;
1009 case REBASE_START:
1010 case REBASE_CONTINUE:
1011 case REBASE_SQUASH_CONFLICT:
1012 Text = _T("Continue");
1013 break;
1015 case REBASE_CONFLICT:
1016 Text = _T("Commit");
1017 break;
1018 case REBASE_EDIT:
1019 Text = _T("Amend");
1020 break;
1022 case REBASE_SQUASH_EDIT:
1023 Text = _T("Commit");
1024 break;
1026 case REBASE_ABORT:
1027 case REBASE_FINISH:
1028 Text = _T("Finish");
1029 break;
1031 case REBASE_DONE:
1032 Text = _T("Done");
1033 break;
1035 this->GetDlgItem(IDC_REBASE_CONTINUE)->SetWindowText(Text);
1038 void CRebaseDlg::SetControlEnable()
1040 switch(this->m_RebaseStage)
1042 case CHOOSE_BRANCH:
1043 case CHOOSE_COMMIT_PICK_MODE:
1045 this->GetDlgItem(IDC_PICK_ALL)->EnableWindow(TRUE);
1046 this->GetDlgItem(IDC_EDIT_ALL)->EnableWindow(TRUE);
1047 this->GetDlgItem(IDC_SQUASH_ALL)->EnableWindow(TRUE);
1048 this->GetDlgItem(IDC_BUTTON_UP2)->EnableWindow(TRUE);
1049 this->GetDlgItem(IDC_BUTTON_DOWN2)->EnableWindow(TRUE);
1051 if(!m_IsCherryPick)
1053 this->GetDlgItem(IDC_REBASE_COMBOXEX_BRANCH)->EnableWindow(TRUE);
1054 this->GetDlgItem(IDC_REBASE_COMBOXEX_UPSTREAM)->EnableWindow(TRUE);
1055 this->GetDlgItem(IDC_REBASE_CHECK_FORCE)->EnableWindow(TRUE);
1057 //this->m_CommitList.m_IsEnableRebaseMenu=TRUE;
1058 this->m_CommitList.m_ContextMenuMask |= m_CommitList.GetContextMenuBit(CGitLogListBase::ID_REBASE_PICK)|
1059 m_CommitList.GetContextMenuBit(CGitLogListBase::ID_REBASE_SQUASH)|
1060 m_CommitList.GetContextMenuBit(CGitLogListBase::ID_REBASE_EDIT)|
1061 m_CommitList.GetContextMenuBit(CGitLogListBase::ID_REBASE_SKIP);
1062 break;
1064 case REBASE_START:
1065 case REBASE_CONTINUE:
1066 case REBASE_ABORT:
1067 case REBASE_FINISH:
1068 case REBASE_CONFLICT:
1069 case REBASE_EDIT:
1070 case REBASE_SQUASH_CONFLICT:
1071 case REBASE_DONE:
1072 this->GetDlgItem(IDC_PICK_ALL)->EnableWindow(FALSE);
1073 this->GetDlgItem(IDC_EDIT_ALL)->EnableWindow(FALSE);
1074 this->GetDlgItem(IDC_SQUASH_ALL)->EnableWindow(FALSE);
1075 this->GetDlgItem(IDC_REBASE_COMBOXEX_BRANCH)->EnableWindow(FALSE);
1076 this->GetDlgItem(IDC_REBASE_COMBOXEX_UPSTREAM)->EnableWindow(FALSE);
1077 this->GetDlgItem(IDC_REBASE_CHECK_FORCE)->EnableWindow(FALSE);
1078 this->GetDlgItem(IDC_BUTTON_UP2)->EnableWindow(FALSE);
1079 this->GetDlgItem(IDC_BUTTON_DOWN2)->EnableWindow(FALSE);
1080 //this->m_CommitList.m_IsEnableRebaseMenu=FALSE;
1081 this->m_CommitList.m_ContextMenuMask &= ~(m_CommitList.GetContextMenuBit(CGitLogListBase::ID_REBASE_PICK)|
1082 m_CommitList.GetContextMenuBit(CGitLogListBase::ID_REBASE_SQUASH)|
1083 m_CommitList.GetContextMenuBit(CGitLogListBase::ID_REBASE_EDIT)|
1084 m_CommitList.GetContextMenuBit(CGitLogListBase::ID_REBASE_SKIP));
1086 if( m_RebaseStage == REBASE_DONE && (this->m_PostButtonTexts.GetCount() != 0) )
1088 this->GetDlgItem(IDC_STATUS_STATIC)->ShowWindow(SW_HIDE);
1089 this->GetDlgItem(IDC_REBASE_POST_BUTTON)->ShowWindow(SW_SHOWNORMAL);
1090 this->m_PostButton.RemoveAll();
1091 this->m_PostButton.AddEntries(m_PostButtonTexts);
1092 //this->GetDlgItem(IDC_REBASE_POST_BUTTON)->SetWindowText(this->m_PostButtonText);
1094 break;
1097 if(m_bThreadRunning)
1099 this->GetDlgItem(IDC_REBASE_CONTINUE)->EnableWindow(FALSE);
1100 this->GetDlgItem(IDC_REBASE_ABORT)->EnableWindow(FALSE);
1102 }else
1104 this->GetDlgItem(IDC_REBASE_CONTINUE)->EnableWindow(TRUE);
1105 this->GetDlgItem(IDC_REBASE_ABORT)->EnableWindow(TRUE);
1109 void CRebaseDlg::UpdateProgress()
1111 int index;
1112 CRect rect;
1114 if(m_CommitList.m_IsOldFirst)
1115 index = m_CurrentRebaseIndex+1;
1116 else
1117 index = m_CommitList.GetItemCount()-m_CurrentRebaseIndex;
1119 m_ProgressBar.SetRange(1,m_CommitList.GetItemCount());
1120 m_ProgressBar.SetPos(index);
1122 if(m_CurrentRebaseIndex>=0 && m_CurrentRebaseIndex< m_CommitList.GetItemCount())
1124 CString text;
1125 text.Format(_T("Rebasing...(%d/%d)"),index,m_CommitList.GetItemCount());
1126 m_CtrlStatusText.SetWindowText(text);
1130 GitRev *prevRev=NULL, *curRev=NULL;
1132 if( m_CurrentRebaseIndex >= 0 && m_CurrentRebaseIndex< m_CommitList.m_arShownList.GetSize())
1134 curRev=(GitRev*)m_CommitList.m_arShownList[m_CurrentRebaseIndex];
1137 for(int i=0;i<m_CommitList.m_arShownList.GetSize();i++)
1139 prevRev=(GitRev*)m_CommitList.m_arShownList[i];
1140 if(prevRev->GetAction(&m_CommitList) & CTGitPath::LOGACTIONS_REBASE_CURRENT)
1142 prevRev->GetAction(&m_CommitList) &= ~ CTGitPath::LOGACTIONS_REBASE_CURRENT;
1143 m_CommitList.GetItemRect(i,&rect,LVIR_BOUNDS);
1144 m_CommitList.InvalidateRect(rect);
1148 if(curRev)
1150 curRev->GetAction(&m_CommitList) |= CTGitPath::LOGACTIONS_REBASE_CURRENT;
1151 m_CommitList.GetItemRect(m_CurrentRebaseIndex,&rect,LVIR_BOUNDS);
1152 m_CommitList.InvalidateRect(rect);
1154 m_CommitList.EnsureVisible(m_CurrentRebaseIndex,FALSE);
1157 void CRebaseDlg::UpdateCurrentStatus()
1159 if( m_CurrentRebaseIndex < 0 && m_RebaseStage!= REBASE_DONE)
1161 if(m_CommitList.m_IsOldFirst)
1162 m_RebaseStage = CRebaseDlg::REBASE_START;
1163 else
1164 m_RebaseStage = CRebaseDlg::REBASE_FINISH;
1167 if( m_CurrentRebaseIndex == m_CommitList.m_arShownList.GetSize() && m_RebaseStage!= REBASE_DONE)
1169 if(m_CommitList.m_IsOldFirst)
1170 m_RebaseStage = CRebaseDlg::REBASE_DONE;
1171 else
1172 m_RebaseStage = CRebaseDlg::REBASE_FINISH;
1175 SetContinueButtonText();
1176 SetControlEnable();
1177 UpdateProgress();
1180 void CRebaseDlg::AddLogString(CString str)
1182 this->m_wndOutputRebase.SendMessage(SCI_SETREADONLY, FALSE);
1183 CStringA sTextA = m_wndOutputRebase.StringForControl(str);//CUnicodeUtils::GetUTF8(str);
1184 this->m_wndOutputRebase.SendMessage(SCI_REPLACESEL, 0, (LPARAM)(LPCSTR)sTextA);
1185 this->m_wndOutputRebase.SendMessage(SCI_REPLACESEL, 0, (LPARAM)(LPCSTR)"\n");
1186 this->m_wndOutputRebase.SendMessage(SCI_SETREADONLY, TRUE);
1189 int CRebaseDlg::GetCurrentCommitID()
1191 if(m_CommitList.m_IsOldFirst)
1193 return this->m_CurrentRebaseIndex+1;
1195 }else
1197 return m_CommitList.GetItemCount()-m_CurrentRebaseIndex;
1201 int CRebaseDlg::DoRebase()
1203 CString cmd,out;
1204 if(m_CurrentRebaseIndex <0)
1205 return 0;
1206 if(m_CurrentRebaseIndex >= m_CommitList.GetItemCount() )
1207 return 0;
1209 GitRev *pRev = (GitRev*)m_CommitList.m_arShownList[m_CurrentRebaseIndex];
1210 int mode=pRev->GetAction(&m_CommitList) & CTGitPath::LOGACTIONS_REBASE_MODE_MASK;
1211 CString nocommit;
1213 if( mode== CTGitPath::LOGACTIONS_REBASE_SKIP)
1215 pRev->GetAction(&m_CommitList)|= CTGitPath::LOGACTIONS_REBASE_DONE;
1216 return 0;
1219 if( mode != CTGitPath::LOGACTIONS_REBASE_PICK )
1221 this->m_SquashMessage+= pRev->GetSubject();
1222 this->m_SquashMessage+= _T("\n");
1223 this->m_SquashMessage+= pRev->GetBody();
1225 else
1226 this->m_SquashMessage.Empty();
1228 if(mode == CTGitPath::LOGACTIONS_REBASE_SQUASH)
1229 nocommit=_T(" --no-commit ");
1231 CString log;
1232 log.Format(_T("%s %d:%s"),CTGitPath::GetActionName(mode),this->GetCurrentCommitID(),pRev->m_CommitHash.ToString());
1233 AddLogString(log);
1234 AddLogString(pRev->GetSubject());
1235 cmd.Format(_T("git.exe cherry-pick %s %s"),nocommit,pRev->m_CommitHash.ToString());
1237 if(g_Git.Run(cmd,&out,CP_UTF8))
1239 AddLogString(out);
1240 CTGitPathList list;
1241 if(g_Git.ListConflictFile(list))
1243 AddLogString(_T("Get conflict files fail"));
1244 return -1;
1246 if(list.GetCount() == 0 )
1248 if(mode == CTGitPath::LOGACTIONS_REBASE_PICK)
1250 pRev->GetAction(&m_CommitList)|= CTGitPath::LOGACTIONS_REBASE_DONE;
1251 return 0;
1253 if(mode == CTGitPath::LOGACTIONS_REBASE_EDIT)
1255 this->m_RebaseStage = REBASE_EDIT ;
1256 return -1; // Edit return -1 to stop rebase.
1258 // Squash Case
1259 if(CheckNextCommitIsSquash())
1260 { // no squash
1261 // let user edit last commmit message
1262 this->m_RebaseStage = REBASE_SQUASH_EDIT;
1263 return -1;
1266 if(mode == CTGitPath::LOGACTIONS_REBASE_SQUASH)
1267 m_RebaseStage = REBASE_SQUASH_CONFLICT;
1268 else
1269 m_RebaseStage = REBASE_CONFLICT;
1270 return -1;
1272 }else
1274 AddLogString(out);
1275 if(mode == CTGitPath::LOGACTIONS_REBASE_PICK)
1277 pRev->GetAction(&m_CommitList)|= CTGitPath::LOGACTIONS_REBASE_DONE;
1278 return 0;
1280 if(mode == CTGitPath::LOGACTIONS_REBASE_EDIT)
1282 this->m_RebaseStage = REBASE_EDIT ;
1283 return -1; // Edit return -1 to stop rebase.
1286 // Squash Case
1287 if(CheckNextCommitIsSquash())
1288 { // no squash
1289 // let user edit last commmit message
1290 this->m_RebaseStage = REBASE_SQUASH_EDIT;
1291 return -1;
1295 return 0;
1298 BOOL CRebaseDlg::IsEnd()
1300 if(m_CommitList.m_IsOldFirst)
1301 return m_CurrentRebaseIndex>= this->m_CommitList.GetItemCount();
1302 else
1303 return m_CurrentRebaseIndex<0;
1306 int CRebaseDlg::RebaseThread()
1308 int ret=0;
1309 while(1)
1311 if( m_RebaseStage == REBASE_START )
1313 if( this->StartRebase() )
1315 InterlockedExchange(&m_bThreadRunning, FALSE);
1316 ret = -1;
1317 break;
1319 m_RebaseStage = REBASE_CONTINUE;
1321 }else if( m_RebaseStage == REBASE_CONTINUE )
1323 this->GoNext();
1324 if(IsEnd())
1326 ret = 0;
1327 m_RebaseStage = REBASE_FINISH;
1329 }else
1331 ret = DoRebase();
1333 if( ret )
1335 break;
1339 }else if( m_RebaseStage == REBASE_FINISH )
1341 FinishRebase();
1342 m_RebaseStage = REBASE_DONE;
1343 break;
1345 }else
1347 break;
1349 this->PostMessage(MSG_REBASE_UPDATE_UI);
1350 //this->UpdateCurrentStatus();
1353 InterlockedExchange(&m_bThreadRunning, FALSE);
1354 this->PostMessage(MSG_REBASE_UPDATE_UI);
1355 return ret;
1358 void CRebaseDlg::ListConflictFile()
1360 this->m_FileListCtrl.Clear();
1361 CTGitPathList list;
1362 CTGitPath path;
1363 list.AddPath(path);
1365 m_FileListCtrl.m_bIsRevertTheirMy = !m_IsCherryPick;
1367 this->m_FileListCtrl.GetStatus(&list,true);
1368 this->m_FileListCtrl.Show(CTGitPath::LOGACTIONS_UNMERGED|CTGitPath::LOGACTIONS_MODIFIED|CTGitPath::LOGACTIONS_ADDED|CTGitPath::LOGACTIONS_DELETED,
1369 CTGitPath::LOGACTIONS_UNMERGED);
1372 LRESULT CRebaseDlg::OnRebaseUpdateUI(WPARAM,LPARAM)
1374 UpdateCurrentStatus();
1375 if(m_CurrentRebaseIndex <0)
1376 return 0;
1377 if(m_CurrentRebaseIndex >= m_CommitList.GetItemCount() )
1378 return 0;
1379 GitRev *curRev=(GitRev*)m_CommitList.m_arShownList[m_CurrentRebaseIndex];
1381 switch(m_RebaseStage)
1383 case REBASE_CONFLICT:
1384 case REBASE_SQUASH_CONFLICT:
1385 ListConflictFile();
1386 this->m_ctrlTabCtrl.SetActiveTab(REBASE_TAB_CONFLICT);
1387 this->m_LogMessageCtrl.SetText(curRev->GetSubject()+_T("\n")+curRev->GetBody());
1388 break;
1389 case REBASE_EDIT:
1390 this->m_ctrlTabCtrl.SetActiveTab(REBASE_TAB_MESSAGE);
1391 this->m_LogMessageCtrl.SetText(curRev->GetSubject()+_T("\n")+curRev->GetBody());
1392 break;
1393 case REBASE_SQUASH_EDIT:
1394 this->m_ctrlTabCtrl.SetActiveTab(REBASE_TAB_MESSAGE);
1395 this->m_LogMessageCtrl.SetText(this->m_SquashMessage);
1396 break;
1397 default:
1398 this->m_ctrlTabCtrl.SetActiveTab(REBASE_TAB_LOG);
1400 return 0;
1402 void CRebaseDlg::OnCancel()
1404 OnBnClickedAbort();
1406 void CRebaseDlg::OnBnClickedAbort()
1408 CString cmd,out;
1409 if(m_OrigUpstreamHash.IsEmpty())
1411 __super::OnCancel();
1414 if(m_RebaseStage == CHOOSE_BRANCH || m_RebaseStage== CHOOSE_COMMIT_PICK_MODE)
1416 return;
1419 if(CMessageBox::Show(NULL,_T("Are you sure you want to abort the rebase process?"),_T("TortoiseGit"),MB_YESNO) != IDYES)
1420 return;
1422 if(this->m_IsFastForward)
1424 cmd.Format(_T("git.exe reset --hard %s"),this->m_OrigBranchHash.ToString());
1425 if(g_Git.Run(cmd,&out,CP_UTF8))
1427 AddLogString(out);
1428 return ;
1430 __super::OnCancel();
1431 return;
1433 cmd.Format(_T("git.exe checkout -f %s"),this->m_UpstreamCtrl.GetString());
1434 if(g_Git.Run(cmd,&out,CP_UTF8))
1436 AddLogString(out);
1437 return ;
1440 cmd.Format(_T("git.exe reset --hard %s"),this->m_OrigUpstreamHash.ToString());
1441 if(g_Git.Run(cmd,&out,CP_UTF8))
1443 AddLogString(out);
1444 return ;
1447 if(this->m_IsCherryPick) //there are not "branch" at cherry pick mode
1449 __super::OnCancel();
1450 return;
1453 cmd.Format(_T("git checkout -f %s"),this->m_BranchCtrl.GetString());
1454 if(g_Git.Run(cmd,&out,CP_UTF8))
1456 AddLogString(out);
1457 return ;
1460 cmd.Format(_T("git.exe reset --hard %s"),this->m_OrigBranchHash.ToString());
1461 if(g_Git.Run(cmd,&out,CP_UTF8))
1463 AddLogString(out);
1464 return ;
1466 __super::OnCancel();
1469 void CRebaseDlg::OnBnClickedButtonBrowse()
1471 if(CBrowseRefsDlg::PickRefForCombo(&m_UpstreamCtrl, gPickRef_NoTag))
1472 OnCbnSelchangeUpstream();
1475 void CRebaseDlg::OnBnClickedRebaseCheckForce()
1477 this->UpdateData();
1478 this->FetchLogList();
1479 if(this->CheckRebaseCondition())
1481 /* Disable Start Rebase */
1482 this->GetDlgItem(IDC_REBASE_CONTINUE)->EnableWindow(FALSE);
1486 void CRebaseDlg::OnBnClickedRebasePostButton()
1488 this->m_Upstream=this->m_UpstreamCtrl.GetString();
1489 this->m_Branch=this->m_BranchCtrl.GetString();
1491 this->EndDialog(IDC_REBASE_POST_BUTTON+this->m_PostButton.GetCurrentEntry());
1494 void CRebaseDlg::Refresh()
1496 if(this->m_IsCherryPick)
1497 return ;
1499 if(this->m_RebaseStage == CHOOSE_BRANCH )
1501 this->UpdateData();
1502 this->FetchLogList();
1503 if(this->CheckRebaseCondition())
1505 /* Disable Start Rebase */
1506 this->GetDlgItem(IDC_REBASE_CONTINUE)->EnableWindow(FALSE);
1511 void CRebaseDlg::OnBnClickedButtonUp2()
1513 POSITION pos;
1514 pos = m_CommitList.GetFirstSelectedItemPosition();
1515 bool changed = false;
1516 while(pos)
1518 int index=m_CommitList.GetNextSelectedItem(pos);
1519 if(index>=1)
1521 CGitHash old = m_CommitList.m_logEntries[index-1];
1522 m_CommitList.m_logEntries[index-1] = m_CommitList.m_logEntries[index];
1523 m_CommitList.m_logEntries[index] = old;
1524 m_CommitList.SetItemState(index-1, LVIS_SELECTED, LVIS_SELECTED);
1525 m_CommitList.SetItemState(index, 0, LVIS_SELECTED);
1526 changed = true;
1529 if (changed)
1531 m_CommitList.RecalculateShownList(&m_CommitList.m_arShownList);
1532 m_CommitList.Invalidate();
1533 m_CommitList.SetFocus();
1537 void CRebaseDlg::OnBnClickedButtonDown2()
1539 POSITION pos;
1540 pos = m_CommitList.GetFirstSelectedItemPosition();
1541 bool changed = false;
1542 while(pos)
1544 int index=m_CommitList.GetNextSelectedItem(pos);
1545 if(index<m_CommitList.GetItemCount()-1)
1547 CGitHash old = m_CommitList.m_logEntries[index+1];
1548 m_CommitList.m_logEntries[index+1] = m_CommitList.m_logEntries[index];
1549 m_CommitList.m_logEntries[index] = old;
1550 m_CommitList.SetItemState(index, 0, LVIS_SELECTED);
1551 m_CommitList.SetItemState(index+1, LVIS_SELECTED, LVIS_SELECTED);
1552 changed = true;
1555 if (changed)
1557 m_CommitList.RecalculateShownList(&m_CommitList.m_arShownList);
1558 m_CommitList.Invalidate();
1559 m_CommitList.SetFocus();