1 // RebaseDlg.cpp : implementation file
5 #include "TortoiseProc.h"
8 #include "MessageBox.h"
9 #include "UnicodeUtils.h"
10 #include "BrowseRefsDlg.h"
13 IMPLEMENT_DYNAMIC(CRebaseDlg
, CResizableStandAloneDialog
)
15 CRebaseDlg::CRebaseDlg(CWnd
* pParent
/*=NULL*/)
16 : CResizableStandAloneDialog(CRebaseDlg::IDD
, pParent
)
21 m_RebaseStage
=CHOOSE_BRANCH
;
22 m_CurrentRebaseIndex
=-1;
23 m_bThreadRunning
=FALSE
;
24 this->m_IsCherryPick
= FALSE
;
27 CRebaseDlg::~CRebaseDlg()
31 void CRebaseDlg::DoDataExchange(CDataExchange
* pDX
)
33 CDialog::DoDataExchange(pDX
);
34 DDX_Control(pDX
, IDC_REBASE_PROGRESS
, m_ProgressBar
);
35 DDX_Control(pDX
, IDC_STATUS_STATIC
, m_CtrlStatusText
);
36 DDX_Check(pDX
, IDC_PICK_ALL
, m_bPickAll
);
37 DDX_Check(pDX
, IDC_SQUASH_ALL
, m_bSquashAll
);
38 DDX_Check(pDX
, IDC_EDIT_ALL
, m_bEditAll
);
39 DDX_Control(pDX
, IDC_REBASE_SPLIT
, m_wndSplitter
);
40 DDX_Control(pDX
,IDC_COMMIT_LIST
,m_CommitList
);
41 DDX_Control(pDX
,IDC_REBASE_COMBOXEX_BRANCH
, this->m_BranchCtrl
);
42 DDX_Control(pDX
,IDC_REBASE_COMBOXEX_UPSTREAM
, this->m_UpstreamCtrl
);
47 BEGIN_MESSAGE_MAP(CRebaseDlg
, CResizableStandAloneDialog
)
48 ON_BN_CLICKED(IDC_PICK_ALL
, &CRebaseDlg::OnBnClickedPickAll
)
49 ON_BN_CLICKED(IDC_SQUASH_ALL
, &CRebaseDlg::OnBnClickedSquashAll
)
50 ON_BN_CLICKED(IDC_EDIT_ALL
, &CRebaseDlg::OnBnClickedEditAll
)
51 ON_BN_CLICKED(IDC_REBASE_SPLIT
, &CRebaseDlg::OnBnClickedRebaseSplit
)
52 ON_BN_CLICKED(IDC_REBASE_CONTINUE
,OnBnClickedContinue
)
53 ON_BN_CLICKED(IDC_REBASE_ABORT
, OnBnClickedAbort
)
55 ON_CBN_SELCHANGE(IDC_REBASE_COMBOXEX_BRANCH
, &CRebaseDlg::OnCbnSelchangeBranch
)
56 ON_CBN_SELCHANGE(IDC_REBASE_COMBOXEX_UPSTREAM
, &CRebaseDlg::OnCbnSelchangeUpstream
)
57 ON_MESSAGE(MSG_REBASE_UPDATE_UI
, OnRebaseUpdateUI
)
58 ON_BN_CLICKED(IDC_BUTTON_BROWSE
, &CRebaseDlg::OnBnClickedButtonBrowse
)
61 void CRebaseDlg::AddRebaseAnchor()
63 AddAnchor(IDC_REBASE_TAB
,TOP_LEFT
,BOTTOM_RIGHT
);
64 AddAnchor(IDC_COMMIT_LIST
,TOP_LEFT
, TOP_RIGHT
);
65 AddAnchor(IDC_REBASE_SPLIT
,TOP_LEFT
, TOP_RIGHT
);
66 AddAnchor(IDC_STATUS_STATIC
, BOTTOM_LEFT
,BOTTOM_RIGHT
);
67 AddAnchor(IDC_REBASE_CONTINUE
,BOTTOM_RIGHT
);
68 AddAnchor(IDC_REBASE_ABORT
, BOTTOM_RIGHT
);
69 AddAnchor(IDC_REBASE_PROGRESS
,BOTTOM_LEFT
, BOTTOM_RIGHT
);
70 AddAnchor(IDC_PICK_ALL
,TOP_LEFT
);
71 AddAnchor(IDC_SQUASH_ALL
,TOP_LEFT
);
72 AddAnchor(IDC_EDIT_ALL
,TOP_LEFT
);
73 AddAnchor(IDC_REBASE_COMBOXEX_UPSTREAM
,TOP_LEFT
);
74 AddAnchor(IDC_REBASE_COMBOXEX_BRANCH
,TOP_LEFT
);
75 AddAnchor(IDC_REBASE_STATIC_UPSTREAM
,TOP_LEFT
);
76 AddAnchor(IDC_REBASE_STATIC_BRANCH
,TOP_LEFT
);
77 this->AddOthersToAnchor();
80 BOOL
CRebaseDlg::OnInitDialog()
82 CResizableStandAloneDialog::OnInitDialog();
87 GetClientRect(m_DlgOrigRect
);
88 m_CommitList
.GetClientRect(m_CommitListOrigRect
);
90 CWnd
*pwnd
=this->GetDlgItem(IDC_REBASE_DUMY_TAB
);
91 pwnd
->GetWindowRect(&rectDummy
);
92 this->ScreenToClient(rectDummy
);
94 if (!m_ctrlTabCtrl
.Create(CMFCTabCtrl::STYLE_FLAT
, rectDummy
, this, IDC_REBASE_TAB
))
96 TRACE0("Failed to create output tab window\n");
97 return FALSE
; // fail to create
99 m_ctrlTabCtrl
.SetResizeMode(CMFCTabCtrl::RESIZE_NO
);
100 // Create output panes:
101 //const DWORD dwStyle = LBS_NOINTEGRALHEIGHT | WS_CHILD | WS_VISIBLE | WS_HSCROLL | WS_VSCROLL;
102 DWORD dwStyle
=LVS_REPORT
| LVS_SHOWSELALWAYS
| LVS_ALIGNLEFT
| WS_BORDER
| WS_TABSTOP
|LVS_SINGLESEL
|WS_CHILD
| WS_VISIBLE
;
104 if (! this->m_FileListCtrl
.Create(dwStyle
,rectDummy
,&this->m_ctrlTabCtrl
,0) )
106 TRACE0("Failed to create output windows\n");
107 return FALSE
; // fail to create
110 if( ! this->m_LogMessageCtrl
.Create(_T("Scintilla"),_T("source"),0,rectDummy
,&m_ctrlTabCtrl
,0,0) )
112 TRACE0("Failed to create log message control");
115 m_LogMessageCtrl
.Init(0);
117 dwStyle
= LBS_NOINTEGRALHEIGHT
| WS_CHILD
| WS_VISIBLE
| WS_HSCROLL
| WS_VSCROLL
;
119 if (!m_wndOutputRebase
.Create(_T("Scintilla"),_T("source"),0,rectDummy
, &m_ctrlTabCtrl
, 0,0) )
121 TRACE0("Failed to create output windows\n");
122 return -1; // fail to create
124 m_wndOutputRebase
.Init(0);
125 m_wndOutputRebase
.Call(SCI_SETREADONLY
, TRUE
);
127 m_tooltips
.Create(this);
129 m_FileListCtrl
.Init(SVNSLC_COLEXT
| SVNSLC_COLSTATUS
|SVNSLC_COLADD
|SVNSLC_COLDEL
, _T("RebaseDlg"),(SVNSLC_POPALL
^ SVNSLC_POPCOMMIT
),false);
131 m_ctrlTabCtrl
.AddTab(&m_FileListCtrl
,_T("Conflict File"));
132 m_ctrlTabCtrl
.AddTab(&m_LogMessageCtrl
,_T("Commit Message"),1);
133 m_ctrlTabCtrl
.AddTab(&m_wndOutputRebase
,_T("Log"),2);
137 EnableSaveRestore(_T("RebaseDlg"));
139 DWORD yPos
= CRegDWORD(_T("Software\\TortoiseGit\\TortoiseProc\\ResizableState\\RebaseDlgSizer"));
140 RECT rcDlg
, rcLogMsg
, rcFileList
;
141 GetClientRect(&rcDlg
);
142 m_CommitList
.GetWindowRect(&rcLogMsg
);
143 ScreenToClient(&rcLogMsg
);
144 this->m_ctrlTabCtrl
.GetWindowRect(&rcFileList
);
145 ScreenToClient(&rcFileList
);
149 m_wndSplitter
.GetWindowRect(&rectSplitter
);
150 ScreenToClient(&rectSplitter
);
151 int delta
= yPos
- rectSplitter
.top
;
152 if ((rcLogMsg
.bottom
+ delta
> rcLogMsg
.top
)&&(rcLogMsg
.bottom
+ delta
< rcFileList
.bottom
- 30))
154 m_wndSplitter
.SetWindowPos(NULL
, 0, yPos
, 0, 0, SWP_NOSIZE
);
159 if( this->m_RebaseStage
== CHOOSE_BRANCH
)
161 this->LoadBranchInfo();
165 this->m_BranchCtrl
.EnableWindow(FALSE
);
166 this->m_UpstreamCtrl
.EnableWindow(FALSE
);
169 m_CommitList
.m_IsIDReplaceAction
= TRUE
;
170 // m_CommitList.m_IsOldFirst = TRUE;
171 m_CommitList
.m_IsRebaseReplaceGraph
= TRUE
;
173 m_CommitList
.InsertGitColumn();
175 this->SetControlEnable();
179 this->m_BranchCtrl
.SetCurSel(-1);
180 this->m_BranchCtrl
.EnableWindow(FALSE
);
181 this->m_UpstreamCtrl
.EnableWindow(FALSE
);
182 this->SetWindowText(_T("Cherry Pick"));
183 this->m_CommitList
.StartFilter();
187 SetContinueButtonText();
188 m_CommitList
.DeleteAllItems();
192 m_CommitList
.m_ContextMenuMask
&= ~(m_CommitList
.GetContextMenuBit(CGitLogListBase::ID_CHERRY_PICK
)|
193 m_CommitList
.GetContextMenuBit(CGitLogListBase::ID_SWITCHTOREV
)|
194 m_CommitList
.GetContextMenuBit(CGitLogListBase::ID_RESET
)|
195 m_CommitList
.GetContextMenuBit(CGitLogListBase::ID_REVERTREV
)|
196 m_CommitList
.GetContextMenuBit(CGitLogListBase::ID_REBASE_TO_VERSION
)|
197 m_CommitList
.GetContextMenuBit(CGitLogListBase::ID_REVERTTOREV
)|
198 m_CommitList
.GetContextMenuBit(CGitLogListBase::ID_COMBINE_COMMIT
));
200 if(m_CommitList
.m_IsOldFirst
)
201 this->m_CurrentRebaseIndex
= -1;
203 this->m_CurrentRebaseIndex
= m_CommitList
.m_logEntries
.size();
208 // CRebaseDlg message handlers
210 void CRebaseDlg::OnBnClickedPickAll()
212 // TODO: Add your control notification handler code here
215 this->SetAllRebaseAction(CTGitPath::LOGACTIONS_REBASE_PICK
);
217 this->m_bEditAll
=FALSE
;
218 this->m_bSquashAll
=FALSE
;
219 this->UpdateData(FALSE
);
223 void CRebaseDlg::OnBnClickedSquashAll()
225 // TODO: Add your control notification handler code here
227 if(this->m_bSquashAll
)
228 this->SetAllRebaseAction(CTGitPath::LOGACTIONS_REBASE_SQUASH
);
230 this->m_bEditAll
=FALSE
;
231 this->m_bPickAll
=FALSE
;
232 this->UpdateData(FALSE
);
236 void CRebaseDlg::OnBnClickedEditAll()
238 // TODO: Add your control notification handler code here
240 if( this->m_bEditAll
)
241 this->SetAllRebaseAction(CTGitPath::LOGACTIONS_REBASE_EDIT
);
243 this->m_bPickAll
=FALSE
;
244 this->m_bSquashAll
=FALSE
;
245 this->UpdateData(FALSE
);
249 void CRebaseDlg::SetAllRebaseAction(int action
)
251 for(int i
=0;i
<this->m_CommitList
.m_logEntries
.size();i
++)
253 m_CommitList
.m_logEntries
[i
].m_Action
=action
;
255 m_CommitList
.Invalidate();
258 void CRebaseDlg::OnBnClickedRebaseSplit()
261 // TODO: Add your control notification handler code here
264 LRESULT
CRebaseDlg::DefWindowProc(UINT message
, WPARAM wParam
, LPARAM lParam
)
268 if (wParam
== IDC_REBASE_SPLIT
)
270 SPC_NMHDR
* pHdr
= (SPC_NMHDR
*) lParam
;
276 return __super::DefWindowProc(message
, wParam
, lParam
);
279 void CRebaseDlg::DoSize(int delta
)
282 this->RemoveAllAnchors();
284 CSplitterControl::ChangeHeight(GetDlgItem(IDC_COMMIT_LIST
), delta
, CW_TOPALIGN
);
285 //CSplitterControl::ChangeHeight(GetDlgItem(), delta, CW_TOPALIGN);
286 CSplitterControl::ChangeHeight(GetDlgItem(IDC_REBASE_TAB
), -delta
, CW_BOTTOMALIGN
);
287 //CSplitterControl::ChangeHeight(GetDlgItem(), -delta, CW_BOTTOMALIGN);
288 CSplitterControl::ChangePos(GetDlgItem(IDC_SQUASH_ALL
),0,delta
);
289 CSplitterControl::ChangePos(GetDlgItem(IDC_PICK_ALL
),0,delta
);
290 CSplitterControl::ChangePos(GetDlgItem(IDC_EDIT_ALL
),0,delta
);
292 this->AddRebaseAnchor();
293 // adjust the minimum size of the dialog to prevent the resizing from
294 // moving the list control too far down.
296 m_CommitList
.GetClientRect(rcLogMsg
);
297 SetMinTrackSize(CSize(m_DlgOrigRect
.Width(), m_DlgOrigRect
.Height()-m_CommitListOrigRect
.Height()+rcLogMsg
.Height()));
300 // m_CommitList.Invalidate();
302 // GetDlgItem(IDC_LOGMESSAGE)->Invalidate();
304 this->m_ctrlTabCtrl
.Invalidate();
305 this->m_CommitList
.Invalidate();
306 this->m_FileListCtrl
.Invalidate();
307 this->m_LogMessageCtrl
.Invalidate();
311 void CRebaseDlg::SetSplitterRange()
313 if ((m_CommitList
)&&(m_ctrlTabCtrl
))
316 m_CommitList
.GetWindowRect(rcTop
);
317 ScreenToClient(rcTop
);
319 m_ctrlTabCtrl
.GetWindowRect(rcMiddle
);
320 ScreenToClient(rcMiddle
);
321 if (rcMiddle
.Height() && rcMiddle
.Width())
322 m_wndSplitter
.SetRange(rcTop
.top
+60, rcMiddle
.bottom
-80);
326 void CRebaseDlg::OnSize(UINT nType
,int cx
, int cy
)
328 // first, let the resizing take place
329 __super::OnSize(nType
, cx
, cy
);
335 void CRebaseDlg::SaveSplitterPos()
339 CRegDWORD regPos
= CRegDWORD(_T("Software\\TortoiseGit\\TortoiseProc\\ResizableState\\RebaseDlgSizer"));
341 m_wndSplitter
.GetWindowRect(&rectSplitter
);
342 ScreenToClient(&rectSplitter
);
343 regPos
= rectSplitter
.top
;
347 void CRebaseDlg::LoadBranchInfo()
349 m_BranchCtrl
.SetMaxHistoryItems(0x7FFFFFFF);
350 m_UpstreamCtrl
.SetMaxHistoryItems(0x7FFFFFFF);
355 g_Git
.GetBranchList(list
,¤t
,CGit::BRANCH_ALL
);
356 m_BranchCtrl
.AddString(list
);
357 m_UpstreamCtrl
.AddString(list
);
359 m_BranchCtrl
.SetCurSel(current
);
361 AddBranchToolTips(&m_BranchCtrl
);
362 AddBranchToolTips(&m_UpstreamCtrl
);
364 if(!m_Upstream
.IsEmpty())
366 m_UpstreamCtrl
.AddString(m_Upstream
);
367 m_UpstreamCtrl
.SetCurSel(m_UpstreamCtrl
.GetCount()-1);
371 void CRebaseDlg::OnCbnSelchangeBranch()
376 void CRebaseDlg::OnCbnSelchangeUpstream()
381 void CRebaseDlg::FetchLogList()
383 m_CommitList
.Clear();
384 this->m_CommitList
.FillGitLog(NULL
,0,&m_UpstreamCtrl
.GetString(),&m_BranchCtrl
.GetString());
385 if( m_CommitList
.GetItemCount() == 0 )
386 m_CommitList
.ShowText(_T("Nothing Rebase"));
388 CString hash
=g_Git
.GetHash(m_UpstreamCtrl
.GetString());
391 if(m_CommitList
.m_logEntries
[m_CommitList
.m_logEntries
.size()-1].m_ParentHash
.size() >=0 )
393 if(hash
== m_CommitList
.m_logEntries
[m_CommitList
.m_logEntries
.size()-1].m_ParentHash
[0])
395 m_CommitList
.Clear();
396 m_CommitList
.ShowText(_T("Nothing Rebase"));
402 AddBranchToolTips(&this->m_BranchCtrl
);
403 AddBranchToolTips(&this->m_UpstreamCtrl
);
405 for(int i
=0;i
<m_CommitList
.m_logEntries
.size();i
++)
407 m_CommitList
.m_logEntries
[i
].m_Action
= CTGitPath::LOGACTIONS_REBASE_PICK
;
410 m_CommitList
.Invalidate();
412 if(m_CommitList
.m_IsOldFirst
)
413 this->m_CurrentRebaseIndex
= -1;
415 this->m_CurrentRebaseIndex
= m_CommitList
.m_logEntries
.size();
419 void CRebaseDlg::AddBranchToolTips(CHistoryCombo
*pBranch
)
423 CString text
=pBranch
->GetString();
426 g_Git
.GetLog(data
,text
,NULL
,1,0);
428 rev
.ParserFromLog(data
);
429 tooltip
.Format(_T("CommitHash:%s\nCommit by: %s %s\n <b>%s</b> \n %s"),
432 CAppUtils::FormatDateAndTime(rev
.m_AuthorDate
,DATE_LONGDATE
),
436 pBranch
->DisableTooltip();
437 this->m_tooltips
.AddTool(pBranch
->GetComboBoxCtrl(),tooltip
);
441 BOOL
CRebaseDlg::PreTranslateMessage(MSG
*pMsg
)
443 m_tooltips
.RelayEvent(pMsg
);
444 return CResizableStandAloneDialog::PreTranslateMessage(pMsg
);
446 int CRebaseDlg::CheckRebaseCondition()
448 this->m_ctrlTabCtrl
.SetActiveTab(REBASE_TAB_LOG
);
450 if( !g_Git
.CheckCleanWorkTree() )
452 CMessageBox::Show(NULL
,_T("Rebase Need Clean Working Tree"),_T("TortoiseGit"),MB_OK
);
455 //Todo Check $REBASE_ROOT
459 cmd
=_T("git.exe var GIT_COMMITTER_IDENT");
460 if(g_Git
.Run(cmd
,NULL
,CP_UTF8
))
463 //Todo call pre_rebase_hook
466 int CRebaseDlg::StartRebase()
470 if(!this->m_IsCherryPick
)
472 //Todo call comment_for_reflog
473 cmd
.Format(_T("git.exe checkout %s"),this->m_BranchCtrl
.GetString());
474 this->AddLogString(cmd
);
476 if(g_Git
.Run(cmd
,&out
,CP_UTF8
))
479 this->AddLogString(out
);
482 cmd
=_T("git.exe rev-parse --verify HEAD");
483 if(g_Git
.Run(cmd
,&out
,CP_UTF8
))
485 AddLogString(_T("No Head"));
489 //git symbolic-ref HEAD > "$DOTEST"/head-name 2> /dev/null ||
490 // echo "detached HEAD" > "$DOTEST"/head-name
492 cmd
.Format(_T("git.exe update-ref ORIG_HEAD HEAD"));
493 if(g_Git
.Run(cmd
,&out
,CP_UTF8
))
495 AddLogString(_T("update ORIG_HEAD Fail"));
499 if( !this->m_IsCherryPick
)
501 cmd
.Format(_T("git.exe checkout %s"),this->m_UpstreamCtrl
.GetString());
502 this->AddLogString(cmd
);
505 if(g_Git
.Run(cmd
,&out
,CP_UTF8
))
511 m_OrigUpstreamHash
.Empty();
512 m_OrigUpstreamHash
= g_Git
.GetHash(this->m_UpstreamCtrl
.GetString());
513 if(m_OrigUpstreamHash
.IsEmpty())
515 this->AddLogString(m_OrigUpstreamHash
);
519 if( !this->m_IsCherryPick
)
521 cmd
.Format(_T("git.exe rev-parse %s"),this->m_BranchCtrl
.GetString());
522 if(g_Git
.Run(cmd
,&this->m_OrigBranchHash
,CP_UTF8
))
524 this->AddLogString(m_OrigBranchHash
);
527 this->AddLogString(_T("Start Rebase\r\n"));
530 this->AddLogString(_T("Start Cherry-pick\r\n"));
534 int CRebaseDlg::VerifyNoConflict()
537 if(g_Git
.ListConflictFile(list
))
539 AddLogString(_T("Get conflict files fail"));
542 if( list
.GetCount() != 0 )
544 CMessageBox::Show(NULL
,_T("There are conflict file, you should mark it resolve"),_T("TortoiseGit"),MB_OK
);
550 int CRebaseDlg::FinishRebase()
552 if(this->m_IsCherryPick
) //cherry pick mode no "branch", working at upstream branch
556 cmd
.Format(_T("git.exe branch -f %s"),this->m_BranchCtrl
.GetString());
557 if(g_Git
.Run(cmd
,&out
,CP_UTF8
))
563 cmd
.Format(_T("git.exe reset --hard %s"),this->m_OrigUpstreamHash
);
564 if(g_Git
.Run(cmd
,&out
,CP_UTF8
))
570 cmd
.Format(_T("git.exe checkout -f %s"),this->m_BranchCtrl
.GetString());
571 if(g_Git
.Run(cmd
,&out
,CP_UTF8
))
578 void CRebaseDlg::OnBnClickedContinue()
580 if( m_RebaseStage
== CHOOSE_BRANCH
|| m_RebaseStage
== CHOOSE_COMMIT_PICK_MODE
)
582 if(CheckRebaseCondition())
584 m_RebaseStage
= REBASE_START
;
587 if( m_RebaseStage
== REBASE_DONE
)
592 if( m_RebaseStage
== REBASE_FINISH
)
600 if( m_RebaseStage
== REBASE_SQUASH_CONFLICT
)
602 if(VerifyNoConflict())
604 GitRev
*curRev
=(GitRev
*)m_CommitList
.m_arShownList
[m_CurrentRebaseIndex
];
605 if(this->CheckNextCommitIsSquash())
606 {//next commit is not squash;
607 m_RebaseStage
= REBASE_SQUASH_EDIT
;
608 this->OnRebaseUpdateUI(0,0);
609 this->UpdateCurrentStatus();
613 m_RebaseStage
=REBASE_CONTINUE
;
614 curRev
->m_Action
|=CTGitPath::LOGACTIONS_REBASE_DONE
;
615 this->UpdateCurrentStatus();
619 if( m_RebaseStage
== REBASE_CONFLICT
)
621 if(VerifyNoConflict())
624 GitRev
*curRev
=(GitRev
*)m_CommitList
.m_arShownList
[m_CurrentRebaseIndex
];
628 cmd
.Format(_T("git.exe commit -C %s"), curRev
->m_CommitHash
);
630 if(g_Git
.Run(cmd
,&out
,CP_UTF8
))
632 if(!g_Git
.CheckCleanWorkTree())
634 CMessageBox::Show(NULL
,out
,_T("TortoiseGit"),MB_OK
|MB_ICONERROR
);
640 this->m_ctrlTabCtrl
.SetActiveTab(REBASE_TAB_LOG
);
641 if( curRev
->m_Action
& CTGitPath::LOGACTIONS_REBASE_EDIT
)
643 m_RebaseStage
=REBASE_EDIT
;
644 this->m_ctrlTabCtrl
.SetActiveTab(REBASE_TAB_MESSAGE
);
645 this->UpdateCurrentStatus();
650 m_RebaseStage
=REBASE_CONTINUE
;
651 curRev
->m_Action
|=CTGitPath::LOGACTIONS_REBASE_DONE
;
652 this->UpdateCurrentStatus();
657 if( m_RebaseStage
== REBASE_EDIT
|| m_RebaseStage
== REBASE_SQUASH_EDIT
)
660 GitRev
*curRev
=(GitRev
*)m_CommitList
.m_arShownList
[m_CurrentRebaseIndex
];
662 str
=this->m_LogMessageCtrl
.GetText();
663 if(str
.Trim().IsEmpty())
665 CMessageBox::Show(NULL
,_T("Commit Message Is Empty"),_T("TortoiseGit"),MB_OK
|MB_ICONERROR
);
669 CString tempfile
=::GetTempFile();
670 CFile
file(tempfile
,CFile::modeReadWrite
|CFile::modeCreate
);
671 CStringA log
=CUnicodeUtils::GetUTF8( str
);
672 file
.Write(log
,log
.GetLength());
673 //file.WriteString(m_sLogMessage);
678 if( m_RebaseStage
== REBASE_SQUASH_EDIT
)
679 cmd
.Format(_T("git.exe commit -F \"%s\""), tempfile
);
681 cmd
.Format(_T("git.exe commit --amend -F \"%s\""), tempfile
);
683 if(g_Git
.Run(cmd
,&out
,CP_UTF8
))
685 if(!g_Git
.CheckCleanWorkTree())
687 CMessageBox::Show(NULL
,out
,_T("TortoiseGit"),MB_OK
|MB_ICONERROR
);
692 CFile::Remove(tempfile
);
694 this->m_ctrlTabCtrl
.SetActiveTab(REBASE_TAB_LOG
);
695 m_RebaseStage
=REBASE_CONTINUE
;
696 curRev
->m_Action
|=CTGitPath::LOGACTIONS_REBASE_DONE
;
697 this->UpdateCurrentStatus();
701 InterlockedExchange(&m_bThreadRunning
, TRUE
);
704 if (AfxBeginThread(RebaseThreadEntry
, this)==NULL
)
706 InterlockedExchange(&m_bThreadRunning
, FALSE
);
707 CMessageBox::Show(NULL
, _T("Create Rebase Thread Fail"), _T("TortoiseGit"), MB_OK
| MB_ICONERROR
);
711 int CRebaseDlg::CheckNextCommitIsSquash()
714 if(m_CommitList
.m_IsOldFirst
)
715 index
=m_CurrentRebaseIndex
+1;
717 index
=m_CurrentRebaseIndex
-1;
724 if(index
>= m_CommitList
.GetItemCount())
727 curRev
=(GitRev
*)m_CommitList
.m_arShownList
[index
];
729 if( curRev
->m_Action
&CTGitPath::LOGACTIONS_REBASE_SQUASH
)
731 if( curRev
->m_Action
&CTGitPath::LOGACTIONS_REBASE_SKIP
)
733 if(m_CommitList
.m_IsOldFirst
)
740 }while(curRev
->m_Action
&CTGitPath::LOGACTIONS_REBASE_SKIP
);
745 int CRebaseDlg::GoNext()
747 if(m_CommitList
.m_IsOldFirst
)
748 m_CurrentRebaseIndex
++;
750 m_CurrentRebaseIndex
--;
754 int CRebaseDlg::StateAction()
756 switch(this->m_RebaseStage
)
759 case CHOOSE_COMMIT_PICK_MODE
:
762 m_RebaseStage
= REBASE_START
;
769 void CRebaseDlg::SetContinueButtonText()
772 switch(this->m_RebaseStage
)
775 case CHOOSE_COMMIT_PICK_MODE
:
780 case REBASE_CONTINUE
:
781 case REBASE_SQUASH_CONFLICT
:
782 Text
= _T("Continue");
785 case REBASE_CONFLICT
:
792 case REBASE_SQUASH_EDIT
:
805 this->GetDlgItem(IDC_REBASE_CONTINUE
)->SetWindowText(Text
);
808 void CRebaseDlg::SetControlEnable()
810 switch(this->m_RebaseStage
)
813 case CHOOSE_COMMIT_PICK_MODE
:
815 this->GetDlgItem(IDC_PICK_ALL
)->EnableWindow(TRUE
);
816 this->GetDlgItem(IDC_EDIT_ALL
)->EnableWindow(TRUE
);
817 this->GetDlgItem(IDC_SQUASH_ALL
)->EnableWindow(TRUE
);
820 this->GetDlgItem(IDC_REBASE_COMBOXEX_BRANCH
)->EnableWindow(TRUE
);
821 this->GetDlgItem(IDC_REBASE_COMBOXEX_UPSTREAM
)->EnableWindow(TRUE
);
823 //this->m_CommitList.m_IsEnableRebaseMenu=TRUE;
824 this->m_CommitList
.m_ContextMenuMask
|= m_CommitList
.GetContextMenuBit(CGitLogListBase::ID_REBASE_PICK
)|
825 m_CommitList
.GetContextMenuBit(CGitLogListBase::ID_REBASE_SQUASH
)|
826 m_CommitList
.GetContextMenuBit(CGitLogListBase::ID_REBASE_EDIT
)|
827 m_CommitList
.GetContextMenuBit(CGitLogListBase::ID_REBASE_SKIP
);
831 case REBASE_CONTINUE
:
834 case REBASE_CONFLICT
:
836 case REBASE_SQUASH_CONFLICT
:
838 this->GetDlgItem(IDC_PICK_ALL
)->EnableWindow(FALSE
);
839 this->GetDlgItem(IDC_EDIT_ALL
)->EnableWindow(FALSE
);
840 this->GetDlgItem(IDC_SQUASH_ALL
)->EnableWindow(FALSE
);
841 this->GetDlgItem(IDC_REBASE_COMBOXEX_BRANCH
)->EnableWindow(FALSE
);
842 this->GetDlgItem(IDC_REBASE_COMBOXEX_UPSTREAM
)->EnableWindow(FALSE
);
843 //this->m_CommitList.m_IsEnableRebaseMenu=FALSE;
844 this->m_CommitList
.m_ContextMenuMask
&= ~(m_CommitList
.GetContextMenuBit(CGitLogListBase::ID_REBASE_PICK
)|
845 m_CommitList
.GetContextMenuBit(CGitLogListBase::ID_REBASE_SQUASH
)|
846 m_CommitList
.GetContextMenuBit(CGitLogListBase::ID_REBASE_EDIT
)|
847 m_CommitList
.GetContextMenuBit(CGitLogListBase::ID_REBASE_SKIP
));
853 this->GetDlgItem(IDC_REBASE_CONTINUE
)->EnableWindow(FALSE
);
854 this->GetDlgItem(IDC_REBASE_ABORT
)->EnableWindow(FALSE
);
858 this->GetDlgItem(IDC_REBASE_CONTINUE
)->EnableWindow(TRUE
);
859 this->GetDlgItem(IDC_REBASE_ABORT
)->EnableWindow(TRUE
);
863 void CRebaseDlg::UpdateProgress()
868 if(m_CommitList
.m_IsOldFirst
)
869 index
= m_CurrentRebaseIndex
+1;
871 index
= m_CommitList
.GetItemCount()-m_CurrentRebaseIndex
;
873 m_ProgressBar
.SetRange(1,m_CommitList
.GetItemCount());
874 m_ProgressBar
.SetPos(index
);
876 if(m_CurrentRebaseIndex
>=0 && m_CurrentRebaseIndex
< m_CommitList
.GetItemCount())
879 text
.Format(_T("Rebasing...(%d/%d)"),index
,m_CommitList
.GetItemCount());
880 m_CtrlStatusText
.SetWindowText(text
);
884 GitRev
*prevRev
=NULL
, *curRev
=NULL
;
886 if( m_CurrentRebaseIndex
>= 0 && m_CurrentRebaseIndex
< m_CommitList
.m_arShownList
.GetSize())
888 curRev
=(GitRev
*)m_CommitList
.m_arShownList
[m_CurrentRebaseIndex
];
891 for(int i
=0;i
<m_CommitList
.m_arShownList
.GetSize();i
++)
893 prevRev
=(GitRev
*)m_CommitList
.m_arShownList
[i
];
894 if(prevRev
->m_Action
& CTGitPath::LOGACTIONS_REBASE_CURRENT
)
896 prevRev
->m_Action
&= ~ CTGitPath::LOGACTIONS_REBASE_CURRENT
;
897 m_CommitList
.GetItemRect(i
,&rect
,LVIR_BOUNDS
);
898 m_CommitList
.InvalidateRect(rect
);
904 curRev
->m_Action
|= CTGitPath::LOGACTIONS_REBASE_CURRENT
;
905 m_CommitList
.GetItemRect(m_CurrentRebaseIndex
,&rect
,LVIR_BOUNDS
);
906 m_CommitList
.InvalidateRect(rect
);
908 m_CommitList
.EnsureVisible(m_CurrentRebaseIndex
,FALSE
);
912 void CRebaseDlg::UpdateCurrentStatus()
914 if( m_CurrentRebaseIndex
< 0 && m_RebaseStage
!= REBASE_DONE
)
916 if(m_CommitList
.m_IsOldFirst
)
917 m_RebaseStage
= CRebaseDlg::REBASE_START
;
919 m_RebaseStage
= CRebaseDlg::REBASE_FINISH
;
922 if( m_CurrentRebaseIndex
== m_CommitList
.m_arShownList
.GetSize() && m_RebaseStage
!= REBASE_DONE
)
924 if(m_CommitList
.m_IsOldFirst
)
925 m_RebaseStage
= CRebaseDlg::REBASE_DONE
;
927 m_RebaseStage
= CRebaseDlg::REBASE_FINISH
;
930 SetContinueButtonText();
935 void CRebaseDlg::AddLogString(CString str
)
937 this->m_wndOutputRebase
.SendMessage(SCI_SETREADONLY
, FALSE
);
938 CStringA sTextA
= m_wndOutputRebase
.StringForControl(str
);//CUnicodeUtils::GetUTF8(str);
939 this->m_wndOutputRebase
.SendMessage(SCI_REPLACESEL
, 0, (LPARAM
)(LPCSTR
)sTextA
);
940 this->m_wndOutputRebase
.SendMessage(SCI_REPLACESEL
, 0, (LPARAM
)(LPCSTR
)"\n");
941 this->m_wndOutputRebase
.SendMessage(SCI_SETREADONLY
, TRUE
);
944 int CRebaseDlg::GetCurrentCommitID()
946 if(m_CommitList
.m_IsOldFirst
)
948 return this->m_CurrentRebaseIndex
+1;
952 return m_CommitList
.GetItemCount()-m_CurrentRebaseIndex
;
956 int CRebaseDlg::DoRebase()
959 if(m_CurrentRebaseIndex
<0)
961 if(m_CurrentRebaseIndex
>= m_CommitList
.GetItemCount() )
964 GitRev
*pRev
= (GitRev
*)m_CommitList
.m_arShownList
[m_CurrentRebaseIndex
];
965 int mode
=pRev
->m_Action
& CTGitPath::LOGACTIONS_REBASE_MODE_MASK
;
968 if( mode
== CTGitPath::LOGACTIONS_REBASE_SKIP
)
970 pRev
->m_Action
|= CTGitPath::LOGACTIONS_REBASE_DONE
;
974 if( mode
!= CTGitPath::LOGACTIONS_REBASE_PICK
)
976 this->m_SquashMessage
+= pRev
->m_Subject
;
977 this->m_SquashMessage
+= _T("\n");
978 this->m_SquashMessage
+= pRev
->m_Body
;
981 this->m_SquashMessage
.Empty();
983 if(mode
== CTGitPath::LOGACTIONS_REBASE_SQUASH
)
984 nocommit
=_T(" --no-commit ");
987 log
.Format(_T("%s %d:%s"),CTGitPath::GetActionName(mode
),this->GetCurrentCommitID(),pRev
->m_CommitHash
);
989 AddLogString(pRev
->m_Subject
);
990 cmd
.Format(_T("git.exe cherry-pick %s %s"),nocommit
,pRev
->m_CommitHash
);
992 if(g_Git
.Run(cmd
,&out
,CP_UTF8
))
996 if(g_Git
.ListConflictFile(list
))
998 AddLogString(_T("Get conflict files fail"));
1001 if(list
.GetCount() == 0 )
1003 if(mode
== CTGitPath::LOGACTIONS_REBASE_PICK
)
1005 pRev
->m_Action
|= CTGitPath::LOGACTIONS_REBASE_DONE
;
1008 if(mode
== CTGitPath::LOGACTIONS_REBASE_EDIT
)
1010 this->m_RebaseStage
= REBASE_EDIT
;
1011 return -1; // Edit return -1 to stop rebase.
1014 if(CheckNextCommitIsSquash())
1016 // let user edit last commmit message
1017 this->m_RebaseStage
= REBASE_SQUASH_EDIT
;
1021 if(mode
== CTGitPath::LOGACTIONS_REBASE_SQUASH
)
1022 m_RebaseStage
= REBASE_SQUASH_CONFLICT
;
1024 m_RebaseStage
= REBASE_CONFLICT
;
1030 if(mode
== CTGitPath::LOGACTIONS_REBASE_PICK
)
1032 pRev
->m_Action
|= CTGitPath::LOGACTIONS_REBASE_DONE
;
1035 if(mode
== CTGitPath::LOGACTIONS_REBASE_EDIT
)
1037 this->m_RebaseStage
= REBASE_EDIT
;
1038 return -1; // Edit return -1 to stop rebase.
1042 if(CheckNextCommitIsSquash())
1044 // let user edit last commmit message
1045 this->m_RebaseStage
= REBASE_SQUASH_EDIT
;
1053 BOOL
CRebaseDlg::IsEnd()
1055 if(m_CommitList
.m_IsOldFirst
)
1056 return m_CurrentRebaseIndex
>= this->m_CommitList
.GetItemCount();
1058 return m_CurrentRebaseIndex
<0;
1061 int CRebaseDlg::RebaseThread()
1066 if( m_RebaseStage
== REBASE_START
)
1068 if( this->StartRebase() )
1070 InterlockedExchange(&m_bThreadRunning
, FALSE
);
1074 m_RebaseStage
= REBASE_CONTINUE
;
1076 }else if( m_RebaseStage
== REBASE_CONTINUE
)
1082 m_RebaseStage
= REBASE_FINISH
;
1094 }else if( m_RebaseStage
== REBASE_FINISH
)
1097 m_RebaseStage
= REBASE_DONE
;
1104 this->PostMessage(MSG_REBASE_UPDATE_UI
);
1105 //this->UpdateCurrentStatus();
1108 InterlockedExchange(&m_bThreadRunning
, FALSE
);
1109 this->PostMessage(MSG_REBASE_UPDATE_UI
);
1113 void CRebaseDlg::ListConflictFile()
1115 this->m_FileListCtrl
.Clear();
1120 this->m_FileListCtrl
.GetStatus(&list
,true);
1121 this->m_FileListCtrl
.Show(CTGitPath::LOGACTIONS_UNMERGED
|CTGitPath::LOGACTIONS_MODIFIED
|CTGitPath::LOGACTIONS_ADDED
|CTGitPath::LOGACTIONS_DELETED
,
1122 CTGitPath::LOGACTIONS_UNMERGED
);
1123 if( this->m_FileListCtrl
.GetItemCount() == 0 )
1129 LRESULT
CRebaseDlg::OnRebaseUpdateUI(WPARAM
,LPARAM
)
1131 UpdateCurrentStatus();
1132 if(m_CurrentRebaseIndex
<0)
1134 if(m_CurrentRebaseIndex
>= m_CommitList
.GetItemCount() )
1136 GitRev
*curRev
=(GitRev
*)m_CommitList
.m_arShownList
[m_CurrentRebaseIndex
];
1138 switch(m_RebaseStage
)
1140 case REBASE_CONFLICT
:
1141 case REBASE_SQUASH_CONFLICT
:
1143 this->m_ctrlTabCtrl
.SetActiveTab(REBASE_TAB_CONFLICT
);
1144 this->m_LogMessageCtrl
.SetText(curRev
->m_Subject
+_T("\n")+curRev
->m_Body
);
1147 this->m_ctrlTabCtrl
.SetActiveTab(REBASE_TAB_MESSAGE
);
1148 this->m_LogMessageCtrl
.SetText(curRev
->m_Subject
+_T("\n")+curRev
->m_Body
);
1150 case REBASE_SQUASH_EDIT
:
1151 this->m_ctrlTabCtrl
.SetActiveTab(REBASE_TAB_MESSAGE
);
1152 this->m_LogMessageCtrl
.SetText(this->m_SquashMessage
);
1155 this->m_ctrlTabCtrl
.SetActiveTab(REBASE_TAB_LOG
);
1159 void CRebaseDlg::OnCancel()
1163 void CRebaseDlg::OnBnClickedAbort()
1166 if(m_OrigUpstreamHash
.IsEmpty())
1168 __super::OnCancel();
1171 if(m_RebaseStage
== CHOOSE_BRANCH
|| m_RebaseStage
== CHOOSE_COMMIT_PICK_MODE
)
1176 if(CMessageBox::Show(NULL
,_T("Are you sure abort rebase"),_T("TortoiseGit"),MB_YESNO
) != IDYES
)
1179 cmd
.Format(_T("git.exe checkout -f %s"),this->m_UpstreamCtrl
.GetString());
1180 if(g_Git
.Run(cmd
,&out
,CP_UTF8
))
1186 cmd
.Format(_T("git.exe reset --hard %s"),this->m_OrigUpstreamHash
.Left(40));
1187 if(g_Git
.Run(cmd
,&out
,CP_UTF8
))
1193 if(this->m_IsCherryPick
) //there are not "branch" at cherry pick mode
1196 cmd
.Format(_T("git checkout -f %s"),this->m_BranchCtrl
.GetString());
1197 if(g_Git
.Run(cmd
,&out
,CP_UTF8
))
1203 cmd
.Format(_T("git.exe reset --hard %s"),this->m_OrigBranchHash
.Left(40));
1204 if(g_Git
.Run(cmd
,&out
,CP_UTF8
))
1209 __super::OnCancel();
1212 void CRebaseDlg::OnBnClickedButtonBrowse()
1214 if(CBrowseRefsDlg::PickRefForCombo(&m_UpstreamCtrl
, gPickRef_NoTag
))
1215 OnCbnSelchangeUpstream();