OSDN Git Service

Fixed issue #157: SVN Rebase doesn't fast-forward
[tortoisegit/TortoiseGitJp.git] / src / TortoiseProc / RebaseDlg.cpp
1 // RebaseDlg.cpp : implementation file\r
2 //\r
3 \r
4 #include "stdafx.h"\r
5 #include "TortoiseProc.h"\r
6 #include "RebaseDlg.h"\r
7 #include "AppUtils.h"\r
8 #include "MessageBox.h"\r
9 #include "UnicodeUtils.h"\r
10 #include "BrowseRefsDlg.h"\r
11 #include "ProgressDlg.h"\r
12 // CRebaseDlg dialog\r
13 \r
14 IMPLEMENT_DYNAMIC(CRebaseDlg, CResizableStandAloneDialog)\r
15 \r
16 CRebaseDlg::CRebaseDlg(CWnd* pParent /*=NULL*/)\r
17         : CResizableStandAloneDialog(CRebaseDlg::IDD, pParent)\r
18     , m_bPickAll(FALSE)\r
19     , m_bSquashAll(FALSE)\r
20     , m_bEditAll(FALSE)\r
21 {\r
22         m_RebaseStage=CHOOSE_BRANCH;\r
23         m_CurrentRebaseIndex=-1;\r
24         m_bThreadRunning =FALSE;\r
25         this->m_IsCherryPick = FALSE;\r
26         m_bForce=FALSE;\r
27         m_IsFastForward=FALSE;\r
28 }\r
29 \r
30 CRebaseDlg::~CRebaseDlg()\r
31 {\r
32 }\r
33 \r
34 void CRebaseDlg::DoDataExchange(CDataExchange* pDX)\r
35 {\r
36     CDialog::DoDataExchange(pDX);\r
37     DDX_Control(pDX, IDC_REBASE_PROGRESS, m_ProgressBar);\r
38     DDX_Control(pDX, IDC_STATUS_STATIC, m_CtrlStatusText);\r
39     DDX_Check(pDX, IDC_PICK_ALL, m_bPickAll);\r
40     DDX_Check(pDX, IDC_SQUASH_ALL, m_bSquashAll);\r
41     DDX_Check(pDX, IDC_EDIT_ALL, m_bEditAll);\r
42         DDX_Control(pDX, IDC_REBASE_SPLIT, m_wndSplitter);\r
43         DDX_Control(pDX,IDC_COMMIT_LIST,m_CommitList);\r
44         DDX_Control(pDX,IDC_REBASE_COMBOXEX_BRANCH, this->m_BranchCtrl);\r
45         DDX_Control(pDX,IDC_REBASE_COMBOXEX_UPSTREAM,   this->m_UpstreamCtrl);\r
46         DDX_Check(pDX, IDC_REBASE_CHECK_FORCE,m_bForce);\r
47 \r
48 }\r
49 \r
50 \r
51 BEGIN_MESSAGE_MAP(CRebaseDlg, CResizableStandAloneDialog)\r
52     ON_BN_CLICKED(IDC_PICK_ALL, &CRebaseDlg::OnBnClickedPickAll)\r
53     ON_BN_CLICKED(IDC_SQUASH_ALL, &CRebaseDlg::OnBnClickedSquashAll)\r
54     ON_BN_CLICKED(IDC_EDIT_ALL, &CRebaseDlg::OnBnClickedEditAll)\r
55     ON_BN_CLICKED(IDC_REBASE_SPLIT, &CRebaseDlg::OnBnClickedRebaseSplit)\r
56         ON_BN_CLICKED(IDC_REBASE_CONTINUE,OnBnClickedContinue)\r
57         ON_BN_CLICKED(IDC_REBASE_ABORT,  OnBnClickedAbort)\r
58         ON_WM_SIZE()\r
59         ON_CBN_SELCHANGE(IDC_REBASE_COMBOXEX_BRANCH,   &CRebaseDlg::OnCbnSelchangeBranch)\r
60         ON_CBN_SELCHANGE(IDC_REBASE_COMBOXEX_UPSTREAM, &CRebaseDlg::OnCbnSelchangeUpstream)\r
61         ON_MESSAGE(MSG_REBASE_UPDATE_UI, OnRebaseUpdateUI)\r
62         ON_BN_CLICKED(IDC_BUTTON_BROWSE, &CRebaseDlg::OnBnClickedButtonBrowse)\r
63         ON_BN_CLICKED(IDC_REBASE_CHECK_FORCE, &CRebaseDlg::OnBnClickedRebaseCheckForce)\r
64         ON_STN_CLICKED(IDC_STATUS_STATIC, &CRebaseDlg::OnStnClickedStatusStatic)\r
65         ON_BN_CLICKED(IDC_REBASE_POST_BUTTON, &CRebaseDlg::OnBnClickedRebasePostButton)\r
66 END_MESSAGE_MAP()\r
67 \r
68 void CRebaseDlg::AddRebaseAnchor()\r
69 {\r
70         AddAnchor(IDC_REBASE_TAB,TOP_LEFT,BOTTOM_RIGHT);\r
71         AddAnchor(IDC_COMMIT_LIST,TOP_LEFT, TOP_RIGHT);\r
72         AddAnchor(IDC_REBASE_SPLIT,TOP_LEFT, TOP_RIGHT);\r
73         AddAnchor(IDC_STATUS_STATIC, BOTTOM_LEFT,BOTTOM_RIGHT);\r
74         AddAnchor(IDC_REBASE_CONTINUE,BOTTOM_RIGHT);\r
75         AddAnchor(IDC_REBASE_ABORT, BOTTOM_RIGHT);\r
76         AddAnchor(IDC_REBASE_PROGRESS,BOTTOM_LEFT, BOTTOM_RIGHT);\r
77         AddAnchor(IDC_PICK_ALL,TOP_LEFT);\r
78         AddAnchor(IDC_SQUASH_ALL,TOP_LEFT);\r
79         AddAnchor(IDC_EDIT_ALL,TOP_LEFT);       \r
80         AddAnchor(IDC_REBASE_COMBOXEX_UPSTREAM,TOP_LEFT);\r
81         AddAnchor(IDC_REBASE_COMBOXEX_BRANCH,TOP_LEFT);\r
82         AddAnchor(IDC_REBASE_STATIC_UPSTREAM,TOP_LEFT);\r
83         AddAnchor(IDC_REBASE_STATIC_BRANCH,TOP_LEFT);\r
84         AddAnchor(IDHELP, BOTTOM_RIGHT);\r
85         AddAnchor(IDC_REBASE_CHECK_FORCE,TOP_RIGHT);\r
86         AddAnchor(IDC_REBASE_POST_BUTTON,BOTTOM_LEFT);\r
87         \r
88         this->AddOthersToAnchor();\r
89 }\r
90 \r
91 BOOL CRebaseDlg::OnInitDialog()\r
92 {\r
93         CResizableStandAloneDialog::OnInitDialog();\r
94 \r
95         CRect rectDummy;\r
96         //IDC_REBASE_DUMY_TAB\r
97         \r
98         GetClientRect(m_DlgOrigRect);\r
99         m_CommitList.GetClientRect(m_CommitListOrigRect);\r
100 \r
101         CWnd *pwnd=this->GetDlgItem(IDC_REBASE_DUMY_TAB);\r
102         pwnd->GetWindowRect(&rectDummy);\r
103         this->ScreenToClient(rectDummy);\r
104 \r
105         if (!m_ctrlTabCtrl.Create(CMFCTabCtrl::STYLE_FLAT, rectDummy, this, IDC_REBASE_TAB))\r
106         {\r
107                 TRACE0("Failed to create output tab window\n");\r
108                 return FALSE;      // fail to create\r
109         }\r
110         m_ctrlTabCtrl.SetResizeMode(CMFCTabCtrl::RESIZE_NO);\r
111         // Create output panes:\r
112         //const DWORD dwStyle = LBS_NOINTEGRALHEIGHT | WS_CHILD | WS_VISIBLE | WS_HSCROLL | WS_VSCROLL;\r
113         DWORD dwStyle =LVS_REPORT | LVS_SHOWSELALWAYS | LVS_ALIGNLEFT | WS_BORDER | WS_TABSTOP |LVS_SINGLESEL |WS_CHILD | WS_VISIBLE;\r
114 \r
115         if (! this->m_FileListCtrl.Create(dwStyle,rectDummy,&this->m_ctrlTabCtrl,0) )\r
116         {\r
117                 TRACE0("Failed to create output windows\n");\r
118                 return FALSE;      // fail to create\r
119         }\r
120 \r
121         if( ! this->m_LogMessageCtrl.Create(_T("Scintilla"),_T("source"),0,rectDummy,&m_ctrlTabCtrl,0,0) )\r
122         {\r
123                 TRACE0("Failed to create log message control");\r
124                 return FALSE;\r
125         }\r
126         m_LogMessageCtrl.Init(0);\r
127 \r
128         dwStyle = LBS_NOINTEGRALHEIGHT | WS_CHILD | WS_VISIBLE | WS_HSCROLL | WS_VSCROLL;\r
129 \r
130         if (!m_wndOutputRebase.Create(_T("Scintilla"),_T("source"),0,rectDummy, &m_ctrlTabCtrl, 0,0) )\r
131         {\r
132                 TRACE0("Failed to create output windows\n");\r
133                 return -1;      // fail to create\r
134         }\r
135         m_wndOutputRebase.Init(0);\r
136         m_wndOutputRebase.Call(SCI_SETREADONLY, TRUE);\r
137         \r
138         m_tooltips.Create(this);\r
139         \r
140         m_tooltips.AddTool(IDC_REBASE_CHECK_FORCE,IDS_REBASE_FORCE_TT);\r
141         m_tooltips.AddTool(IDC_REBASE_ABORT,IDS_REBASE_ABORT_TT);\r
142         \r
143 \r
144 \r
145         m_FileListCtrl.Init(SVNSLC_COLEXT | SVNSLC_COLSTATUS |SVNSLC_COLADD|SVNSLC_COLDEL , _T("RebaseDlg"),(SVNSLC_POPALL ^ SVNSLC_POPCOMMIT),false);\r
146 \r
147         m_ctrlTabCtrl.AddTab(&m_FileListCtrl,_T("Conflict File"));\r
148         m_ctrlTabCtrl.AddTab(&m_LogMessageCtrl,_T("Commit Message"),1);\r
149         m_ctrlTabCtrl.AddTab(&m_wndOutputRebase,_T("Log"),2);\r
150         AddRebaseAnchor();\r
151 \r
152 \r
153         EnableSaveRestore(_T("RebaseDlg"));\r
154 \r
155         DWORD yPos = CRegDWORD(_T("Software\\TortoiseGit\\TortoiseProc\\ResizableState\\RebaseDlgSizer"));\r
156         RECT rcDlg, rcLogMsg, rcFileList;\r
157         GetClientRect(&rcDlg);\r
158         m_CommitList.GetWindowRect(&rcLogMsg);\r
159         ScreenToClient(&rcLogMsg);\r
160         this->m_ctrlTabCtrl.GetWindowRect(&rcFileList);\r
161         ScreenToClient(&rcFileList);\r
162         if (yPos)\r
163         {\r
164                 RECT rectSplitter;\r
165                 m_wndSplitter.GetWindowRect(&rectSplitter);\r
166                 ScreenToClient(&rectSplitter);\r
167                 int delta = yPos - rectSplitter.top;\r
168                 if ((rcLogMsg.bottom + delta > rcLogMsg.top)&&(rcLogMsg.bottom + delta < rcFileList.bottom - 30))\r
169                 {\r
170                         m_wndSplitter.SetWindowPos(NULL, 0, yPos, 0, 0, SWP_NOSIZE);\r
171                         DoSize(delta);\r
172                 }\r
173         }\r
174 \r
175         if( this->m_RebaseStage == CHOOSE_BRANCH)\r
176         {\r
177                 this->LoadBranchInfo();\r
178 \r
179         }else\r
180         {\r
181                 this->m_BranchCtrl.EnableWindow(FALSE);\r
182                 this->m_UpstreamCtrl.EnableWindow(FALSE);\r
183         }\r
184 \r
185         m_CommitList.m_IsIDReplaceAction = TRUE;\r
186 //      m_CommitList.m_IsOldFirst = TRUE;\r
187         m_CommitList.m_IsRebaseReplaceGraph = TRUE;\r
188 \r
189         m_CommitList.InsertGitColumn();\r
190 \r
191         this->SetControlEnable();\r
192 \r
193         if(!this->m_PreCmd.IsEmpty())\r
194         {\r
195                 CProgressDlg progress;\r
196                 progress.m_GitCmd=m_PreCmd;\r
197                 progress.m_bAutoCloseOnSuccess=true;\r
198                 progress.DoModal();\r
199         }\r
200 \r
201         if(m_IsCherryPick)\r
202         {\r
203                 this->m_BranchCtrl.SetCurSel(-1);\r
204                 this->m_BranchCtrl.EnableWindow(FALSE);\r
205                 this->m_UpstreamCtrl.EnableWindow(FALSE);\r
206                 this->SetWindowText(_T("Cherry Pick"));\r
207                 this->m_CommitList.StartFilter();\r
208 \r
209         }else\r
210         {\r
211                 SetContinueButtonText();\r
212                 m_CommitList.DeleteAllItems();\r
213                 FetchLogList();\r
214         }\r
215 \r
216         m_CommitList.m_ContextMenuMask &= ~(m_CommitList.GetContextMenuBit(CGitLogListBase::ID_CHERRY_PICK)|\r
217                                                                                 m_CommitList.GetContextMenuBit(CGitLogListBase::ID_SWITCHTOREV)|\r
218                                                                                 m_CommitList.GetContextMenuBit(CGitLogListBase::ID_RESET)|\r
219                                                                                 m_CommitList.GetContextMenuBit(CGitLogListBase::ID_REVERTREV)|\r
220                                                                                 m_CommitList.GetContextMenuBit(CGitLogListBase::ID_REBASE_TO_VERSION)|\r
221                                                                                 m_CommitList.GetContextMenuBit(CGitLogListBase::ID_REVERTTOREV)|\r
222                                                                                 m_CommitList.GetContextMenuBit(CGitLogListBase::ID_COMBINE_COMMIT));\r
223 \r
224         if(m_CommitList.m_IsOldFirst)\r
225                 this->m_CurrentRebaseIndex = -1;\r
226         else\r
227                 this->m_CurrentRebaseIndex = m_CommitList.m_logEntries.size();\r
228 \r
229 \r
230         return TRUE;\r
231 }\r
232 // CRebaseDlg message handlers\r
233 \r
234 void CRebaseDlg::OnBnClickedPickAll()\r
235 {\r
236     // TODO: Add your control notification handler code here\r
237         this->UpdateData();\r
238         if(this->m_bPickAll)\r
239                 this->SetAllRebaseAction(CTGitPath::LOGACTIONS_REBASE_PICK);\r
240 \r
241         this->m_bEditAll=FALSE;\r
242         this->m_bSquashAll=FALSE;\r
243         this->UpdateData(FALSE);\r
244         \r
245 }\r
246 \r
247 void CRebaseDlg::OnBnClickedSquashAll()\r
248 {\r
249     // TODO: Add your control notification handler code here\r
250         this->UpdateData();\r
251         if(this->m_bSquashAll)\r
252                 this->SetAllRebaseAction(CTGitPath::LOGACTIONS_REBASE_SQUASH);\r
253 \r
254         this->m_bEditAll=FALSE;\r
255         this->m_bPickAll=FALSE;\r
256         this->UpdateData(FALSE);\r
257 \r
258 }\r
259 \r
260 void CRebaseDlg::OnBnClickedEditAll()\r
261 {\r
262     // TODO: Add your control notification handler code here\r
263         this->UpdateData();\r
264         if( this->m_bEditAll )\r
265                 this->SetAllRebaseAction(CTGitPath::LOGACTIONS_REBASE_EDIT);\r
266 \r
267         this->m_bPickAll=FALSE;\r
268         this->m_bSquashAll=FALSE;\r
269         this->UpdateData(FALSE);\r
270 \r
271 }\r
272 \r
273 void CRebaseDlg::SetAllRebaseAction(int action)\r
274 {\r
275         for(int i=0;i<this->m_CommitList.m_logEntries.size();i++)\r
276         {\r
277                 m_CommitList.m_logEntries[i].m_Action=action;\r
278         }\r
279         m_CommitList.Invalidate();\r
280 }\r
281 \r
282 void CRebaseDlg::OnBnClickedRebaseSplit()\r
283 {\r
284         this->UpdateData();\r
285     // TODO: Add your control notification handler code here\r
286 }\r
287 \r
288 LRESULT CRebaseDlg::DefWindowProc(UINT message, WPARAM wParam, LPARAM lParam)\r
289 {\r
290         switch (message) {\r
291         case WM_NOTIFY:\r
292                 if (wParam == IDC_REBASE_SPLIT)\r
293                 { \r
294                         SPC_NMHDR* pHdr = (SPC_NMHDR*) lParam;\r
295                         DoSize(pHdr->delta);\r
296                 }\r
297                 break;\r
298         }\r
299 \r
300         return __super::DefWindowProc(message, wParam, lParam);\r
301 }\r
302 \r
303 void CRebaseDlg::DoSize(int delta)\r
304 {\r
305         \r
306         this->RemoveAllAnchors();\r
307 \r
308         CSplitterControl::ChangeHeight(GetDlgItem(IDC_COMMIT_LIST), delta, CW_TOPALIGN);\r
309         //CSplitterControl::ChangeHeight(GetDlgItem(), delta, CW_TOPALIGN);\r
310         CSplitterControl::ChangeHeight(GetDlgItem(IDC_REBASE_TAB), -delta, CW_BOTTOMALIGN);\r
311         //CSplitterControl::ChangeHeight(GetDlgItem(), -delta, CW_BOTTOMALIGN);\r
312         CSplitterControl::ChangePos(GetDlgItem(IDC_SQUASH_ALL),0,delta);\r
313         CSplitterControl::ChangePos(GetDlgItem(IDC_PICK_ALL),0,delta);\r
314         CSplitterControl::ChangePos(GetDlgItem(IDC_EDIT_ALL),0,delta);\r
315         \r
316         this->AddRebaseAnchor();\r
317         // adjust the minimum size of the dialog to prevent the resizing from\r
318         // moving the list control too far down.\r
319         CRect rcLogMsg;\r
320         m_CommitList.GetClientRect(rcLogMsg);\r
321         SetMinTrackSize(CSize(m_DlgOrigRect.Width(), m_DlgOrigRect.Height()-m_CommitListOrigRect.Height()+rcLogMsg.Height()));\r
322 \r
323         SetSplitterRange();\r
324 //      m_CommitList.Invalidate();\r
325 \r
326 //      GetDlgItem(IDC_LOGMESSAGE)->Invalidate();\r
327 \r
328         this->m_ctrlTabCtrl.Invalidate();\r
329         this->m_CommitList.Invalidate();\r
330         this->m_FileListCtrl.Invalidate();\r
331         this->m_LogMessageCtrl.Invalidate();\r
332 \r
333 }\r
334 \r
335 void CRebaseDlg::SetSplitterRange()\r
336 {\r
337         if ((m_CommitList)&&(m_ctrlTabCtrl))\r
338         {\r
339                 CRect rcTop;\r
340                 m_CommitList.GetWindowRect(rcTop);\r
341                 ScreenToClient(rcTop);\r
342                 CRect rcMiddle;\r
343                 m_ctrlTabCtrl.GetWindowRect(rcMiddle);\r
344                 ScreenToClient(rcMiddle);\r
345                 if (rcMiddle.Height() && rcMiddle.Width())\r
346                         m_wndSplitter.SetRange(rcTop.top+60, rcMiddle.bottom-80);\r
347         }\r
348 }\r
349 \r
350 void CRebaseDlg::OnSize(UINT nType,int cx, int cy)\r
351 {\r
352          // first, let the resizing take place\r
353     __super::OnSize(nType, cx, cy);\r
354 \r
355     //set range\r
356     SetSplitterRange();\r
357 }\r
358 \r
359 void CRebaseDlg::SaveSplitterPos()\r
360 {\r
361         if (!IsIconic())\r
362         {\r
363                 CRegDWORD regPos = CRegDWORD(_T("Software\\TortoiseGit\\TortoiseProc\\ResizableState\\RebaseDlgSizer"));\r
364                 RECT rectSplitter;\r
365                 m_wndSplitter.GetWindowRect(&rectSplitter);\r
366                 ScreenToClient(&rectSplitter);\r
367                 regPos = rectSplitter.top;\r
368         }\r
369 }\r
370 \r
371 void CRebaseDlg::LoadBranchInfo()\r
372 {\r
373         m_BranchCtrl.SetMaxHistoryItems(0x7FFFFFFF);\r
374         m_UpstreamCtrl.SetMaxHistoryItems(0x7FFFFFFF);\r
375 \r
376         STRING_VECTOR list;\r
377         list.clear();\r
378         int current;\r
379         g_Git.GetBranchList(list,&current,CGit::BRANCH_ALL);\r
380         m_BranchCtrl.AddString(list);\r
381         m_UpstreamCtrl.AddString(list);\r
382 \r
383         m_BranchCtrl.SetCurSel(current);\r
384 \r
385         AddBranchToolTips(&m_BranchCtrl);\r
386         AddBranchToolTips(&m_UpstreamCtrl);\r
387 \r
388         if(!m_Upstream.IsEmpty())\r
389         {\r
390                 m_UpstreamCtrl.AddString(m_Upstream);\r
391                 m_UpstreamCtrl.SetCurSel(m_UpstreamCtrl.GetCount()-1);\r
392         }\r
393         else\r
394         {\r
395                 //Select pull-remote from current branch\r
396                 CString currentBranch = g_Git.GetSymbolicRef();\r
397                 CString configName;\r
398                 configName.Format(L"branch.%s.remote", currentBranch);\r
399                 CString pullRemote = g_Git.GetConfigValue(configName);\r
400 \r
401                 //Select pull-branch from current branch\r
402                 configName.Format(L"branch.%s.merge", currentBranch);\r
403                 CString pullBranch = CGit::StripRefName(g_Git.GetConfigValue(configName));\r
404 \r
405                 CString defaultUpstream;\r
406                 defaultUpstream.Format(L"remotes/%s/%s", pullRemote, pullBranch);\r
407                 int found = m_UpstreamCtrl.FindStringExact(0, defaultUpstream);\r
408                 if(found >= 0)\r
409                         m_UpstreamCtrl.SetCurSel(found);\r
410         }\r
411 }\r
412 \r
413 void CRebaseDlg::OnCbnSelchangeBranch()\r
414 {\r
415         FetchLogList();\r
416 }\r
417 \r
418 void CRebaseDlg::OnCbnSelchangeUpstream()\r
419 {\r
420         FetchLogList();\r
421 }\r
422 \r
423 void CRebaseDlg::FetchLogList()\r
424 {\r
425         CString base,hash;\r
426         CString cmd;\r
427         m_IsFastForward=FALSE;\r
428         cmd.Format(_T("git.exe merge-base %s %s"), m_UpstreamCtrl.GetString(),m_BranchCtrl.GetString());\r
429         if(g_Git.Run(cmd,&base,CP_ACP))\r
430         {\r
431                 CMessageBox::Show(NULL,base,_T("TortoiseGit"),MB_OK|MB_ICONERROR);\r
432                 return;\r
433         }\r
434         base=base.Left(40);\r
435 \r
436         hash=g_Git.GetHash(m_BranchCtrl.GetString());\r
437 \r
438         hash=hash.Left(40);\r
439         \r
440         if(hash == base )\r
441         {\r
442                 //fast forword\r
443                 this->m_IsFastForward=TRUE;\r
444 \r
445                 m_CommitList.Clear();\r
446                 CString text,fmt;\r
447                 fmt.LoadString(IDS_REBASE_FASTFORWARD_FMT);\r
448                 text.Format(fmt,m_BranchCtrl.GetString(),this->m_UpstreamCtrl.GetString(),\r
449                                                 m_BranchCtrl.GetString(),this->m_UpstreamCtrl.GetString());\r
450 \r
451                 m_CommitList.ShowText(text);\r
452                 this->GetDlgItem(IDC_REBASE_CONTINUE)->EnableWindow(true);\r
453                 SetContinueButtonText();\r
454                 \r
455                 return ;\r
456         }\r
457 \r
458         hash.Empty();\r
459 \r
460         if(!this->m_bForce)\r
461         {\r
462                 cmd.Format(_T("git.exe rev-parse %s"), m_UpstreamCtrl.GetString());\r
463                 if( g_Git.Run(cmd,&hash,CP_ACP))\r
464                 {\r
465                         CMessageBox::Show(NULL,base,_T("TortoiseGit"),MB_OK|MB_ICONERROR);\r
466                         return;\r
467                 }\r
468                 hash=hash.Left(40);\r
469                 \r
470                 if( base == hash )\r
471                 {\r
472                         m_CommitList.Clear();\r
473                         CString text,fmt;\r
474                         fmt.LoadString(IDS_REBASE_UPTODATE_FMT);\r
475                         text.Format(fmt,m_BranchCtrl.GetString());\r
476                         m_CommitList.ShowText(text);\r
477                         this->GetDlgItem(IDC_REBASE_CONTINUE)->EnableWindow(m_CommitList.GetItemCount());\r
478                         SetContinueButtonText();\r
479                         return;\r
480                 }\r
481         }\r
482 \r
483         m_CommitList.Clear();\r
484         this->m_CommitList.FillGitLog(NULL,0,&m_UpstreamCtrl.GetString(),&m_BranchCtrl.GetString());\r
485         if( m_CommitList.GetItemCount() == 0 )\r
486                 m_CommitList.ShowText(_T("Nothing to Rebase"));\r
487 \r
488         hash=g_Git.GetHash(m_UpstreamCtrl.GetString());\r
489         \r
490 #if 0\r
491         if(m_CommitList.m_logEntries[m_CommitList.m_logEntries.size()-1].m_ParentHash.size() >=0 )\r
492         {\r
493                 if(hash ==  m_CommitList.m_logEntries[m_CommitList.m_logEntries.size()-1].m_ParentHash[0])\r
494                 {\r
495                         m_CommitList.Clear();\r
496                         m_CommitList.ShowText(_T("Nothing Rebase"));\r
497                 }\r
498         }\r
499 #endif\r
500 \r
501         m_tooltips.Pop();\r
502         AddBranchToolTips(&this->m_BranchCtrl);\r
503         AddBranchToolTips(&this->m_UpstreamCtrl);\r
504         \r
505         for(int i=0;i<m_CommitList.m_logEntries.size();i++)\r
506         {\r
507                 m_CommitList.m_logEntries[i].m_Action = CTGitPath::LOGACTIONS_REBASE_PICK;\r
508         }\r
509 \r
510         m_CommitList.Invalidate();\r
511 \r
512         if(m_CommitList.m_IsOldFirst)\r
513                 this->m_CurrentRebaseIndex = -1;\r
514         else\r
515                 this->m_CurrentRebaseIndex = m_CommitList.m_logEntries.size();\r
516         \r
517         this->GetDlgItem(IDC_REBASE_CONTINUE)->EnableWindow(m_CommitList.GetItemCount());\r
518         SetContinueButtonText();\r
519 }\r
520 \r
521 void CRebaseDlg::AddBranchToolTips(CHistoryCombo *pBranch)\r
522 {\r
523         if(pBranch)\r
524         {\r
525                 CString text=pBranch->GetString();\r
526                 CString tooltip;\r
527                 BYTE_VECTOR data;\r
528                 g_Git.GetLog(data,text,NULL,1,0);\r
529                 GitRev rev;\r
530                 rev.ParserFromLog(data);\r
531                 tooltip.Format(_T("CommitHash:%s\nCommit by: %s  %s\n <b>%s</b> \n %s"),\r
532                         rev.m_CommitHash,\r
533                         rev.m_AuthorName,\r
534                         CAppUtils::FormatDateAndTime(rev.m_AuthorDate,DATE_LONGDATE),\r
535                         rev.m_Subject,\r
536                         rev.m_Body);\r
537 \r
538                 pBranch->DisableTooltip();\r
539                 this->m_tooltips.AddTool(pBranch->GetComboBoxCtrl(),tooltip);\r
540         }\r
541 }\r
542 \r
543 BOOL CRebaseDlg::PreTranslateMessage(MSG*pMsg)\r
544 {\r
545         m_tooltips.RelayEvent(pMsg);\r
546         return CResizableStandAloneDialog::PreTranslateMessage(pMsg);\r
547 }\r
548 int CRebaseDlg::CheckRebaseCondition()\r
549 {\r
550         this->m_ctrlTabCtrl.SetActiveTab(REBASE_TAB_LOG);\r
551 \r
552         if( !g_Git.CheckCleanWorkTree()  )\r
553         {\r
554                 CMessageBox::Show(NULL,_T("Rebase Need Clean Working Tree"),_T("TortoiseGit"),MB_OK);\r
555                 return -1;\r
556         }\r
557         //Todo Check $REBASE_ROOT\r
558         //Todo Check $DOTEST\r
559 \r
560         CString cmd;\r
561         cmd=_T("git.exe var GIT_COMMITTER_IDENT");\r
562         if(g_Git.Run(cmd,NULL,CP_UTF8))\r
563                 return -1;\r
564 \r
565         //Todo call pre_rebase_hook\r
566         return 0;\r
567 }\r
568 int CRebaseDlg::StartRebase()\r
569 {\r
570         CString cmd,out;\r
571 \r
572         if(!this->m_IsCherryPick)\r
573         {\r
574                 //Todo call comment_for_reflog\r
575                 cmd.Format(_T("git.exe checkout %s"),this->m_BranchCtrl.GetString());\r
576                 this->AddLogString(cmd);\r
577 \r
578                 if(g_Git.Run(cmd,&out,CP_UTF8))\r
579                         return -1;\r
580 \r
581                 this->AddLogString(out);\r
582         }\r
583 \r
584         cmd=_T("git.exe rev-parse --verify HEAD");\r
585         if(g_Git.Run(cmd,&out,CP_UTF8))\r
586         {\r
587                 AddLogString(_T("No Head"));\r
588                 return -1;\r
589         }\r
590         //Todo \r
591         //git symbolic-ref HEAD > "$DOTEST"/head-name 2> /dev/null ||\r
592         //              echo "detached HEAD" > "$DOTEST"/head-name\r
593 \r
594         cmd.Format(_T("git.exe update-ref ORIG_HEAD HEAD"));\r
595         if(g_Git.Run(cmd,&out,CP_UTF8))\r
596         {\r
597                 AddLogString(_T("update ORIG_HEAD Fail"));\r
598                 return -1;\r
599         }\r
600         \r
601         if( !this->m_IsCherryPick )\r
602         {\r
603                 cmd.Format(_T("git.exe checkout %s"),this->m_UpstreamCtrl.GetString());\r
604                 this->AddLogString(cmd);\r
605 \r
606                 out.Empty();\r
607                 if(g_Git.Run(cmd,&out,CP_UTF8))\r
608                 {\r
609                         return -1;\r
610                 }\r
611         }\r
612         \r
613         m_OrigUpstreamHash.Empty();\r
614         m_OrigUpstreamHash= g_Git.GetHash(this->m_UpstreamCtrl.GetString());\r
615         if(m_OrigUpstreamHash.IsEmpty())\r
616         {\r
617                 this->AddLogString(m_OrigUpstreamHash);\r
618                 return -1;\r
619         }\r
620 \r
621         if( !this->m_IsCherryPick )\r
622         {\r
623                 cmd.Format(_T("git.exe rev-parse %s"),this->m_BranchCtrl.GetString());\r
624                 if(g_Git.Run(cmd,&this->m_OrigBranchHash,CP_UTF8))\r
625                 {\r
626                         this->AddLogString(m_OrigBranchHash);\r
627                         return -1;\r
628                 }\r
629                 this->AddLogString(_T("Start Rebase\r\n"));\r
630 \r
631         }else\r
632                 this->AddLogString(_T("Start Cherry-pick\r\n"));\r
633         \r
634         return 0;\r
635 }\r
636 int  CRebaseDlg::VerifyNoConflict()\r
637 {\r
638         CTGitPathList list;\r
639         if(g_Git.ListConflictFile(list))\r
640         {\r
641                 AddLogString(_T("Get conflict files fail"));\r
642                 return -1;\r
643         }\r
644         if( list.GetCount() != 0 )\r
645         {\r
646                 CMessageBox::Show(NULL,_T("There are conflict file, you should mark it resolve"),_T("TortoiseGit"),MB_OK);\r
647                 return -1;\r
648         }\r
649         return 0;\r
650 \r
651 }\r
652 int CRebaseDlg::FinishRebase()\r
653 {\r
654         if(this->m_IsCherryPick) //cherry pick mode no "branch", working at upstream branch\r
655                 return 0;\r
656 \r
657         CString cmd,out;\r
658         cmd.Format(_T("git.exe branch -f %s"),this->m_BranchCtrl.GetString());\r
659         if(g_Git.Run(cmd,&out,CP_UTF8))\r
660         {\r
661                 AddLogString(out);\r
662                 return -1;\r
663         }\r
664         out.Empty();\r
665         cmd.Format(_T("git.exe reset --hard %s"),this->m_OrigUpstreamHash);\r
666         if(g_Git.Run(cmd,&out,CP_UTF8))\r
667         {\r
668                 AddLogString(out);\r
669                 return -1;\r
670         }\r
671         out.Empty();\r
672         cmd.Format(_T("git.exe checkout -f %s"),this->m_BranchCtrl.GetString());\r
673         if(g_Git.Run(cmd,&out,CP_UTF8))\r
674         {\r
675                 AddLogString(out);\r
676                 return -1;\r
677         }\r
678         return 0;\r
679 }\r
680 void CRebaseDlg::OnBnClickedContinue()\r
681 {\r
682         if( m_RebaseStage == REBASE_DONE)\r
683         {\r
684                 OnOK();\r
685         }\r
686 \r
687         if( this->m_IsFastForward )\r
688         {\r
689                 m_OrigBranchHash = g_Git.GetHash(m_BranchCtrl.GetString());\r
690                 m_OrigUpstreamHash = g_Git.GetHash(this->m_UpstreamCtrl.GetString());\r
691                         \r
692                 if(!g_Git.IsFastForward(this->m_BranchCtrl.GetString(),this->m_UpstreamCtrl.GetString()))\r
693                 {\r
694                         this->m_ctrlTabCtrl.SetActiveTab(REBASE_TAB_LOG);\r
695                         AddLogString(_T("No fast forward\r\nMaybe repository changed"));\r
696                         return;\r
697                 }\r
698                 CString cmd,out;\r
699                 cmd.Format(_T("git.exe reset --hard %s"),this->m_UpstreamCtrl.GetString());\r
700                 this->AddLogString(CString(_T("Fast forward to "))+m_UpstreamCtrl.GetString());\r
701 \r
702                 AddLogString(cmd);\r
703                 this->m_ctrlTabCtrl.SetActiveTab(REBASE_TAB_LOG);\r
704                 if(g_Git.Run(cmd,&out,CP_ACP))\r
705                 {\r
706                         AddLogString(_T("Fail"));\r
707                         AddLogString(out);\r
708                         return;\r
709                 }\r
710                 AddLogString(out);\r
711                 AddLogString(_T("Done"));\r
712                 m_RebaseStage = REBASE_DONE;\r
713                 UpdateCurrentStatus();\r
714                 return;\r
715 \r
716         }\r
717         if( m_RebaseStage == CHOOSE_BRANCH|| m_RebaseStage == CHOOSE_COMMIT_PICK_MODE )\r
718         {\r
719                 if(CheckRebaseCondition())\r
720                         return ;\r
721                 m_RebaseStage = REBASE_START;\r
722         }\r
723 \r
724 \r
725         if( m_RebaseStage == REBASE_FINISH )\r
726         {\r
727                 if(FinishRebase())\r
728                         return ;\r
729 \r
730                 OnOK();\r
731         }\r
732 \r
733         if( m_RebaseStage == REBASE_SQUASH_CONFLICT)\r
734         {\r
735                 if(VerifyNoConflict())\r
736                         return;\r
737                 GitRev *curRev=(GitRev*)m_CommitList.m_arShownList[m_CurrentRebaseIndex];\r
738                 if(this->CheckNextCommitIsSquash())\r
739                 {//next commit is not squash;\r
740                         m_RebaseStage = REBASE_SQUASH_EDIT;\r
741                         this->OnRebaseUpdateUI(0,0);\r
742                         this->UpdateCurrentStatus();\r
743                         return ;\r
744 \r
745                 }\r
746                 m_RebaseStage=REBASE_CONTINUE;\r
747                 curRev->m_Action|=CTGitPath::LOGACTIONS_REBASE_DONE;\r
748                 this->UpdateCurrentStatus();\r
749 \r
750         }\r
751 \r
752         if( m_RebaseStage == REBASE_CONFLICT )\r
753         {\r
754                 if(VerifyNoConflict())\r
755                         return;\r
756 \r
757                 GitRev *curRev=(GitRev*)m_CommitList.m_arShownList[m_CurrentRebaseIndex];\r
758                 \r
759                 CString out =_T("");\r
760                 CString cmd;\r
761                 cmd.Format(_T("git.exe commit -C %s"), curRev->m_CommitHash);\r
762 \r
763                 if(g_Git.Run(cmd,&out,CP_UTF8))\r
764                 {\r
765                         if(!g_Git.CheckCleanWorkTree())\r
766                         {\r
767                                 CMessageBox::Show(NULL,out,_T("TortoiseGit"),MB_OK|MB_ICONERROR);\r
768                                 return;\r
769                         }\r
770                 }\r
771 \r
772                 AddLogString(out);\r
773                 this->m_ctrlTabCtrl.SetActiveTab(REBASE_TAB_LOG);\r
774                 if( curRev->m_Action & CTGitPath::LOGACTIONS_REBASE_EDIT)\r
775                 {\r
776                         m_RebaseStage=REBASE_EDIT;\r
777                         this->m_ctrlTabCtrl.SetActiveTab(REBASE_TAB_MESSAGE);\r
778                         this->UpdateCurrentStatus();\r
779                         return;\r
780                 }\r
781                 else\r
782                 {\r
783                         m_RebaseStage=REBASE_CONTINUE;\r
784                         curRev->m_Action|=CTGitPath::LOGACTIONS_REBASE_DONE;\r
785                         this->UpdateCurrentStatus();\r
786                 }\r
787                 \r
788         }\r
789 \r
790         if( m_RebaseStage == REBASE_EDIT ||  m_RebaseStage == REBASE_SQUASH_EDIT )\r
791         {\r
792                 CString str;\r
793                 GitRev *curRev=(GitRev*)m_CommitList.m_arShownList[m_CurrentRebaseIndex];\r
794         \r
795                 str=this->m_LogMessageCtrl.GetText();\r
796                 if(str.Trim().IsEmpty())\r
797                 {\r
798                         CMessageBox::Show(NULL,_T("Commit Message Is Empty"),_T("TortoiseGit"),MB_OK|MB_ICONERROR);\r
799                                 return;\r
800                 }\r
801 \r
802                 CString tempfile=::GetTempFile();\r
803                 CFile file(tempfile,CFile::modeReadWrite|CFile::modeCreate );\r
804                 CStringA log=CUnicodeUtils::GetUTF8( str);\r
805                 file.Write(log,log.GetLength());\r
806                 //file.WriteString(m_sLogMessage);\r
807                 file.Close();\r
808         \r
809                 CString out,cmd;\r
810                 \r
811                 if(  m_RebaseStage == REBASE_SQUASH_EDIT )\r
812                         cmd.Format(_T("git.exe commit -F \"%s\""), tempfile);\r
813                 else\r
814                         cmd.Format(_T("git.exe commit --amend -F \"%s\""), tempfile);\r
815 \r
816                 if(g_Git.Run(cmd,&out,CP_UTF8))\r
817                 {\r
818                         if(!g_Git.CheckCleanWorkTree())\r
819                         {\r
820                                 CMessageBox::Show(NULL,out,_T("TortoiseGit"),MB_OK|MB_ICONERROR);\r
821                                 return;\r
822                         }\r
823                 }\r
824 \r
825                 CFile::Remove(tempfile);\r
826                 AddLogString(out);\r
827                 this->m_ctrlTabCtrl.SetActiveTab(REBASE_TAB_LOG);\r
828                 m_RebaseStage=REBASE_CONTINUE;\r
829                 curRev->m_Action|=CTGitPath::LOGACTIONS_REBASE_DONE;\r
830                 this->UpdateCurrentStatus();\r
831         }\r
832 \r
833 \r
834         InterlockedExchange(&m_bThreadRunning, TRUE);\r
835         SetControlEnable();\r
836         \r
837         if (AfxBeginThread(RebaseThreadEntry, this)==NULL)\r
838         {\r
839                 InterlockedExchange(&m_bThreadRunning, FALSE);\r
840                 CMessageBox::Show(NULL, _T("Create Rebase Thread Fail"), _T("TortoiseGit"), MB_OK | MB_ICONERROR);\r
841                 SetControlEnable();\r
842         }\r
843 }\r
844 int CRebaseDlg::CheckNextCommitIsSquash()\r
845 {\r
846         int index;\r
847         if(m_CommitList.m_IsOldFirst)\r
848                 index=m_CurrentRebaseIndex+1;\r
849         else\r
850                 index=m_CurrentRebaseIndex-1;\r
851 \r
852         GitRev *curRev;\r
853         do\r
854         {\r
855                 if(index<0)\r
856                         return -1;\r
857                 if(index>= m_CommitList.GetItemCount())\r
858                         return -1;\r
859 \r
860                 curRev=(GitRev*)m_CommitList.m_arShownList[index];\r
861                 \r
862                 if( curRev->m_Action&CTGitPath::LOGACTIONS_REBASE_SQUASH )\r
863                         return 0;\r
864                 if( curRev->m_Action&CTGitPath::LOGACTIONS_REBASE_SKIP)\r
865                 {\r
866                         if(m_CommitList.m_IsOldFirst)\r
867                                 index++;\r
868                         else\r
869                                 index--;\r
870                 }else\r
871                         return -1;              \r
872 \r
873         }while(curRev->m_Action&CTGitPath::LOGACTIONS_REBASE_SKIP);\r
874         \r
875         return -1;\r
876 \r
877 }\r
878 int CRebaseDlg::GoNext()\r
879 {\r
880         if(m_CommitList.m_IsOldFirst)\r
881                 m_CurrentRebaseIndex++;\r
882         else\r
883                 m_CurrentRebaseIndex--; \r
884         return 0;\r
885 \r
886 }\r
887 int CRebaseDlg::StateAction()\r
888 {\r
889         switch(this->m_RebaseStage)\r
890         {\r
891         case CHOOSE_BRANCH:\r
892         case CHOOSE_COMMIT_PICK_MODE:\r
893                 if(StartRebase())\r
894                         return -1;\r
895                 m_RebaseStage = REBASE_START;\r
896                 GoNext();\r
897                 break;\r
898         }\r
899 \r
900         return 0;       \r
901 }\r
902 void CRebaseDlg::SetContinueButtonText()\r
903 {\r
904         CString Text;\r
905         switch(this->m_RebaseStage)\r
906         {\r
907         case CHOOSE_BRANCH:\r
908         case CHOOSE_COMMIT_PICK_MODE:\r
909                 if(this->m_IsFastForward)\r
910                         Text = _T("Start(FastFwd)");\r
911                 else\r
912                         Text = _T("Start");\r
913                 break;\r
914 \r
915         case REBASE_START:\r
916         case REBASE_CONTINUE:\r
917         case REBASE_SQUASH_CONFLICT:\r
918                 Text = _T("Continue");\r
919                 break;\r
920 \r
921         case REBASE_CONFLICT:\r
922                 Text = _T("Commit");\r
923                 break;\r
924         case REBASE_EDIT:\r
925                 Text = _T("Amend");\r
926                 break;\r
927 \r
928         case REBASE_SQUASH_EDIT:\r
929                 Text = _T("Commit");\r
930                 break;\r
931 \r
932         case REBASE_ABORT:\r
933         case REBASE_FINISH:\r
934                 Text = _T("Finish");\r
935                 break;\r
936 \r
937         case REBASE_DONE:\r
938                 Text = _T("Done");\r
939                 break;\r
940         }\r
941         this->GetDlgItem(IDC_REBASE_CONTINUE)->SetWindowText(Text);\r
942 }\r
943 \r
944 void CRebaseDlg::SetControlEnable()\r
945 {\r
946         switch(this->m_RebaseStage)\r
947         {\r
948         case CHOOSE_BRANCH:\r
949         case CHOOSE_COMMIT_PICK_MODE:\r
950                 \r
951                 this->GetDlgItem(IDC_PICK_ALL)->EnableWindow(TRUE);\r
952                 this->GetDlgItem(IDC_EDIT_ALL)->EnableWindow(TRUE);\r
953                 this->GetDlgItem(IDC_SQUASH_ALL)->EnableWindow(TRUE);\r
954                 if(!m_IsCherryPick)\r
955                 {\r
956                         this->GetDlgItem(IDC_REBASE_COMBOXEX_BRANCH)->EnableWindow(TRUE);\r
957                         this->GetDlgItem(IDC_REBASE_COMBOXEX_UPSTREAM)->EnableWindow(TRUE);\r
958                 }\r
959                 //this->m_CommitList.m_IsEnableRebaseMenu=TRUE;\r
960                 this->m_CommitList.m_ContextMenuMask |= m_CommitList.GetContextMenuBit(CGitLogListBase::ID_REBASE_PICK)|\r
961                                                                                                 m_CommitList.GetContextMenuBit(CGitLogListBase::ID_REBASE_SQUASH)|\r
962                                                                                                 m_CommitList.GetContextMenuBit(CGitLogListBase::ID_REBASE_EDIT)|\r
963                                                                                                 m_CommitList.GetContextMenuBit(CGitLogListBase::ID_REBASE_SKIP);\r
964                 break;\r
965 \r
966         case REBASE_START:\r
967         case REBASE_CONTINUE:\r
968         case REBASE_ABORT:\r
969         case REBASE_FINISH:\r
970         case REBASE_CONFLICT:\r
971         case REBASE_EDIT:\r
972         case REBASE_SQUASH_CONFLICT:\r
973         case REBASE_DONE:\r
974                 this->GetDlgItem(IDC_PICK_ALL)->EnableWindow(FALSE);\r
975                 this->GetDlgItem(IDC_EDIT_ALL)->EnableWindow(FALSE);\r
976                 this->GetDlgItem(IDC_SQUASH_ALL)->EnableWindow(FALSE);\r
977                 this->GetDlgItem(IDC_REBASE_COMBOXEX_BRANCH)->EnableWindow(FALSE);\r
978                 this->GetDlgItem(IDC_REBASE_COMBOXEX_UPSTREAM)->EnableWindow(FALSE);\r
979                 //this->m_CommitList.m_IsEnableRebaseMenu=FALSE;\r
980                 this->m_CommitList.m_ContextMenuMask &= ~(m_CommitList.GetContextMenuBit(CGitLogListBase::ID_REBASE_PICK)|\r
981                                                                                                 m_CommitList.GetContextMenuBit(CGitLogListBase::ID_REBASE_SQUASH)|\r
982                                                                                                 m_CommitList.GetContextMenuBit(CGitLogListBase::ID_REBASE_EDIT)|\r
983                                                                                                 m_CommitList.GetContextMenuBit(CGitLogListBase::ID_REBASE_SKIP));\r
984 \r
985                 if( m_RebaseStage == REBASE_DONE && (!this->m_PostButtonText.IsEmpty()) )\r
986                 {\r
987                         this->GetDlgItem(IDC_STATUS_STATIC)->ShowWindow(SW_HIDE);\r
988                         this->GetDlgItem(IDC_REBASE_POST_BUTTON)->ShowWindow(SW_SHOWNORMAL);\r
989                         this->GetDlgItem(IDC_REBASE_POST_BUTTON)->SetWindowText(this->m_PostButtonText);\r
990                 }\r
991                 break;\r
992         }\r
993 \r
994         if(m_bThreadRunning)\r
995         {\r
996                 this->GetDlgItem(IDC_REBASE_CONTINUE)->EnableWindow(FALSE);\r
997                 this->GetDlgItem(IDC_REBASE_ABORT)->EnableWindow(FALSE);\r
998 \r
999         }else\r
1000         {\r
1001                 this->GetDlgItem(IDC_REBASE_CONTINUE)->EnableWindow(TRUE);\r
1002                 this->GetDlgItem(IDC_REBASE_ABORT)->EnableWindow(TRUE);\r
1003         }\r
1004 }\r
1005 \r
1006 void CRebaseDlg::UpdateProgress()\r
1007 {\r
1008         int index;\r
1009         CRect rect;\r
1010 \r
1011         if(m_CommitList.m_IsOldFirst)\r
1012                 index = m_CurrentRebaseIndex+1;\r
1013         else\r
1014                 index = m_CommitList.GetItemCount()-m_CurrentRebaseIndex;\r
1015 \r
1016         m_ProgressBar.SetRange(1,m_CommitList.GetItemCount());\r
1017         m_ProgressBar.SetPos(index);\r
1018 \r
1019         if(m_CurrentRebaseIndex>=0 && m_CurrentRebaseIndex< m_CommitList.GetItemCount())\r
1020         {\r
1021                 CString text;\r
1022                 text.Format(_T("Rebasing...(%d/%d)"),index,m_CommitList.GetItemCount());\r
1023                 m_CtrlStatusText.SetWindowText(text);\r
1024 \r
1025         }\r
1026 \r
1027         GitRev *prevRev=NULL, *curRev=NULL;\r
1028 \r
1029         if( m_CurrentRebaseIndex >= 0 && m_CurrentRebaseIndex< m_CommitList.m_arShownList.GetSize())\r
1030         {\r
1031                 curRev=(GitRev*)m_CommitList.m_arShownList[m_CurrentRebaseIndex];\r
1032         }\r
1033         \r
1034         for(int i=0;i<m_CommitList.m_arShownList.GetSize();i++)\r
1035         {\r
1036                 prevRev=(GitRev*)m_CommitList.m_arShownList[i];\r
1037                 if(prevRev->m_Action & CTGitPath::LOGACTIONS_REBASE_CURRENT)\r
1038                 {       \r
1039                         prevRev->m_Action &= ~ CTGitPath::LOGACTIONS_REBASE_CURRENT;\r
1040                         m_CommitList.GetItemRect(i,&rect,LVIR_BOUNDS);\r
1041                         m_CommitList.InvalidateRect(rect);\r
1042                 }\r
1043         }\r
1044 \r
1045         if(curRev)\r
1046         {\r
1047                 curRev->m_Action |= CTGitPath::LOGACTIONS_REBASE_CURRENT;\r
1048                 m_CommitList.GetItemRect(m_CurrentRebaseIndex,&rect,LVIR_BOUNDS);\r
1049                 m_CommitList.InvalidateRect(rect);\r
1050         }\r
1051         m_CommitList.EnsureVisible(m_CurrentRebaseIndex,FALSE);\r
1052 \r
1053 }\r
1054 \r
1055 void CRebaseDlg::UpdateCurrentStatus()\r
1056 {\r
1057         if( m_CurrentRebaseIndex < 0 && m_RebaseStage!= REBASE_DONE)\r
1058         {\r
1059                 if(m_CommitList.m_IsOldFirst)\r
1060                         m_RebaseStage = CRebaseDlg::REBASE_START;\r
1061                 else\r
1062                         m_RebaseStage = CRebaseDlg::REBASE_FINISH;\r
1063         }\r
1064 \r
1065         if( m_CurrentRebaseIndex == m_CommitList.m_arShownList.GetSize() && m_RebaseStage!= REBASE_DONE)\r
1066         {\r
1067                 if(m_CommitList.m_IsOldFirst)\r
1068                         m_RebaseStage = CRebaseDlg::REBASE_DONE;\r
1069                 else\r
1070                         m_RebaseStage = CRebaseDlg::REBASE_FINISH;\r
1071         }\r
1072 \r
1073         SetContinueButtonText();\r
1074         SetControlEnable();\r
1075         UpdateProgress();\r
1076 }\r
1077 \r
1078 void CRebaseDlg::AddLogString(CString str)\r
1079 {\r
1080         this->m_wndOutputRebase.SendMessage(SCI_SETREADONLY, FALSE);\r
1081         CStringA sTextA = m_wndOutputRebase.StringForControl(str);//CUnicodeUtils::GetUTF8(str);\r
1082         this->m_wndOutputRebase.SendMessage(SCI_REPLACESEL, 0, (LPARAM)(LPCSTR)sTextA);\r
1083         this->m_wndOutputRebase.SendMessage(SCI_REPLACESEL, 0, (LPARAM)(LPCSTR)"\n");\r
1084         this->m_wndOutputRebase.SendMessage(SCI_SETREADONLY, TRUE);\r
1085 }\r
1086 \r
1087 int CRebaseDlg::GetCurrentCommitID()\r
1088 {\r
1089         if(m_CommitList.m_IsOldFirst)\r
1090         {\r
1091                 return this->m_CurrentRebaseIndex+1;\r
1092 \r
1093         }else\r
1094         {\r
1095                 return m_CommitList.GetItemCount()-m_CurrentRebaseIndex;\r
1096         }\r
1097 }\r
1098 \r
1099 int CRebaseDlg::DoRebase()\r
1100 {       \r
1101         CString cmd,out;\r
1102         if(m_CurrentRebaseIndex <0)\r
1103                 return 0;\r
1104         if(m_CurrentRebaseIndex >= m_CommitList.GetItemCount() )\r
1105                 return 0;\r
1106 \r
1107         GitRev *pRev = (GitRev*)m_CommitList.m_arShownList[m_CurrentRebaseIndex];\r
1108         int mode=pRev->m_Action & CTGitPath::LOGACTIONS_REBASE_MODE_MASK;\r
1109         CString nocommit;\r
1110 \r
1111         if( mode== CTGitPath::LOGACTIONS_REBASE_SKIP)\r
1112         {\r
1113                 pRev->m_Action|= CTGitPath::LOGACTIONS_REBASE_DONE;\r
1114                 return 0;\r
1115         }\r
1116         \r
1117         if( mode != CTGitPath::LOGACTIONS_REBASE_PICK )\r
1118         {\r
1119                 this->m_SquashMessage+= pRev->m_Subject;\r
1120                 this->m_SquashMessage+= _T("\n");\r
1121                 this->m_SquashMessage+= pRev->m_Body;\r
1122         }\r
1123         else\r
1124                 this->m_SquashMessage.Empty();\r
1125 \r
1126         if(mode == CTGitPath::LOGACTIONS_REBASE_SQUASH)\r
1127                 nocommit=_T(" --no-commit ");\r
1128 \r
1129         CString log;\r
1130         log.Format(_T("%s %d:%s"),CTGitPath::GetActionName(mode),this->GetCurrentCommitID(),pRev->m_CommitHash);\r
1131         AddLogString(log);\r
1132         AddLogString(pRev->m_Subject);\r
1133         cmd.Format(_T("git.exe cherry-pick %s %s"),nocommit,pRev->m_CommitHash);\r
1134 \r
1135         if(g_Git.Run(cmd,&out,CP_UTF8))\r
1136         {\r
1137                 AddLogString(out);\r
1138                 CTGitPathList list;\r
1139                 if(g_Git.ListConflictFile(list))\r
1140                 {\r
1141                         AddLogString(_T("Get conflict files fail"));\r
1142                         return -1;\r
1143                 }\r
1144                 if(list.GetCount() == 0 )\r
1145                 {\r
1146                         if(mode ==  CTGitPath::LOGACTIONS_REBASE_PICK)\r
1147                         {\r
1148                                 pRev->m_Action|= CTGitPath::LOGACTIONS_REBASE_DONE;\r
1149                                 return 0;\r
1150                         }\r
1151                         if(mode == CTGitPath::LOGACTIONS_REBASE_EDIT)\r
1152                         {\r
1153                                 this->m_RebaseStage = REBASE_EDIT ;\r
1154                                 return -1; // Edit return -1 to stop rebase. \r
1155                         }\r
1156                         // Squash Case\r
1157                         if(CheckNextCommitIsSquash())\r
1158                         {   // no squash\r
1159                                 // let user edit last commmit message\r
1160                                 this->m_RebaseStage = REBASE_SQUASH_EDIT;\r
1161                                 return -1;\r
1162                         }\r
1163                 }\r
1164                 if(mode == CTGitPath::LOGACTIONS_REBASE_SQUASH)\r
1165                         m_RebaseStage = REBASE_SQUASH_CONFLICT;\r
1166                 else\r
1167                         m_RebaseStage = REBASE_CONFLICT;\r
1168                 return -1;      \r
1169 \r
1170         }else\r
1171         {\r
1172                 AddLogString(out);\r
1173                 if(mode ==  CTGitPath::LOGACTIONS_REBASE_PICK)\r
1174                 {\r
1175                         pRev->m_Action|= CTGitPath::LOGACTIONS_REBASE_DONE;\r
1176                         return 0;\r
1177                 }\r
1178                 if(mode == CTGitPath::LOGACTIONS_REBASE_EDIT)\r
1179                 {\r
1180                         this->m_RebaseStage = REBASE_EDIT ;\r
1181                         return -1; // Edit return -1 to stop rebase. \r
1182                 }\r
1183 \r
1184                 // Squash Case\r
1185                 if(CheckNextCommitIsSquash())\r
1186                 {   // no squash\r
1187                         // let user edit last commmit message\r
1188                         this->m_RebaseStage = REBASE_SQUASH_EDIT;\r
1189                         return -1;\r
1190                 }\r
1191         }\r
1192         \r
1193         return 0;\r
1194 }\r
1195 \r
1196 BOOL CRebaseDlg::IsEnd()\r
1197 {\r
1198         if(m_CommitList.m_IsOldFirst)\r
1199                 return m_CurrentRebaseIndex>= this->m_CommitList.GetItemCount();\r
1200         else\r
1201                 return m_CurrentRebaseIndex<0;\r
1202 }\r
1203 \r
1204 int CRebaseDlg::RebaseThread()\r
1205 {\r
1206         int ret=0;\r
1207         while(1)\r
1208         {\r
1209                 if( m_RebaseStage == REBASE_START )\r
1210                 {\r
1211                         if( this->StartRebase() )\r
1212                         {\r
1213                                 InterlockedExchange(&m_bThreadRunning, FALSE);\r
1214                                 ret = -1;\r
1215                                 break;\r
1216                         }\r
1217                         m_RebaseStage = REBASE_CONTINUE;\r
1218 \r
1219                 }else if( m_RebaseStage == REBASE_CONTINUE )\r
1220                 {\r
1221                         this->GoNext(); \r
1222                         if(IsEnd())\r
1223                         {\r
1224                                 ret = 0;\r
1225                                 m_RebaseStage = REBASE_FINISH;\r
1226                                 \r
1227                         }else\r
1228                         {\r
1229                                 ret = DoRebase();\r
1230 \r
1231                                 if( ret )\r
1232                                 {       \r
1233                                         break;\r
1234                                 }\r
1235                         }\r
1236 \r
1237                 }else if( m_RebaseStage == REBASE_FINISH )\r
1238                 {                       \r
1239                         FinishRebase();\r
1240                         m_RebaseStage = REBASE_DONE;\r
1241                         break;\r
1242                         \r
1243                 }else\r
1244                 {\r
1245                         break;\r
1246                 }\r
1247                 this->PostMessage(MSG_REBASE_UPDATE_UI);\r
1248                 //this->UpdateCurrentStatus();\r
1249         }\r
1250 \r
1251         InterlockedExchange(&m_bThreadRunning, FALSE);\r
1252         this->PostMessage(MSG_REBASE_UPDATE_UI);\r
1253         return ret;\r
1254 }\r
1255 \r
1256 void CRebaseDlg::ListConflictFile()\r
1257 {\r
1258         this->m_FileListCtrl.Clear();   \r
1259         CTGitPathList list;\r
1260         CTGitPath path;\r
1261         list.AddPath(path);\r
1262 \r
1263         this->m_FileListCtrl.GetStatus(&list,true);\r
1264         this->m_FileListCtrl.Show(CTGitPath::LOGACTIONS_UNMERGED|CTGitPath::LOGACTIONS_MODIFIED|CTGitPath::LOGACTIONS_ADDED|CTGitPath::LOGACTIONS_DELETED,\r
1265                                                            CTGitPath::LOGACTIONS_UNMERGED);\r
1266         if( this->m_FileListCtrl.GetItemCount() == 0 )\r
1267         {\r
1268                 \r
1269         }\r
1270 }\r
1271 \r
1272 LRESULT CRebaseDlg::OnRebaseUpdateUI(WPARAM,LPARAM)\r
1273 {\r
1274         UpdateCurrentStatus();\r
1275         if(m_CurrentRebaseIndex <0)\r
1276                 return 0;\r
1277         if(m_CurrentRebaseIndex >= m_CommitList.GetItemCount() )\r
1278                 return 0;\r
1279         GitRev *curRev=(GitRev*)m_CommitList.m_arShownList[m_CurrentRebaseIndex];\r
1280         \r
1281         switch(m_RebaseStage)\r
1282         {\r
1283         case REBASE_CONFLICT:\r
1284         case REBASE_SQUASH_CONFLICT:\r
1285                 ListConflictFile();                     \r
1286                 this->m_ctrlTabCtrl.SetActiveTab(REBASE_TAB_CONFLICT);\r
1287                 this->m_LogMessageCtrl.SetText(curRev->m_Subject+_T("\n")+curRev->m_Body);\r
1288                 break;\r
1289         case REBASE_EDIT:\r
1290                 this->m_ctrlTabCtrl.SetActiveTab(REBASE_TAB_MESSAGE);\r
1291                 this->m_LogMessageCtrl.SetText(curRev->m_Subject+_T("\n")+curRev->m_Body);\r
1292                 break;\r
1293         case REBASE_SQUASH_EDIT:\r
1294                 this->m_ctrlTabCtrl.SetActiveTab(REBASE_TAB_MESSAGE);\r
1295                 this->m_LogMessageCtrl.SetText(this->m_SquashMessage);\r
1296                 break;\r
1297         default:\r
1298                 this->m_ctrlTabCtrl.SetActiveTab(REBASE_TAB_LOG);\r
1299         }       \r
1300         return 0;\r
1301 }\r
1302 void CRebaseDlg::OnCancel()\r
1303 {\r
1304         OnBnClickedAbort();\r
1305 }\r
1306 void CRebaseDlg::OnBnClickedAbort()\r
1307 {\r
1308         CString cmd,out;\r
1309         if(m_OrigUpstreamHash.IsEmpty())\r
1310         {\r
1311                 __super::OnCancel();\r
1312         }\r
1313         \r
1314         if(m_RebaseStage == CHOOSE_BRANCH || m_RebaseStage== CHOOSE_COMMIT_PICK_MODE)\r
1315         {\r
1316                 return;\r
1317         }\r
1318 \r
1319         if(CMessageBox::Show(NULL,_T("Are you sure you want to abort the rebase process?"),_T("TortoiseGit"),MB_YESNO) != IDYES)\r
1320                 return;\r
1321 \r
1322         if(this->m_IsFastForward)\r
1323         {\r
1324                 cmd.Format(_T("git.exe reset --hard  %s"),this->m_OrigBranchHash.Left(40));\r
1325                 if(g_Git.Run(cmd,&out,CP_UTF8))\r
1326                 {\r
1327                         AddLogString(out);\r
1328                         return ;\r
1329                 }\r
1330                 __super::OnCancel();\r
1331                 return;\r
1332         }\r
1333         cmd.Format(_T("git.exe checkout -f %s"),this->m_UpstreamCtrl.GetString());\r
1334         if(g_Git.Run(cmd,&out,CP_UTF8))\r
1335         {\r
1336                 AddLogString(out);\r
1337                 return ;\r
1338         }\r
1339 \r
1340         cmd.Format(_T("git.exe reset --hard  %s"),this->m_OrigUpstreamHash.Left(40));\r
1341         if(g_Git.Run(cmd,&out,CP_UTF8))\r
1342         {\r
1343                 AddLogString(out);\r
1344                 return ;\r
1345         }\r
1346         \r
1347         if(this->m_IsCherryPick) //there are not "branch" at cherry pick mode\r
1348                 return;\r
1349 \r
1350         cmd.Format(_T("git checkout -f %s"),this->m_BranchCtrl.GetString());\r
1351         if(g_Git.Run(cmd,&out,CP_UTF8))\r
1352         {\r
1353                 AddLogString(out);\r
1354                 return ;\r
1355         }\r
1356         \r
1357         cmd.Format(_T("git.exe reset --hard  %s"),this->m_OrigBranchHash.Left(40));\r
1358         if(g_Git.Run(cmd,&out,CP_UTF8))\r
1359         {\r
1360                 AddLogString(out);\r
1361                 return ;\r
1362         }\r
1363         __super::OnCancel();\r
1364 }\r
1365 \r
1366 void CRebaseDlg::OnBnClickedButtonBrowse()\r
1367 {\r
1368         if(CBrowseRefsDlg::PickRefForCombo(&m_UpstreamCtrl, gPickRef_NoTag))\r
1369                 OnCbnSelchangeUpstream();\r
1370 }\r
1371 \r
1372 void CRebaseDlg::OnBnClickedRebaseCheckForce()\r
1373 {\r
1374         // TODO: Add your control notification handler code here\r
1375         this->UpdateData();\r
1376         this->FetchLogList();\r
1377 }\r
1378 \r
1379 void CRebaseDlg::OnStnClickedStatusStatic()\r
1380 {\r
1381         // TODO: Add your control notification handler code here\r
1382 }\r
1383 \r
1384 void CRebaseDlg::OnBnClickedRebasePostButton()\r
1385 {\r
1386         // TODO: Add your control notification handler code here\r
1387         this->m_Upstream=this->m_UpstreamCtrl.GetString();\r
1388         this->m_Branch=this->m_BranchCtrl.GetString();\r
1389 \r
1390         this->EndDialog(IDC_REBASE_POST_BUTTON);\r
1391 }\r