1 // TortoiseGit - a Windows shell extension for easy version control
3 // Copyright (C) 2008-2014 - 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
24 #include "TortoiseProc.h"
25 #include "RebaseDlg.h"
27 #include "LoglistUtils.h"
28 #include "MessageBox.h"
29 #include "UnicodeUtils.h"
30 #include "BrowseRefsDlg.h"
31 #include "ProgressDlg.h"
32 #include "SmartHandle.h"
33 #include "../TGitCache/CacheInterface.h"
34 #include "Settings\Settings.h"
35 #include "MassiveGitTask.h"
36 #include "CommitDlg.h"
40 IMPLEMENT_DYNAMIC(CRebaseDlg
, CResizableStandAloneDialog
)
42 CRebaseDlg::CRebaseDlg(CWnd
* pParent
/*=NULL*/)
43 : CResizableStandAloneDialog(CRebaseDlg::IDD
, pParent
)
44 , m_bAddCherryPickedFrom(FALSE
)
45 , m_bStatusWarning(false)
46 , m_bAutoSkipFailedCommit(FALSE
)
47 , m_bFinishedRebase(false)
49 , m_bSplitCommit(FALSE
)
51 m_RebaseStage
=CHOOSE_BRANCH
;
52 m_CurrentRebaseIndex
=-1;
53 m_bThreadRunning
=FALSE
;
54 this->m_IsCherryPick
= FALSE
;
56 m_IsFastForward
=FALSE
;
59 CRebaseDlg::~CRebaseDlg()
63 void CRebaseDlg::DoDataExchange(CDataExchange
* pDX
)
65 CDialog::DoDataExchange(pDX
);
66 DDX_Control(pDX
, IDC_REBASE_PROGRESS
, m_ProgressBar
);
67 DDX_Control(pDX
, IDC_STATUS_STATIC
, m_CtrlStatusText
);
68 DDX_Control(pDX
, IDC_REBASE_SPLIT
, m_wndSplitter
);
69 DDX_Control(pDX
,IDC_COMMIT_LIST
,m_CommitList
);
70 DDX_Control(pDX
,IDC_REBASE_COMBOXEX_BRANCH
, this->m_BranchCtrl
);
71 DDX_Control(pDX
,IDC_REBASE_COMBOXEX_UPSTREAM
, this->m_UpstreamCtrl
);
72 DDX_Check(pDX
, IDC_REBASE_CHECK_FORCE
,m_bForce
);
73 DDX_Check(pDX
, IDC_CHECK_CHERRYPICKED_FROM
, m_bAddCherryPickedFrom
);
74 DDX_Control(pDX
,IDC_REBASE_POST_BUTTON
,m_PostButton
);
75 DDX_Control(pDX
, IDC_SPLITALLOPTIONS
, m_SplitAllOptions
);
76 DDX_Check(pDX
, IDC_REBASE_SPLIT_COMMIT
, m_bSplitCommit
);
80 BEGIN_MESSAGE_MAP(CRebaseDlg
, CResizableStandAloneDialog
)
81 ON_BN_CLICKED(IDC_REBASE_SPLIT
, &CRebaseDlg::OnBnClickedRebaseSplit
)
82 ON_BN_CLICKED(IDC_REBASE_CONTINUE
,OnBnClickedContinue
)
83 ON_BN_CLICKED(IDC_REBASE_ABORT
, OnBnClickedAbort
)
85 ON_CBN_SELCHANGE(IDC_REBASE_COMBOXEX_BRANCH
, &CRebaseDlg::OnCbnSelchangeBranch
)
86 ON_CBN_SELCHANGE(IDC_REBASE_COMBOXEX_UPSTREAM
, &CRebaseDlg::OnCbnSelchangeUpstream
)
87 ON_MESSAGE(MSG_REBASE_UPDATE_UI
, OnRebaseUpdateUI
)
88 ON_REGISTERED_MESSAGE(CGitStatusListCtrl::GITSLNM_NEEDSREFRESH
, OnGitStatusListCtrlNeedsRefresh
)
89 ON_BN_CLICKED(IDC_BUTTON_REVERSE
, OnBnClickedButtonReverse
)
90 ON_BN_CLICKED(IDC_BUTTON_BROWSE
, &CRebaseDlg::OnBnClickedButtonBrowse
)
91 ON_BN_CLICKED(IDC_REBASE_CHECK_FORCE
, &CRebaseDlg::OnBnClickedRebaseCheckForce
)
92 ON_BN_CLICKED(IDC_CHECK_CHERRYPICKED_FROM
, &CRebaseDlg::OnBnClickedCheckCherryPickedFrom
)
93 ON_BN_CLICKED(IDC_REBASE_POST_BUTTON
, &CRebaseDlg::OnBnClickedRebasePostButton
)
94 ON_BN_CLICKED(IDC_BUTTON_UP2
, &CRebaseDlg::OnBnClickedButtonUp2
)
95 ON_BN_CLICKED(IDC_BUTTON_DOWN2
, &CRebaseDlg::OnBnClickedButtonDown2
)
96 ON_REGISTERED_MESSAGE(WM_TASKBARBTNCREATED
, OnTaskbarBtnCreated
)
97 ON_NOTIFY(LVN_ITEMCHANGED
, IDC_COMMIT_LIST
, OnLvnItemchangedLoglist
)
98 ON_REGISTERED_MESSAGE(CGitLogListBase::m_RebaseActionMessage
, OnRebaseActionMessage
)
100 ON_BN_CLICKED(IDC_SPLITALLOPTIONS
, &CRebaseDlg::OnBnClickedSplitAllOptions
)
101 ON_BN_CLICKED(IDC_REBASE_SPLIT_COMMIT
, &CRebaseDlg::OnBnClickedRebaseSplitCommit
)
104 void CRebaseDlg::AddRebaseAnchor()
106 AddAnchor(IDC_REBASE_TAB
,TOP_LEFT
,BOTTOM_RIGHT
);
107 AddAnchor(IDC_COMMIT_LIST
,TOP_LEFT
, TOP_RIGHT
);
108 AddAnchor(IDC_REBASE_SPLIT
,TOP_LEFT
, TOP_RIGHT
);
109 AddAnchor(IDC_STATUS_STATIC
, BOTTOM_LEFT
,BOTTOM_RIGHT
);
110 AddAnchor(IDC_REBASE_CONTINUE
,BOTTOM_RIGHT
);
111 AddAnchor(IDC_REBASE_ABORT
, BOTTOM_RIGHT
);
112 AddAnchor(IDC_REBASE_PROGRESS
,BOTTOM_LEFT
, BOTTOM_RIGHT
);
113 AddAnchor(IDC_SPLITALLOPTIONS
, TOP_LEFT
);
114 AddAnchor(IDC_BUTTON_UP2
,TOP_LEFT
);
115 AddAnchor(IDC_BUTTON_DOWN2
,TOP_LEFT
);
116 AddAnchor(IDC_REBASE_COMBOXEX_UPSTREAM
,TOP_LEFT
);
117 AddAnchor(IDC_REBASE_COMBOXEX_BRANCH
,TOP_LEFT
);
118 AddAnchor(IDC_REBASE_STATIC_UPSTREAM
,TOP_LEFT
);
119 AddAnchor(IDC_REBASE_STATIC_BRANCH
,TOP_LEFT
);
120 AddAnchor(IDHELP
, BOTTOM_RIGHT
);
121 AddAnchor(IDC_REBASE_CHECK_FORCE
,TOP_RIGHT
);
122 AddAnchor(IDC_CHECK_CHERRYPICKED_FROM
, TOP_RIGHT
);
123 AddAnchor(IDC_REBASE_SPLIT_COMMIT
, BOTTOM_RIGHT
);
124 AddAnchor(IDC_REBASE_POST_BUTTON
,BOTTOM_LEFT
);
126 this->AddOthersToAnchor();
129 BOOL
CRebaseDlg::OnInitDialog()
131 CResizableStandAloneDialog::OnInitDialog();
132 CAppUtils::MarkWindowAsUnpinnable(m_hWnd
);
134 // Let the TaskbarButtonCreated message through the UIPI filter. If we don't
135 // do this, Explorer would be unable to send that message to our window if we
136 // were running elevated. It's OK to make the call all the time, since if we're
137 // not elevated, this is a no-op.
138 CHANGEFILTERSTRUCT cfs
= { sizeof(CHANGEFILTERSTRUCT
) };
139 typedef BOOL STDAPICALLTYPE
ChangeWindowMessageFilterExDFN(HWND hWnd
, UINT message
, DWORD action
, PCHANGEFILTERSTRUCT pChangeFilterStruct
);
140 CAutoLibrary hUser
= AtlLoadSystemLibraryUsingFullPath(_T("user32.dll"));
143 ChangeWindowMessageFilterExDFN
*pfnChangeWindowMessageFilterEx
= (ChangeWindowMessageFilterExDFN
*)GetProcAddress(hUser
, "ChangeWindowMessageFilterEx");
144 if (pfnChangeWindowMessageFilterEx
)
146 pfnChangeWindowMessageFilterEx(m_hWnd
, WM_TASKBARBTNCREATED
, MSGFLT_ALLOW
, &cfs
);
149 m_pTaskbarList
.Release();
150 if (FAILED(m_pTaskbarList
.CoCreateInstance(CLSID_TaskbarList
)))
151 m_pTaskbarList
= nullptr;
154 //IDC_REBASE_DUMY_TAB
156 GetClientRect(m_DlgOrigRect
);
157 m_CommitList
.GetClientRect(m_CommitListOrigRect
);
159 CWnd
*pwnd
=this->GetDlgItem(IDC_REBASE_DUMY_TAB
);
160 pwnd
->GetWindowRect(&rectDummy
);
161 this->ScreenToClient(rectDummy
);
163 if (!m_ctrlTabCtrl
.Create(CMFCTabCtrl::STYLE_FLAT
, rectDummy
, this, IDC_REBASE_TAB
))
165 TRACE0("Failed to create output tab window\n");
166 return FALSE
; // fail to create
168 m_ctrlTabCtrl
.SetResizeMode(CMFCTabCtrl::RESIZE_NO
);
169 // Create output panes:
170 //const DWORD dwStyle = LBS_NOINTEGRALHEIGHT | WS_CHILD | WS_VISIBLE | WS_HSCROLL | WS_VSCROLL;
171 DWORD dwStyle
=LVS_REPORT
| LVS_SHOWSELALWAYS
| LVS_ALIGNLEFT
| WS_BORDER
| WS_TABSTOP
| WS_CHILD
| WS_VISIBLE
;
173 if (! this->m_FileListCtrl
.Create(dwStyle
,rectDummy
,&this->m_ctrlTabCtrl
,0) )
175 TRACE0("Failed to create output windows\n");
176 return FALSE
; // fail to create
178 m_FileListCtrl
.m_hwndLogicalParent
= this;
180 if( ! this->m_LogMessageCtrl
.Create(_T("Scintilla"),_T("source"),0,rectDummy
,&m_ctrlTabCtrl
,0,0) )
182 TRACE0("Failed to create log message control");
185 m_LogMessageCtrl
.Init(0);
186 m_LogMessageCtrl
.Call(SCI_SETREADONLY
, TRUE
);
188 dwStyle
= LBS_NOINTEGRALHEIGHT
| WS_CHILD
| WS_VISIBLE
| WS_HSCROLL
| WS_VSCROLL
;
190 if (!m_wndOutputRebase
.Create(_T("Scintilla"),_T("source"),0,rectDummy
, &m_ctrlTabCtrl
, 0,0) )
192 TRACE0("Failed to create output windows\n");
193 return -1; // fail to create
195 m_wndOutputRebase
.Init(0, FALSE
);
196 m_wndOutputRebase
.Call(SCI_SETREADONLY
, TRUE
);
198 m_tooltips
.Create(this);
200 m_tooltips
.AddTool(IDC_REBASE_CHECK_FORCE
,IDS_REBASE_FORCE_TT
);
201 m_tooltips
.AddTool(IDC_REBASE_ABORT
, IDS_REBASE_ABORT_TT
);
205 temp
.LoadString(IDS_PROC_REBASE_SELECTALL_PICK
);
206 m_SplitAllOptions
.AddEntry(temp
);
207 temp
.LoadString(IDS_PROC_REBASE_SELECTALL_SQUASH
);
208 m_SplitAllOptions
.AddEntry(temp
);
209 temp
.LoadString(IDS_PROC_REBASE_SELECTALL_EDIT
);
210 m_SplitAllOptions
.AddEntry(temp
);
213 m_FileListCtrl
.Init(GITSLC_COLEXT
| GITSLC_COLSTATUS
|GITSLC_COLADD
|GITSLC_COLDEL
, _T("RebaseDlg"),(GITSLC_POPALL
^ (GITSLC_POPCOMMIT
|GITSLC_POPRESTORE
)), false, true, GITSLC_COLEXT
| GITSLC_COLSTATUS
| GITSLC_COLADD
| GITSLC_COLDEL
);
215 m_ctrlTabCtrl
.AddTab(&m_FileListCtrl
, CString(MAKEINTRESOURCE(IDS_PROC_REVISIONFILES
)));
216 m_ctrlTabCtrl
.AddTab(&m_LogMessageCtrl
, CString(MAKEINTRESOURCE(IDS_PROC_COMMITMESSAGE
)), 1);
219 AdjustControlSize(IDC_CHECK_CHERRYPICKED_FROM
);
220 AdjustControlSize(IDC_REBASE_SPLIT_COMMIT
);
222 CString sWindowTitle
;
223 GetWindowText(sWindowTitle
);
224 CAppUtils::SetWindowTitle(m_hWnd
, g_Git
.m_CurrentDir
, sWindowTitle
);
226 EnableSaveRestore(_T("RebaseDlg"));
228 DWORD yPos
= CRegDWORD(_T("Software\\TortoiseGit\\TortoiseProc\\ResizableState\\RebaseDlgSizer"));
229 RECT rcDlg
, rcLogMsg
, rcFileList
;
230 GetClientRect(&rcDlg
);
231 m_CommitList
.GetWindowRect(&rcLogMsg
);
232 ScreenToClient(&rcLogMsg
);
233 this->m_ctrlTabCtrl
.GetWindowRect(&rcFileList
);
234 ScreenToClient(&rcFileList
);
238 m_wndSplitter
.GetWindowRect(&rectSplitter
);
239 ScreenToClient(&rectSplitter
);
240 int delta
= yPos
- rectSplitter
.top
;
241 if ((rcLogMsg
.bottom
+ delta
> rcLogMsg
.top
)&&(rcLogMsg
.bottom
+ delta
< rcFileList
.bottom
- 30))
243 m_wndSplitter
.SetWindowPos(NULL
, 0, yPos
, 0, 0, SWP_NOSIZE
);
248 if( this->m_RebaseStage
== CHOOSE_BRANCH
)
250 this->LoadBranchInfo();
255 this->m_BranchCtrl
.EnableWindow(FALSE
);
256 this->m_UpstreamCtrl
.EnableWindow(FALSE
);
257 GetDlgItem(IDC_BUTTON_REVERSE
)->EnableWindow(FALSE
);
260 m_CommitList
.m_ColumnRegKey
= _T("Rebase");
261 m_CommitList
.m_IsIDReplaceAction
= TRUE
;
262 // m_CommitList.m_IsOldFirst = TRUE;
263 m_CommitList
.m_IsRebaseReplaceGraph
= TRUE
;
264 m_CommitList
.m_bNoHightlightHead
= TRUE
;
266 m_CommitList
.InsertGitColumn();
268 this->SetControlEnable();
272 this->m_BranchCtrl
.SetCurSel(-1);
273 this->m_BranchCtrl
.EnableWindow(FALSE
);
274 GetDlgItem(IDC_REBASE_CHECK_FORCE
)->ShowWindow(SW_HIDE
);
275 GetDlgItem(IDC_BUTTON_BROWSE
)->EnableWindow(FALSE
);
276 GetDlgItem(IDC_BUTTON_REVERSE
)->EnableWindow(FALSE
);
277 this->m_UpstreamCtrl
.AddString(_T("HEAD"));
278 this->m_UpstreamCtrl
.EnableWindow(FALSE
);
279 CAppUtils::SetWindowTitle(m_hWnd
, g_Git
.m_CurrentDir
, CString(MAKEINTRESOURCE(IDS_PROGS_TITLE_CHERRYPICK
)));
280 this->m_CommitList
.StartFilter();
284 GetDlgItem(IDC_CHECK_CHERRYPICKED_FROM
)->ShowWindow(SW_HIDE
);
285 ((CButton
*)GetDlgItem(IDC_BUTTON_REVERSE
))->SetIcon((HICON
)LoadImage(AfxGetResourceHandle(), MAKEINTRESOURCE(IDI_SWITCHLEFTRIGHT
), IMAGE_ICON
, 16, 16, LR_DEFAULTCOLOR
));
286 SetContinueButtonText();
287 m_CommitList
.DeleteAllItems();
291 m_CommitList
.m_ContextMenuMask
&= ~(m_CommitList
.GetContextMenuBit(CGitLogListBase::ID_CHERRY_PICK
)|
292 m_CommitList
.GetContextMenuBit(CGitLogListBase::ID_SWITCHTOREV
)|
293 m_CommitList
.GetContextMenuBit(CGitLogListBase::ID_RESET
)|
294 m_CommitList
.GetContextMenuBit(CGitLogListBase::ID_REVERTREV
)|
295 m_CommitList
.GetContextMenuBit(CGitLogListBase::ID_MERGEREV
) |
296 m_CommitList
.GetContextMenuBit(CGitLogListBase::ID_REBASE_TO_VERSION
)|
297 m_CommitList
.GetContextMenuBit(CGitLogListBase::ID_REVERTTOREV
)|
298 m_CommitList
.GetContextMenuBit(CGitLogListBase::ID_COMBINE_COMMIT
));
300 if(m_CommitList
.m_IsOldFirst
)
301 this->m_CurrentRebaseIndex
= -1;
303 this->m_CurrentRebaseIndex
= (int)m_CommitList
.m_logEntries
.size();
307 // CRebaseDlg message handlers
309 HBRUSH
CRebaseDlg::OnCtlColor(CDC
* pDC
, CWnd
* pWnd
, UINT nCtlColor
)
311 if (pWnd
->GetDlgCtrlID() == IDC_STATUS_STATIC
&& nCtlColor
== CTLCOLOR_STATIC
&& m_bStatusWarning
)
313 pDC
->SetBkColor(RGB(255, 0, 0));
314 pDC
->SetTextColor(RGB(255, 255, 255));
315 return CreateSolidBrush(RGB(255, 0, 0));
318 return CResizableStandAloneDialog::OnCtlColor(pDC
, pWnd
, nCtlColor
);
321 void CRebaseDlg::SetAllRebaseAction(int action
)
323 for (size_t i
= 0; i
< this->m_CommitList
.m_logEntries
.size(); ++i
)
325 m_CommitList
.m_logEntries
.GetGitRevAt(i
).GetRebaseAction() = action
;
327 m_CommitList
.Invalidate();
330 void CRebaseDlg::OnBnClickedRebaseSplit()
335 LRESULT
CRebaseDlg::DefWindowProc(UINT message
, WPARAM wParam
, LPARAM lParam
)
339 if (wParam
== IDC_REBASE_SPLIT
)
341 SPC_NMHDR
* pHdr
= (SPC_NMHDR
*) lParam
;
347 return __super::DefWindowProc(message
, wParam
, lParam
);
350 void CRebaseDlg::DoSize(int delta
)
352 this->RemoveAllAnchors();
354 CSplitterControl::ChangeHeight(GetDlgItem(IDC_COMMIT_LIST
), delta
, CW_TOPALIGN
);
355 //CSplitterControl::ChangeHeight(GetDlgItem(), delta, CW_TOPALIGN);
356 CSplitterControl::ChangeHeight(GetDlgItem(IDC_REBASE_TAB
), -delta
, CW_BOTTOMALIGN
);
357 //CSplitterControl::ChangeHeight(GetDlgItem(), -delta, CW_BOTTOMALIGN);
358 CSplitterControl::ChangePos(GetDlgItem(IDC_SPLITALLOPTIONS
), 0, delta
);
359 CSplitterControl::ChangePos(GetDlgItem(IDC_BUTTON_UP2
),0,delta
);
360 CSplitterControl::ChangePos(GetDlgItem(IDC_BUTTON_DOWN2
),0,delta
);
361 CSplitterControl::ChangePos(GetDlgItem(IDC_REBASE_CHECK_FORCE
),0,delta
);
362 CSplitterControl::ChangePos(GetDlgItem(IDC_CHECK_CHERRYPICKED_FROM
), 0, delta
);
364 this->AddRebaseAnchor();
365 // adjust the minimum size of the dialog to prevent the resizing from
366 // moving the list control too far down.
368 m_CommitList
.GetClientRect(rcLogMsg
);
369 SetMinTrackSize(CSize(m_DlgOrigRect
.Width(), m_DlgOrigRect
.Height()-m_CommitListOrigRect
.Height()+rcLogMsg
.Height()));
372 // m_CommitList.Invalidate();
374 // GetDlgItem(IDC_LOGMESSAGE)->Invalidate();
376 this->m_ctrlTabCtrl
.Invalidate();
377 this->m_CommitList
.Invalidate();
378 this->m_FileListCtrl
.Invalidate();
379 this->m_LogMessageCtrl
.Invalidate();
383 void CRebaseDlg::SetSplitterRange()
385 if ((m_CommitList
)&&(m_ctrlTabCtrl
))
388 m_CommitList
.GetWindowRect(rcTop
);
389 ScreenToClient(rcTop
);
391 m_ctrlTabCtrl
.GetWindowRect(rcMiddle
);
392 ScreenToClient(rcMiddle
);
393 if (rcMiddle
.Height() && rcMiddle
.Width())
394 m_wndSplitter
.SetRange(rcTop
.top
+60, rcMiddle
.bottom
-80);
398 void CRebaseDlg::OnSize(UINT nType
,int cx
, int cy
)
400 // first, let the resizing take place
401 __super::OnSize(nType
, cx
, cy
);
407 void CRebaseDlg::SaveSplitterPos()
411 CRegDWORD regPos
= CRegDWORD(_T("Software\\TortoiseGit\\TortoiseProc\\ResizableState\\RebaseDlgSizer"));
413 m_wndSplitter
.GetWindowRect(&rectSplitter
);
414 ScreenToClient(&rectSplitter
);
415 regPos
= rectSplitter
.top
;
419 void CRebaseDlg::LoadBranchInfo()
421 m_BranchCtrl
.SetMaxHistoryItems(0x7FFFFFFF);
422 m_UpstreamCtrl
.SetMaxHistoryItems(0x7FFFFFFF);
427 g_Git
.GetBranchList(list
,¤t
,CGit::BRANCH_ALL
);
428 m_BranchCtrl
.SetList(list
);
430 m_BranchCtrl
.SetCurSel(current
);
432 m_BranchCtrl
.AddString(g_Git
.GetCurrentBranch(true));
434 g_Git
.GetBranchList(list
, NULL
, CGit::BRANCH_ALL_F
);
435 m_UpstreamCtrl
.SetList(list
);
437 AddBranchToolTips(&m_BranchCtrl
);
439 if(!m_Upstream
.IsEmpty())
441 m_UpstreamCtrl
.AddString(m_Upstream
);
445 //Select pull-remote from current branch
446 CString pullRemote
, pullBranch
;
447 g_Git
.GetRemoteTrackedBranchForHEAD(pullRemote
, pullBranch
);
449 CString defaultUpstream
;
450 defaultUpstream
.Format(L
"remotes/%s/%s", pullRemote
, pullBranch
);
451 int found
= m_UpstreamCtrl
.FindStringExact(0, defaultUpstream
);
453 m_UpstreamCtrl
.SetCurSel(found
);
455 m_UpstreamCtrl
.SetCurSel(-1);
457 AddBranchToolTips(&m_UpstreamCtrl
);
460 void CRebaseDlg::OnCbnSelchangeBranch()
465 void CRebaseDlg::OnCbnSelchangeUpstream()
470 void CRebaseDlg::FetchLogList()
472 CGitHash base
,hash
,upstream
;
473 m_IsFastForward
=FALSE
;
475 if (m_BranchCtrl
.GetString().IsEmpty())
477 m_CommitList
.ShowText(CString(MAKEINTRESOURCE(IDS_SELECTBRANCH
)));
478 this->GetDlgItem(IDC_REBASE_CONTINUE
)->EnableWindow(false);
482 if (g_Git
.GetHash(hash
, m_BranchCtrl
.GetString()))
484 m_CommitList
.ShowText(g_Git
.GetGitLastErr(_T("Could not get hash of \"") + m_BranchCtrl
.GetString() + _T("\".")));
485 this->GetDlgItem(IDC_REBASE_CONTINUE
)->EnableWindow(false);
489 if (m_UpstreamCtrl
.GetString().IsEmpty())
491 m_CommitList
.ShowText(CString(MAKEINTRESOURCE(IDS_SELECTUPSTREAM
)));
492 this->GetDlgItem(IDC_REBASE_CONTINUE
)->EnableWindow(false);
496 if (g_Git
.GetHash(upstream
, m_UpstreamCtrl
.GetString()))
498 m_CommitList
.ShowText(g_Git
.GetGitLastErr(_T("Could not get hash of \"") + m_UpstreamCtrl
.GetString() + _T("\".")));
499 this->GetDlgItem(IDC_REBASE_CONTINUE
)->EnableWindow(false);
503 if (hash
== upstream
)
505 m_CommitList
.Clear();
507 fmt
.LoadString(IDS_REBASE_EQUAL_FMT
);
508 text
.Format(fmt
,m_BranchCtrl
.GetString(),this->m_UpstreamCtrl
.GetString());
510 m_CommitList
.ShowText(text
);
511 this->GetDlgItem(IDC_REBASE_CONTINUE
)->EnableWindow(false);
515 if (g_Git
.IsFastForward(m_BranchCtrl
.GetString(), m_UpstreamCtrl
.GetString(), &base
))
518 this->m_IsFastForward
=TRUE
;
520 m_CommitList
.Clear();
522 fmt
.LoadString(IDS_REBASE_FASTFORWARD_FMT
);
523 text
.Format(fmt
,m_BranchCtrl
.GetString(),this->m_UpstreamCtrl
.GetString(),
524 m_BranchCtrl
.GetString(),this->m_UpstreamCtrl
.GetString());
526 m_CommitList
.ShowText(text
);
527 this->GetDlgItem(IDC_REBASE_CONTINUE
)->EnableWindow(true);
528 SetContinueButtonText();
535 if (base
== upstream
)
537 m_CommitList
.Clear();
539 fmt
.LoadString(IDS_REBASE_UPTODATE_FMT
);
540 text
.Format(fmt
,m_BranchCtrl
.GetString());
541 m_CommitList
.ShowText(text
);
542 this->GetDlgItem(IDC_REBASE_CONTINUE
)->EnableWindow(m_CommitList
.GetItemCount());
543 SetContinueButtonText();
548 m_CommitList
.Clear();
549 CString refFrom
= g_Git
.FixBranchName(m_UpstreamCtrl
.GetString());
550 CString refTo
= g_Git
.FixBranchName(m_BranchCtrl
.GetString());
552 range
.Format(_T("%s..%s"), refFrom
, refTo
);
553 this->m_CommitList
.FillGitLog(nullptr, &range
, 0);
555 if( m_CommitList
.GetItemCount() == 0 )
556 m_CommitList
.ShowText(CString(MAKEINTRESOURCE(IDS_PROC_NOTHINGTOREBASE
)));
559 if(m_CommitList
.m_logEntries
[m_CommitList
.m_logEntries
.size()-1].m_ParentHash
.size() >=0 )
561 if(upstream
== m_CommitList
.m_logEntries
[m_CommitList
.m_logEntries
.size()-1].m_ParentHash
[0])
563 m_CommitList
.Clear();
564 m_CommitList
.ShowText(_T("Nothing Rebase"));
570 AddBranchToolTips(&this->m_BranchCtrl
);
571 AddBranchToolTips(&this->m_UpstreamCtrl
);
573 // Default all actions to 'pick'
574 std::map
<CGitHash
, size_t> revIxMap
;
575 for (size_t i
= 0; i
< m_CommitList
.m_logEntries
.size(); ++i
)
577 GitRev
& rev
= m_CommitList
.m_logEntries
.GetGitRevAt(i
);
578 rev
.GetRebaseAction() = CGitLogListBase::LOGACTIONS_REBASE_PICK
;
579 revIxMap
[rev
.m_CommitHash
] = i
;
582 // Default to skip when already in upstream
584 cherryCmd
.Format(L
"git.exe cherry \"%s\" \"%s\"", refFrom
, refTo
);
585 bool bHasSKip
= false;
586 g_Git
.Run(cherryCmd
, [&](const CStringA
& line
)
588 if (line
.GetLength() < 2)
591 return; // Don't skip (only skip commits starting with a '-')
592 CString hash
= CUnicodeUtils::GetUnicode(line
.Mid(1));
594 auto itIx
= revIxMap
.find(CGitHash(hash
));
595 if (itIx
== revIxMap
.end())
596 return; // Not found?? Should not occur...
599 m_CommitList
.m_logEntries
.GetGitRevAt(itIx
->second
).GetRebaseAction() = CGitLogListBase::LOGACTIONS_REBASE_SKIP
;
603 m_CommitList
.Invalidate();
606 m_CtrlStatusText
.SetWindowText(CString(MAKEINTRESOURCE(IDS_REBASE_AUTOSKIPPED
)));
607 m_bStatusWarning
= true;
611 m_CtrlStatusText
.SetWindowText(m_sStatusText
);
612 m_bStatusWarning
= false;
614 m_CtrlStatusText
.Invalidate();
616 if(m_CommitList
.m_IsOldFirst
)
617 this->m_CurrentRebaseIndex
= -1;
619 this->m_CurrentRebaseIndex
= (int)m_CommitList
.m_logEntries
.size();
621 this->GetDlgItem(IDC_REBASE_CONTINUE
)->EnableWindow(m_CommitList
.GetItemCount());
622 SetContinueButtonText();
625 void CRebaseDlg::AddBranchToolTips(CHistoryCombo
*pBranch
)
629 CString text
=pBranch
->GetString();
637 catch (const char *msg
)
639 CMessageBox::Show(m_hWnd
, _T("Could not get commit ") + text
+ _T("\nlibgit reports:\n") + CString(msg
), _T("TortoiseGit"), MB_ICONERROR
);
642 tooltip
.Format(_T("%s: %s\n%s: %s <%s>\n%s: %s\n%s:\n%s\n%s"),
643 CString(MAKEINTRESOURCE(IDS_LOG_REVISION
)),
644 rev
.m_CommitHash
.ToString(),
645 CString(MAKEINTRESOURCE(IDS_LOG_AUTHOR
)),
647 rev
.GetAuthorEmail(),
648 CString(MAKEINTRESOURCE(IDS_LOG_DATE
)),
649 CLoglistUtils::FormatDateAndTime(rev
.GetAuthorDate(), DATE_LONGDATE
),
650 CString(MAKEINTRESOURCE(IDS_LOG_MESSAGE
)),
654 pBranch
->DisableTooltip();
655 this->m_tooltips
.AddTool(pBranch
->GetComboBoxCtrl(),tooltip
);
659 BOOL
CRebaseDlg::PreTranslateMessage(MSG
*pMsg
)
661 if (pMsg
->message
== WM_KEYDOWN
)
663 switch (pMsg
->wParam
)
666 if (LogListHasFocus(pMsg
->hwnd
)
667 && LogListHasMenuItem(CGitLogListBase::ID_REBASE_PICK
)
668 && LogListHasMenuItem(CGitLogListBase::ID_REBASE_SQUASH
)
669 && LogListHasMenuItem(CGitLogListBase::ID_REBASE_EDIT
)
670 && LogListHasMenuItem(CGitLogListBase::ID_REBASE_SKIP
))
672 m_CommitList
.ShiftSelectedRebaseAction();
677 if (LogListHasFocus(pMsg
->hwnd
) && LogListHasMenuItem(CGitLogListBase::ID_REBASE_PICK
))
679 m_CommitList
.SetSelectedRebaseAction(CGitLogListBase::LOGACTIONS_REBASE_PICK
);
684 if (LogListHasFocus(pMsg
->hwnd
) && LogListHasMenuItem(CGitLogListBase::ID_REBASE_SKIP
))
686 m_CommitList
.SetSelectedRebaseAction(CGitLogListBase::LOGACTIONS_REBASE_SKIP
);
691 if (LogListHasFocus(pMsg
->hwnd
) && LogListHasMenuItem(CGitLogListBase::ID_REBASE_SQUASH
))
693 m_CommitList
.SetSelectedRebaseAction(CGitLogListBase::LOGACTIONS_REBASE_SQUASH
);
698 if (LogListHasFocus(pMsg
->hwnd
) && LogListHasMenuItem(CGitLogListBase::ID_REBASE_EDIT
))
700 m_CommitList
.SetSelectedRebaseAction(CGitLogListBase::LOGACTIONS_REBASE_EDIT
);
705 if(LogListHasFocus(pMsg
->hwnd
) && GetAsyncKeyState(VK_CONTROL
) & 0x8000)
707 // select all entries
708 for (int i
= 0; i
< m_CommitList
.GetItemCount(); ++i
)
710 m_CommitList
.SetItemState(i
, LVIS_SELECTED
, LVIS_SELECTED
);
723 if (GetAsyncKeyState(VK_CONTROL
) & 0x8000)
725 if (GetDlgItem(IDC_REBASE_CONTINUE
)->IsWindowEnabled())
726 GetDlgItem(IDC_REBASE_CONTINUE
)->SetFocus();
727 else if (GetDlgItem(IDC_REBASE_ABORT
)->IsWindowEnabled())
728 GetDlgItem(IDC_REBASE_ABORT
)->SetFocus();
730 GetDlgItem(IDHELP
)->SetFocus();
735 /* Avoid TAB control destroy but dialog exist*/
739 TCHAR buff
[128] = { 0 };
740 ::GetClassName(pMsg
->hwnd
,buff
,128);
743 /* Use MSFTEDIT_CLASS http://msdn.microsoft.com/en-us/library/bb531344.aspx */
744 if (_tcsnicmp(buff
, MSFTEDIT_CLASS
, 128) == 0 || //Unicode and MFC 2012 and later
745 _tcsnicmp(buff
, RICHEDIT_CLASS
, 128) == 0 || //ANSI or MFC 2010
746 _tcsnicmp(buff
,_T("Scintilla"),128)==0 ||
747 _tcsnicmp(buff
,_T("SysListView32"),128)==0||
748 ::GetParent(pMsg
->hwnd
) == this->m_ctrlTabCtrl
.m_hWnd
)
750 this->PostMessage(WM_KEYDOWN
,VK_ESCAPE
,0);
756 else if (pMsg
->message
== WM_NEXTDLGCTL
)
758 HWND hwnd
= GetFocus()->GetSafeHwnd();
759 if (hwnd
== m_LogMessageCtrl
.GetSafeHwnd() || hwnd
== m_wndOutputRebase
.GetSafeHwnd())
761 if (GetDlgItem(IDC_REBASE_CONTINUE
)->IsWindowEnabled())
762 GetDlgItem(IDC_REBASE_CONTINUE
)->SetFocus();
763 else if (GetDlgItem(IDC_REBASE_ABORT
)->IsWindowEnabled())
764 GetDlgItem(IDC_REBASE_ABORT
)->SetFocus();
766 GetDlgItem(IDHELP
)->SetFocus();
770 m_tooltips
.RelayEvent(pMsg
);
771 return CResizableStandAloneDialog::PreTranslateMessage(pMsg
);
774 bool CRebaseDlg::LogListHasFocus(HWND hwnd
)
776 TCHAR buff
[128] = { 0 };
777 ::GetClassName(hwnd
, buff
, 128);
779 if(_tcsnicmp(buff
, _T("SysListView32"), 128) == 0)
784 bool CRebaseDlg::LogListHasMenuItem(int i
)
786 return (m_CommitList
.m_ContextMenuMask
& m_CommitList
.GetContextMenuBit(i
)) != 0;
789 int CRebaseDlg::CheckRebaseCondition()
791 this->m_ctrlTabCtrl
.SetActiveTab(REBASE_TAB_LOG
);
793 if( !g_Git
.CheckCleanWorkTree() )
795 if (CMessageBox::Show(NULL
, IDS_ERROR_NOCLEAN_STASH
, IDS_APPNAME
, 1, IDI_QUESTION
, IDS_STASHBUTTON
, IDS_ABORTBUTTON
) == 1)
798 cmd
=_T("git.exe stash");
799 this->AddLogString(cmd
);
800 if (g_Git
.Run(cmd
, &out
, CP_UTF8
))
802 CMessageBox::Show(NULL
,out
,_T("TortoiseGit"),MB_OK
);
810 //Todo Check $REBASE_ROOT
813 if (!CAppUtils::CheckUserData())
816 //Todo call pre_rebase_hook
820 void CRebaseDlg::CheckRestoreStash()
822 if (m_bStashed
&& CMessageBox::Show(nullptr, IDS_DCOMMIT_STASH_POP
, IDS_APPNAME
, MB_YESNO
| MB_ICONQUESTION
) == IDYES
)
823 CAppUtils::StashPop();
827 int CRebaseDlg::StartRebase()
830 m_FileListCtrl
.m_bIsRevertTheirMy
= !m_IsCherryPick
;
832 m_OrigHEADBranch
= g_Git
.GetCurrentBranch(true);
834 m_OrigHEADHash
.Empty();
835 if (g_Git
.GetHash(m_OrigHEADHash
, _T("HEAD")))
837 AddLogString(CString(MAKEINTRESOURCE(IDS_PROC_NOHEAD
)));
841 //git symbolic-ref HEAD > "$DOTEST"/head-name 2> /dev/null ||
842 // echo "detached HEAD" > "$DOTEST"/head-name
844 cmd
.Format(_T("git.exe update-ref ORIG_HEAD ") + m_OrigHEADHash
.ToString());
845 if(g_Git
.Run(cmd
,&out
,CP_UTF8
))
847 AddLogString(_T("update ORIG_HEAD Fail"));
851 m_OrigUpstreamHash
.Empty();
852 if (g_Git
.GetHash(m_OrigUpstreamHash
, m_UpstreamCtrl
.GetString()))
854 MessageBox(g_Git
.GetGitLastErr(_T("Could not get hash of \"") + m_UpstreamCtrl
.GetString() + _T("\".")), _T("TortoiseGit"), MB_ICONERROR
);
858 if( !this->m_IsCherryPick
)
860 cmd
.Format(_T("git.exe checkout -f %s --"), m_OrigUpstreamHash
.ToString());
861 this->AddLogString(cmd
);
865 if (g_Git
.Run(cmd
, &out
, CP_UTF8
))
867 this->AddLogString(out
);
868 if (CMessageBox::Show(m_hWnd
, out
+ _T("\nRetry?"), _T("TortoiseGit"), MB_YESNO
| MB_ICONERROR
) != IDYES
)
877 if( !this->m_IsCherryPick
)
879 if (g_Git
.GetHash(m_OrigBranchHash
, m_BranchCtrl
.GetString()))
881 MessageBox(g_Git
.GetGitLastErr(_T("Could not get hash of \"") + m_BranchCtrl
.GetString() + _T("\".")), _T("TortoiseGit"), MB_ICONERROR
);
884 log
.Format(_T("%s\r\n"), CString(MAKEINTRESOURCE(IDS_PROC_REBASE_STARTREBASE
)));
887 log
.Format(_T("%s\r\n"), CString(MAKEINTRESOURCE(IDS_PROC_REBASE_STARTCHERRYPICK
)));
889 this->AddLogString(log
);
892 int CRebaseDlg::VerifyNoConflict()
895 if(g_Git
.ListConflictFile(list
))
897 AddLogString(_T("Get conflict files fail"));
902 CMessageBox::Show(NULL
, IDS_PROGRS_CONFLICTSOCCURED
, IDS_APPNAME
, MB_OK
);
909 static bool IsLocalBranch(CString ref
)
912 g_Git
.GetBranchList(list
, nullptr, CGit::BRANCH_LOCAL
);
913 return std::find(list
.begin(), list
.end(), ref
) != list
.end();
916 int CRebaseDlg::FinishRebase()
918 if (m_bFinishedRebase
)
921 m_bFinishedRebase
= true;
922 if(this->m_IsCherryPick
) //cherry pick mode no "branch", working at upstream branch
924 m_sStatusText
.LoadString(IDS_DONE
);
925 m_CtrlStatusText
.SetWindowText(m_sStatusText
);
926 m_bStatusWarning
= false;
927 m_CtrlStatusText
.Invalidate();
932 if (g_Git
.GetHash(head
, _T("HEAD")))
934 MessageBox(g_Git
.GetGitLastErr(_T("Could not get HEAD hash.")), _T("TortoiseGit"), MB_ICONERROR
);
939 if (IsLocalBranch(m_BranchCtrl
.GetString()))
941 cmd
.Format(_T("git.exe checkout -f -B %s %s --"), m_BranchCtrl
.GetString(), head
.ToString());
946 if (g_Git
.Run(cmd
, &out
, CP_UTF8
))
949 if (CMessageBox::Show(m_hWnd
, out
+ _T("\nRetry?"), _T("TortoiseGit"), MB_YESNO
| MB_ICONERROR
) != IDYES
)
958 cmd
.Format(_T("git.exe reset --hard %s --"), head
.ToString());
963 if (g_Git
.Run(cmd
, &out
, CP_UTF8
))
966 if (CMessageBox::Show(m_hWnd
, out
+ _T("\nRetry?"), _T("TortoiseGit"), MB_YESNO
| MB_ICONERROR
) != IDYES
)
974 while (m_ctrlTabCtrl
.GetTabsNum() > 1)
975 m_ctrlTabCtrl
.RemoveTab(0);
976 m_CtrlStatusText
.SetWindowText(CString(MAKEINTRESOURCE(IDS_PROC_REBASEFINISHED
)));
977 m_sStatusText
= CString(MAKEINTRESOURCE(IDS_PROC_REBASEFINISHED
));
978 m_bStatusWarning
= false;
979 m_CtrlStatusText
.Invalidate();
983 void CRebaseDlg::OnBnClickedContinue()
985 if( m_RebaseStage
== REBASE_DONE
)
992 if (m_RebaseStage
== CHOOSE_BRANCH
|| m_RebaseStage
== CHOOSE_COMMIT_PICK_MODE
)
994 if (CheckRebaseCondition())
998 if( this->m_IsFastForward
)
1001 if (g_Git
.GetHash(m_OrigBranchHash
, m_BranchCtrl
.GetString()))
1003 MessageBox(g_Git
.GetGitLastErr(_T("Could not get hash of \"") + m_BranchCtrl
.GetString() + _T("\".")), _T("TortoiseGit"), MB_ICONERROR
);
1006 if (g_Git
.GetHash(m_OrigUpstreamHash
, m_UpstreamCtrl
.GetString()))
1008 MessageBox(g_Git
.GetGitLastErr(_T("Could not get hash of \"") + m_UpstreamCtrl
.GetString() + _T("\".")), _T("TortoiseGit"), MB_ICONERROR
);
1012 if(!g_Git
.IsFastForward(this->m_BranchCtrl
.GetString(),this->m_UpstreamCtrl
.GetString()))
1014 this->m_ctrlTabCtrl
.SetActiveTab(REBASE_TAB_LOG
);
1015 AddLogString(_T("No fast forward possible.\r\nMaybe repository changed"));
1019 if (IsLocalBranch(m_BranchCtrl
.GetString()))
1021 cmd
.Format(_T("git.exe checkout --no-track -f -B %s %s --"), m_BranchCtrl
.GetString(), m_UpstreamCtrl
.GetString());
1026 if (g_Git
.Run(cmd
, &out
, CP_UTF8
))
1028 this->m_ctrlTabCtrl
.SetActiveTab(REBASE_TAB_LOG
);
1030 if (CMessageBox::Show(m_hWnd
, out
+ _T("\nRetry?"), _T("TortoiseGit"), MB_YESNO
| MB_ICONERROR
) != IDYES
)
1039 cmd
.Format(_T("git.exe reset --hard %s --"), g_Git
.FixBranchName(this->m_UpstreamCtrl
.GetString()));
1041 log
.Format(IDS_PROC_REBASE_FFTO
, m_UpstreamCtrl
.GetString());
1042 this->AddLogString(log
);
1045 this->m_ctrlTabCtrl
.SetActiveTab(REBASE_TAB_LOG
);
1049 if (g_Git
.Run(cmd
, &out
, CP_UTF8
))
1051 AddLogString(CString(MAKEINTRESOURCE(IDS_FAIL
)));
1053 if (CMessageBox::Show(m_hWnd
, out
+ _T("\nRetry?"), _T("TortoiseGit"), MB_YESNO
| MB_ICONERROR
) != IDYES
)
1060 AddLogString(CString(MAKEINTRESOURCE(IDS_DONE
)));
1061 m_RebaseStage
= REBASE_DONE
;
1062 UpdateCurrentStatus();
1066 if( m_RebaseStage
== CHOOSE_BRANCH
|| m_RebaseStage
== CHOOSE_COMMIT_PICK_MODE
)
1068 if(CheckRebaseCondition())
1070 m_RebaseStage
= REBASE_START
;
1071 m_FileListCtrl
.Clear();
1072 m_FileListCtrl
.SetHasCheckboxes(false);
1073 m_FileListCtrl
.m_CurrentVersion
= L
"";
1074 m_ctrlTabCtrl
.SetTabLabel(REBASE_TAB_CONFLICT
, CString(MAKEINTRESOURCE(IDS_PROC_CONFLICTFILES
)));
1075 m_ctrlTabCtrl
.AddTab(&m_wndOutputRebase
, CString(MAKEINTRESOURCE(IDS_LOG
)), 2);
1078 if( m_RebaseStage
== REBASE_FINISH
)
1086 if( m_RebaseStage
== REBASE_SQUASH_CONFLICT
)
1088 if(VerifyNoConflict())
1090 GitRev
*curRev
=(GitRev
*)m_CommitList
.m_arShownList
[m_CurrentRebaseIndex
];
1091 if(this->CheckNextCommitIsSquash())
1092 {//next commit is not squash;
1093 m_RebaseStage
= REBASE_SQUASH_EDIT
;
1094 this->OnRebaseUpdateUI(0,0);
1095 this->UpdateCurrentStatus();
1099 m_RebaseStage
=REBASE_CONTINUE
;
1100 curRev
->GetRebaseAction() |= CGitLogListBase::LOGACTIONS_REBASE_DONE
;
1101 this->UpdateCurrentStatus();
1105 if( m_RebaseStage
== REBASE_CONFLICT
)
1107 if(VerifyNoConflict())
1110 GitRev
*curRev
=(GitRev
*)m_CommitList
.m_arShownList
[m_CurrentRebaseIndex
];
1111 // ***************************************************
1112 // ATTENTION: Similar code in CommitDlg.cpp!!!
1113 // ***************************************************
1114 CMassiveGitTask
mgtReAddAfterCommit(_T("add --ignore-errors -f"));
1115 CMassiveGitTask
mgtAdd(_T("add -f"));
1116 CMassiveGitTask
mgtUpdateIndexForceRemove(_T("update-index --force-remove"));
1117 CMassiveGitTask
mgtUpdateIndex(_T("update-index"));
1118 CMassiveGitTask
mgtRm(_T("rm --ignore-unmatch"));
1119 CMassiveGitTask
mgtRmFCache(_T("rm -f --cache"));
1120 CMassiveGitTask
mgtReset(_T("reset"), TRUE
, true);
1121 for (int i
= 0; i
< m_FileListCtrl
.GetItemCount(); i
++)
1123 CTGitPath
*entry
= (CTGitPath
*)m_FileListCtrl
.GetItemData(i
);
1124 if (entry
->m_Checked
)
1126 if (entry
->m_Action
& CTGitPath::LOGACTIONS_UNVER
)
1127 mgtAdd
.AddFile(entry
->GetGitPathString());
1128 else if (entry
->m_Action
& CTGitPath::LOGACTIONS_DELETED
)
1129 mgtUpdateIndexForceRemove
.AddFile(entry
->GetGitPathString());
1131 mgtUpdateIndex
.AddFile(entry
->GetGitPathString());
1133 if (entry
->m_Action
& CTGitPath::LOGACTIONS_REPLACED
)
1134 mgtRm
.AddFile(entry
->GetGitOldPathString());
1138 if (entry
->m_Action
& CTGitPath::LOGACTIONS_ADDED
|| entry
->m_Action
& CTGitPath::LOGACTIONS_REPLACED
)
1140 mgtRmFCache
.AddFile(entry
->GetGitPathString());
1141 mgtReAddAfterCommit
.AddFile(*entry
);
1143 if (entry
->m_Action
& CTGitPath::LOGACTIONS_REPLACED
&& !entry
->GetGitOldPathString().IsEmpty())
1144 mgtReset
.AddFile(entry
->GetGitOldPathString());
1146 else if(!(entry
->m_Action
& CTGitPath::LOGACTIONS_UNVER
))
1147 mgtReset
.AddFile(entry
->GetGitPathString());
1151 BOOL cancel
= FALSE
;
1152 bool successful
= true;
1153 successful
= successful
&& mgtAdd
.Execute(cancel
);
1154 successful
= successful
&& mgtUpdateIndexForceRemove
.Execute(cancel
);
1155 successful
= successful
&& mgtUpdateIndex
.Execute(cancel
);
1156 successful
= successful
&& mgtRm
.Execute(cancel
);
1157 successful
= successful
&& mgtRmFCache
.Execute(cancel
);
1158 successful
= successful
&& mgtReset
.Execute(cancel
);
1162 AddLogString(_T("An error occurred while updating the index."));
1166 CString out
=_T("");
1168 cmd
.Format(_T("git.exe commit -C %s"), curRev
->m_CommitHash
.ToString());
1172 if(g_Git
.Run(cmd
,&out
,CP_UTF8
))
1175 if(!g_Git
.CheckCleanWorkTree())
1177 CMessageBox::Show(NULL
,out
,_T("TortoiseGit"),MB_OK
|MB_ICONERROR
);
1184 // update commit message if needed
1185 CString str
= m_LogMessageCtrl
.GetText().Trim();
1186 if (str
!= (curRev
->GetSubject() + _T("\n") + curRev
->GetBody()).Trim())
1188 if (str
.Trim().IsEmpty())
1190 CMessageBox::Show(NULL
, IDS_PROC_COMMITMESSAGE_EMPTY
,IDS_APPNAME
, MB_OK
| MB_ICONERROR
);
1193 CString tempfile
= ::GetTempFile();
1194 if (CAppUtils::SaveCommitUnicodeFile(tempfile
, str
))
1196 CMessageBox::Show(nullptr, _T("Could not save commit message"), _T("TortoiseGit"), MB_OK
| MB_ICONERROR
);
1201 cmd
.Format(_T("git.exe commit --amend -F \"%s\""), tempfile
);
1204 if (g_Git
.Run(cmd
, &out
, CP_UTF8
))
1207 if (!g_Git
.CheckCleanWorkTree())
1209 CMessageBox::Show(NULL
, out
, _T("TortoiseGit"), MB_OK
| MB_ICONERROR
);
1217 if (((DWORD
)CRegStdDWORD(_T("Software\\TortoiseGit\\ReaddUnselectedAddedFilesAfterCommit"), TRUE
)) == TRUE
)
1219 BOOL cancel
= FALSE
;
1220 mgtReAddAfterCommit
.Execute(cancel
);
1223 this->m_ctrlTabCtrl
.SetActiveTab(REBASE_TAB_LOG
);
1224 if (curRev
->GetRebaseAction() & CGitLogListBase::LOGACTIONS_REBASE_EDIT
)
1226 m_RebaseStage
=REBASE_EDIT
;
1227 this->m_ctrlTabCtrl
.SetActiveTab(REBASE_TAB_MESSAGE
);
1228 this->UpdateCurrentStatus();
1233 m_RebaseStage
=REBASE_CONTINUE
;
1234 curRev
->GetRebaseAction() |= CGitLogListBase::LOGACTIONS_REBASE_DONE
;
1235 this->UpdateCurrentStatus();
1237 if (CheckNextCommitIsSquash() == 0) // remember commit msg after edit if next commit if squash
1238 ResetParentForSquash(str
);
1240 m_SquashMessage
.Empty();
1244 if ((m_RebaseStage
== REBASE_EDIT
|| m_RebaseStage
== REBASE_CONTINUE
|| m_bSplitCommit
) && CheckNextCommitIsSquash() && (m_bSplitCommit
|| !g_Git
.CheckCleanWorkTree(true)))
1246 if (!m_bSplitCommit
&& CMessageBox::Show(nullptr, IDS_PROC_REBASE_CONTINUE_NOTCLEAN
, IDS_APPNAME
, 1, IDI_ERROR
, IDS_MSGBOX_OK
, IDS_ABORTBUTTON
) == 2)
1248 BOOL isFirst
= TRUE
;
1253 dlg
.m_sLogMessage
= m_LogMessageCtrl
.GetText();
1254 dlg
.m_bWholeProject
= true;
1255 dlg
.m_bSelectFilesForCommit
= true;
1256 dlg
.m_bCommitAmend
= isFirst
&& (m_RebaseStage
!= REBASE_SQUASH_EDIT
); // do not amend on squash_edit stage, we need a normal commit there
1258 gpl
.AddPath(CTGitPath(g_Git
.m_CurrentDir
));
1259 dlg
.m_pathList
= gpl
;
1260 dlg
.m_bAmendDiffToLastCommit
= !m_bSplitCommit
;
1261 dlg
.m_bNoPostActions
= true;
1262 if (dlg
.m_bCommitAmend
)
1263 dlg
.m_AmendStr
= dlg
.m_sLogMessage
;
1264 dlg
.m_bWarnDetachedHead
= false;
1266 if (dlg
.DoModal() != IDOK
)
1269 isFirst
= !m_bSplitCommit
; // only select amend on second+ runs if not in split commit mode
1271 m_SquashMessage
.Empty();
1272 } while (!g_Git
.CheckCleanWorkTree() || (m_bSplitCommit
&& MessageBox(_T("Add another commit?"), _T("TortoiseGit"), MB_YESNO
| MB_ICONQUESTION
) == IDYES
));
1274 m_bSplitCommit
= FALSE
;
1277 this->m_ctrlTabCtrl
.SetActiveTab(REBASE_TAB_LOG
);
1278 m_RebaseStage
= REBASE_CONTINUE
;
1279 GitRev
* curRev
= (GitRev
*)m_CommitList
.m_arShownList
[m_CurrentRebaseIndex
];
1280 curRev
->GetRebaseAction() |= CGitLogListBase::LOGACTIONS_REBASE_DONE
;
1281 this->UpdateCurrentStatus();
1284 if( m_RebaseStage
== REBASE_EDIT
|| m_RebaseStage
== REBASE_SQUASH_EDIT
)
1287 GitRev
*curRev
=(GitRev
*)m_CommitList
.m_arShownList
[m_CurrentRebaseIndex
];
1289 str
=this->m_LogMessageCtrl
.GetText();
1290 if(str
.Trim().IsEmpty())
1292 CMessageBox::Show(NULL
, IDS_PROC_COMMITMESSAGE_EMPTY
,IDS_APPNAME
, MB_OK
| MB_ICONERROR
);
1296 CString tempfile
=::GetTempFile();
1297 if (CAppUtils::SaveCommitUnicodeFile(tempfile
, str
))
1299 CMessageBox::Show(nullptr, _T("Could not save commit message"), _T("TortoiseGit"), MB_OK
| MB_ICONERROR
);
1305 if( m_RebaseStage
== REBASE_SQUASH_EDIT
)
1306 cmd
.Format(_T("git.exe commit %s-F \"%s\""), m_SquashFirstMetaData
, tempfile
);
1310 int isEmpty
= IsCommitEmpty(curRev
->m_CommitHash
);
1312 options
= _T("--allow-empty ");
1313 else if (isEmpty
< 0)
1315 cmd
.Format(_T("git.exe commit --amend %s-F \"%s\""), options
, tempfile
);
1318 if(g_Git
.Run(cmd
,&out
,CP_UTF8
))
1320 if(!g_Git
.CheckCleanWorkTree())
1322 CMessageBox::Show(NULL
,out
,_T("TortoiseGit"),MB_OK
|MB_ICONERROR
);
1327 ::DeleteFile(tempfile
);
1329 if (CheckNextCommitIsSquash() == 0 && m_RebaseStage
!= REBASE_SQUASH_EDIT
) // remember commit msg after edit if next commit if squash; but don't do this if ...->squash(reset here)->pick->squash
1331 ResetParentForSquash(str
);
1334 m_SquashMessage
.Empty();
1335 this->m_ctrlTabCtrl
.SetActiveTab(REBASE_TAB_LOG
);
1336 m_RebaseStage
=REBASE_CONTINUE
;
1337 curRev
->GetRebaseAction() |= CGitLogListBase::LOGACTIONS_REBASE_DONE
;
1338 this->UpdateCurrentStatus();
1342 InterlockedExchange(&m_bThreadRunning
, TRUE
);
1345 if (AfxBeginThread(RebaseThreadEntry
, this)==NULL
)
1347 InterlockedExchange(&m_bThreadRunning
, FALSE
);
1348 CMessageBox::Show(NULL
, _T("Create Rebase Thread Fail"), _T("TortoiseGit"), MB_OK
| MB_ICONERROR
);
1352 void CRebaseDlg::ResetParentForSquash(const CString
& commitMessage
)
1354 m_SquashMessage
= commitMessage
;
1355 // reset parent so that we can do "git cherry-pick --no-commit" w/o introducing an unwanted commit
1356 CString cmd
= _T("git.exe reset --soft HEAD~1");
1357 m_ctrlTabCtrl
.SetActiveTab(REBASE_TAB_LOG
);
1361 if (g_Git
.Run(cmd
, &out
, CP_UTF8
))
1364 AddLogString(CString(MAKEINTRESOURCE(IDS_FAIL
)));
1366 if (CMessageBox::Show(m_hWnd
, out
+ _T("\nRetry?"), _T("TortoiseGit"), MB_YESNO
| MB_ICONERROR
) != IDYES
)
1373 int CRebaseDlg::CheckNextCommitIsSquash()
1376 if(m_CommitList
.m_IsOldFirst
)
1377 index
=m_CurrentRebaseIndex
+1;
1379 index
=m_CurrentRebaseIndex
-1;
1386 if(index
>= m_CommitList
.GetItemCount())
1389 curRev
=(GitRev
*)m_CommitList
.m_arShownList
[index
];
1391 if (curRev
->GetRebaseAction() & CGitLogListBase::LOGACTIONS_REBASE_SQUASH
)
1393 if (curRev
->GetRebaseAction() & CGitLogListBase::LOGACTIONS_REBASE_SKIP
)
1395 if(m_CommitList
.m_IsOldFirst
)
1403 } while(curRev
->GetRebaseAction() & CGitLogListBase::LOGACTIONS_REBASE_SKIP
);
1408 int CRebaseDlg::GoNext()
1410 if(m_CommitList
.m_IsOldFirst
)
1411 ++m_CurrentRebaseIndex
;
1413 --m_CurrentRebaseIndex
;
1417 int CRebaseDlg::StateAction()
1419 switch(this->m_RebaseStage
)
1422 case CHOOSE_COMMIT_PICK_MODE
:
1425 m_RebaseStage
= REBASE_START
;
1432 void CRebaseDlg::SetContinueButtonText()
1435 switch(this->m_RebaseStage
)
1438 case CHOOSE_COMMIT_PICK_MODE
:
1439 if(this->m_IsFastForward
)
1440 Text
.LoadString(IDS_PROC_STARTREBASEFFBUTTON
);
1442 Text
.LoadString(IDS_PROC_STARTREBASEBUTTON
);
1447 case REBASE_CONTINUE
:
1448 case REBASE_SQUASH_CONFLICT
:
1449 Text
.LoadString(IDS_CONTINUEBUTTON
);
1452 case REBASE_CONFLICT
:
1453 Text
.LoadString(IDS_COMMITBUTTON
);
1456 Text
.LoadString(IDS_AMENDBUTTON
);
1459 case REBASE_SQUASH_EDIT
:
1460 Text
.LoadString(IDS_COMMITBUTTON
);
1465 Text
.LoadString(IDS_FINISHBUTTON
);
1469 Text
.LoadString(IDS_DONE
);
1472 this->GetDlgItem(IDC_REBASE_CONTINUE
)->SetWindowText(Text
);
1475 void CRebaseDlg::SetControlEnable()
1477 switch(this->m_RebaseStage
)
1480 case CHOOSE_COMMIT_PICK_MODE
:
1482 this->GetDlgItem(IDC_SPLITALLOPTIONS
)->EnableWindow(TRUE
);
1483 this->GetDlgItem(IDC_BUTTON_UP2
)->EnableWindow(TRUE
);
1484 this->GetDlgItem(IDC_BUTTON_DOWN2
)->EnableWindow(TRUE
);
1488 this->GetDlgItem(IDC_REBASE_COMBOXEX_BRANCH
)->EnableWindow(TRUE
);
1489 this->GetDlgItem(IDC_REBASE_COMBOXEX_UPSTREAM
)->EnableWindow(TRUE
);
1490 this->GetDlgItem(IDC_BUTTON_REVERSE
)->EnableWindow(TRUE
);
1491 this->GetDlgItem(IDC_REBASE_CHECK_FORCE
)->EnableWindow(TRUE
);
1493 this->m_CommitList
.m_ContextMenuMask
|= m_CommitList
.GetContextMenuBit(CGitLogListBase::ID_REBASE_PICK
)|
1494 m_CommitList
.GetContextMenuBit(CGitLogListBase::ID_REBASE_SQUASH
)|
1495 m_CommitList
.GetContextMenuBit(CGitLogListBase::ID_REBASE_EDIT
)|
1496 m_CommitList
.GetContextMenuBit(CGitLogListBase::ID_REBASE_SKIP
);
1500 case REBASE_CONTINUE
:
1504 case REBASE_CONFLICT
:
1506 case REBASE_SQUASH_CONFLICT
:
1508 this->GetDlgItem(IDC_SPLITALLOPTIONS
)->EnableWindow(FALSE
);
1509 this->GetDlgItem(IDC_REBASE_COMBOXEX_BRANCH
)->EnableWindow(FALSE
);
1510 this->GetDlgItem(IDC_REBASE_COMBOXEX_UPSTREAM
)->EnableWindow(FALSE
);
1511 this->GetDlgItem(IDC_BUTTON_REVERSE
)->EnableWindow(FALSE
);
1512 this->GetDlgItem(IDC_REBASE_CHECK_FORCE
)->EnableWindow(FALSE
);
1513 this->GetDlgItem(IDC_BUTTON_UP2
)->EnableWindow(FALSE
);
1514 this->GetDlgItem(IDC_BUTTON_DOWN2
)->EnableWindow(FALSE
);
1516 if( m_RebaseStage
== REBASE_DONE
&& (this->m_PostButtonTexts
.GetCount() != 0) )
1518 this->GetDlgItem(IDC_STATUS_STATIC
)->ShowWindow(SW_HIDE
);
1519 this->GetDlgItem(IDC_REBASE_POST_BUTTON
)->ShowWindow(SW_SHOWNORMAL
);
1520 this->m_PostButton
.RemoveAll();
1521 this->m_PostButton
.AddEntries(m_PostButtonTexts
);
1522 //this->GetDlgItem(IDC_REBASE_POST_BUTTON)->SetWindowText(this->m_PostButtonText);
1527 GetDlgItem(IDC_REBASE_SPLIT_COMMIT
)->ShowWindow((m_RebaseStage
== REBASE_EDIT
|| m_RebaseStage
== REBASE_SQUASH_EDIT
) ? SW_SHOW
: SW_HIDE
);
1529 if(m_bThreadRunning
)
1531 this->GetDlgItem(IDC_REBASE_CONTINUE
)->EnableWindow(FALSE
);
1534 else if (m_RebaseStage
!= REBASE_ERROR
)
1536 this->GetDlgItem(IDC_REBASE_CONTINUE
)->EnableWindow(TRUE
);
1540 void CRebaseDlg::UpdateProgress()
1545 if(m_CommitList
.m_IsOldFirst
)
1546 index
= m_CurrentRebaseIndex
+1;
1548 index
= m_CommitList
.GetItemCount()-m_CurrentRebaseIndex
;
1550 int finishedCommits
= index
- 1; // introduced an variable which shows the number handled revisions for the progress bars
1551 if (m_RebaseStage
== REBASE_FINISH
|| finishedCommits
== -1)
1552 finishedCommits
= index
;
1554 m_ProgressBar
.SetRange32(0, m_CommitList
.GetItemCount());
1555 m_ProgressBar
.SetPos(finishedCommits
);
1558 m_pTaskbarList
->SetProgressState(m_hWnd
, TBPF_NORMAL
);
1559 m_pTaskbarList
->SetProgressValue(m_hWnd
, finishedCommits
, m_CommitList
.GetItemCount());
1562 if(m_CurrentRebaseIndex
>=0 && m_CurrentRebaseIndex
< m_CommitList
.GetItemCount())
1565 text
.Format(IDS_PROC_REBASING_PROGRESS
, index
, m_CommitList
.GetItemCount());
1566 m_sStatusText
= text
;
1567 m_CtrlStatusText
.SetWindowText(text
);
1568 m_bStatusWarning
= false;
1569 m_CtrlStatusText
.Invalidate();
1572 GitRev
*prevRev
=NULL
, *curRev
=NULL
;
1574 if( m_CurrentRebaseIndex
>= 0 && m_CurrentRebaseIndex
< m_CommitList
.m_arShownList
.GetSize())
1576 curRev
=(GitRev
*)m_CommitList
.m_arShownList
[m_CurrentRebaseIndex
];
1579 for (int i
= 0; i
< m_CommitList
.m_arShownList
.GetSize(); ++i
)
1581 prevRev
=(GitRev
*)m_CommitList
.m_arShownList
[i
];
1582 if (prevRev
->GetRebaseAction() & CGitLogListBase::LOGACTIONS_REBASE_CURRENT
)
1584 prevRev
->GetRebaseAction() &= ~CGitLogListBase::LOGACTIONS_REBASE_CURRENT
;
1585 m_CommitList
.GetItemRect(i
,&rect
,LVIR_BOUNDS
);
1586 m_CommitList
.InvalidateRect(rect
);
1592 curRev
->GetRebaseAction() |= CGitLogListBase::LOGACTIONS_REBASE_CURRENT
;
1593 m_CommitList
.GetItemRect(m_CurrentRebaseIndex
,&rect
,LVIR_BOUNDS
);
1594 m_CommitList
.InvalidateRect(rect
);
1596 m_CommitList
.EnsureVisible(m_CurrentRebaseIndex
,FALSE
);
1599 void CRebaseDlg::UpdateCurrentStatus()
1601 SetContinueButtonText();
1604 if (m_RebaseStage
== REBASE_DONE
)
1605 GetDlgItem(IDC_REBASE_CONTINUE
)->SetFocus();
1608 void CRebaseDlg::AddLogString(CString str
)
1610 this->m_wndOutputRebase
.SendMessage(SCI_SETREADONLY
, FALSE
);
1611 CStringA sTextA
= m_wndOutputRebase
.StringForControl(str
);//CUnicodeUtils::GetUTF8(str);
1612 this->m_wndOutputRebase
.SendMessage(SCI_DOCUMENTEND
);
1613 this->m_wndOutputRebase
.SendMessage(SCI_REPLACESEL
, 0, (LPARAM
)(LPCSTR
)sTextA
);
1614 this->m_wndOutputRebase
.SendMessage(SCI_REPLACESEL
, 0, (LPARAM
)(LPCSTR
)"\n");
1615 this->m_wndOutputRebase
.SendMessage(SCI_SETREADONLY
, TRUE
);
1618 int CRebaseDlg::GetCurrentCommitID()
1620 if(m_CommitList
.m_IsOldFirst
)
1622 return this->m_CurrentRebaseIndex
+1;
1627 return m_CommitList
.GetItemCount()-m_CurrentRebaseIndex
;
1631 int CRebaseDlg::IsCommitEmpty(const CGitHash
& hash
)
1633 CString cmd
, tree
, ptree
;
1634 cmd
.Format(_T("git.exe rev-parse -q --verify %s^{tree}"), hash
.ToString());
1635 if (g_Git
.Run(cmd
, &tree
, CP_UTF8
))
1641 cmd
.Format(_T("git.exe rev-parse -q --verify %s^^{tree}"), hash
.ToString());
1642 if (g_Git
.Run(cmd
, &ptree
, CP_UTF8
))
1643 ptree
= _T("4b825dc642cb6eb9a060e54bf8d69288fbee4904"); // empty tree
1644 return tree
== ptree
;
1647 int CRebaseDlg::DoRebase()
1650 if(m_CurrentRebaseIndex
<0)
1652 if(m_CurrentRebaseIndex
>= m_CommitList
.GetItemCount() )
1655 GitRev
*pRev
= (GitRev
*)m_CommitList
.m_arShownList
[m_CurrentRebaseIndex
];
1656 int mode
= pRev
->GetRebaseAction() & CGitLogListBase::LOGACTIONS_REBASE_MODE_MASK
;
1659 if (mode
== CGitLogListBase::LOGACTIONS_REBASE_SKIP
)
1661 pRev
->GetRebaseAction() |= CGitLogListBase::LOGACTIONS_REBASE_DONE
;
1665 bool nextCommitIsSquash
= (CheckNextCommitIsSquash() == 0);
1666 if (nextCommitIsSquash
|| mode
!= CGitLogListBase::LOGACTIONS_REBASE_PICK
)
1667 { // next commit is squash or not pick
1668 if (!this->m_SquashMessage
.IsEmpty())
1669 this->m_SquashMessage
+= _T("\n\n");
1670 this->m_SquashMessage
+= pRev
->GetSubject();
1671 this->m_SquashMessage
+= _T("\n");
1672 this->m_SquashMessage
+= pRev
->GetBody().TrimRight();
1673 if (m_bAddCherryPickedFrom
)
1675 if (!pRev
->GetBody().IsEmpty())
1676 m_SquashMessage
+= _T("\n");
1677 m_SquashMessage
+= _T("(cherry picked from commit ");
1678 m_SquashMessage
+= pRev
->m_CommitHash
.ToString();
1679 m_SquashMessage
+= _T(")");
1684 this->m_SquashMessage
.Empty();
1685 m_SquashFirstMetaData
.Empty();
1688 if ((nextCommitIsSquash
&& mode
!= CGitLogListBase::LOGACTIONS_REBASE_EDIT
) || mode
== CGitLogListBase::LOGACTIONS_REBASE_SQUASH
)
1689 { // next or this commit is squash (don't do this on edit->squash sequence)
1690 nocommit
=_T(" --no-commit ");
1693 if (nextCommitIsSquash
&& mode
!= CGitLogListBase::LOGACTIONS_REBASE_SQUASH
)
1694 m_SquashFirstMetaData
.Format(_T("--date=%s --author=\"%s <%s>\" "), pRev
->GetAuthorDate().Format(_T("%Y-%m-%dT%H:%M:%S")), pRev
->GetAuthorName(), pRev
->GetAuthorEmail());
1697 log
.Format(_T("%s %d: %s"), CGitLogListBase::GetRebaseActionName(mode
), GetCurrentCommitID(), pRev
->m_CommitHash
.ToString());
1699 AddLogString(pRev
->GetSubject());
1700 if (pRev
->GetSubject().IsEmpty())
1702 CMessageBox::Show(m_hWnd
, IDS_PROC_REBASE_EMPTYCOMMITMSG
, IDS_APPNAME
, MB_OK
| MB_ICONEXCLAMATION
);
1703 mode
= CGitLogListBase::LOGACTIONS_REBASE_EDIT
;
1706 CString cherryPickedFrom
;
1707 if (m_bAddCherryPickedFrom
)
1708 cherryPickedFrom
= _T("-x ");
1709 else if (!m_IsCherryPick
&& nocommit
.IsEmpty())
1710 cherryPickedFrom
= _T("--ff "); // for issue #1833: "If the current HEAD is the same as the parent of the cherry-pick’ed commit, then a fast forward to this commit will be performed."
1712 int isEmpty
= IsCommitEmpty(pRev
->m_CommitHash
);
1714 cherryPickedFrom
+= _T("--allow-empty ");
1715 else if (isEmpty
< 0)
1720 cmd
.Format(_T("git.exe cherry-pick %s%s %s"), cherryPickedFrom
, nocommit
, pRev
->m_CommitHash
.ToString());
1722 if(g_Git
.Run(cmd
,&out
,CP_UTF8
))
1726 if(g_Git
.ListConflictFile(list
))
1728 AddLogString(_T("Get conflict files fail"));
1733 if (mode
== CGitLogListBase::LOGACTIONS_REBASE_PICK
)
1736 m_pTaskbarList
->SetProgressState(m_hWnd
, TBPF_ERROR
);
1738 if (!m_bAutoSkipFailedCommit
)
1740 choose
= CMessageBox::ShowCheck(m_hWnd
, IDS_CHERRYPICKFAILEDSKIP
, IDS_APPNAME
, 1, IDI_QUESTION
, IDS_SKIPBUTTON
, IDS_MSGBOX_RETRY
, IDS_MSGBOX_CANCEL
, NULL
, IDS_DO_SAME_FOR_REST
, &m_bAutoSkipFailedCommit
);
1743 m_bAutoSkipFailedCommit
= FALSE
;
1744 continue; // retry cherry pick
1747 if (m_bAutoSkipFailedCommit
|| choose
== 1)
1749 bool resetOK
= false;
1753 if (g_Git
.Run(_T("git.exe reset --hard"), &out
, CP_UTF8
))
1756 if (CMessageBox::Show(m_hWnd
, _T("Retry?\nUnrecoverable error on cleanup:\n") + out
, _T("TortoiseGit"), MB_YESNO
| MB_ICONERROR
) != IDYES
)
1765 pRev
->GetRebaseAction() = CGitLogListBase::LOGACTIONS_REBASE_SKIP
;
1766 m_CommitList
.Invalidate();
1771 m_RebaseStage
= REBASE_ERROR
;
1772 AddLogString(_T("An unrecoverable error occurred."));
1775 if (mode
== CGitLogListBase::LOGACTIONS_REBASE_EDIT
)
1777 this->m_RebaseStage
= REBASE_EDIT
;
1778 return -1; // Edit return -1 to stop rebase.
1781 if(CheckNextCommitIsSquash())
1783 // let user edit last commmit message
1784 this->m_RebaseStage
= REBASE_SQUASH_EDIT
;
1790 m_pTaskbarList
->SetProgressState(m_hWnd
, TBPF_ERROR
);
1791 if (mode
== CGitLogListBase::LOGACTIONS_REBASE_SQUASH
)
1792 m_RebaseStage
= REBASE_SQUASH_CONFLICT
;
1794 m_RebaseStage
= REBASE_CONFLICT
;
1801 if (mode
== CGitLogListBase::LOGACTIONS_REBASE_PICK
)
1803 pRev
->GetRebaseAction() |= CGitLogListBase::LOGACTIONS_REBASE_DONE
;
1806 if (mode
== CGitLogListBase::LOGACTIONS_REBASE_EDIT
)
1808 this->m_RebaseStage
= REBASE_EDIT
;
1809 return -1; // Edit return -1 to stop rebase.
1813 if(CheckNextCommitIsSquash())
1815 // let user edit last commmit message
1816 this->m_RebaseStage
= REBASE_SQUASH_EDIT
;
1819 else if (mode
== CGitLogListBase::LOGACTIONS_REBASE_SQUASH
)
1820 pRev
->GetRebaseAction() |= CGitLogListBase::LOGACTIONS_REBASE_DONE
;
1827 BOOL
CRebaseDlg::IsEnd()
1829 if(m_CommitList
.m_IsOldFirst
)
1830 return m_CurrentRebaseIndex
>= this->m_CommitList
.GetItemCount();
1832 return m_CurrentRebaseIndex
<0;
1835 int CRebaseDlg::RebaseThread()
1837 CBlockCacheForPath
cacheBlock(g_Git
.m_CurrentDir
);
1842 if( m_RebaseStage
== REBASE_START
)
1844 if( this->StartRebase() )
1849 m_RebaseStage
= REBASE_CONTINUE
;
1852 else if( m_RebaseStage
== REBASE_CONTINUE
)
1855 SendMessage(MSG_REBASE_UPDATE_UI
);
1859 m_RebaseStage
= REBASE_FINISH
;
1873 else if( m_RebaseStage
== REBASE_FINISH
)
1875 SendMessage(MSG_REBASE_UPDATE_UI
);
1876 m_RebaseStage
= REBASE_DONE
;
1884 this->PostMessage(MSG_REBASE_UPDATE_UI
);
1887 InterlockedExchange(&m_bThreadRunning
, FALSE
);
1888 this->PostMessage(MSG_REBASE_UPDATE_UI
);
1892 void CRebaseDlg::ListConflictFile()
1894 this->m_FileListCtrl
.Clear();
1895 m_FileListCtrl
.SetHasCheckboxes(true);
1900 m_FileListCtrl
.m_bIsRevertTheirMy
= !m_IsCherryPick
;
1902 this->m_FileListCtrl
.GetStatus(&list
,true);
1903 this->m_FileListCtrl
.Show(CTGitPath::LOGACTIONS_UNMERGED
|CTGitPath::LOGACTIONS_MODIFIED
|CTGitPath::LOGACTIONS_ADDED
|CTGitPath::LOGACTIONS_DELETED
,
1904 CTGitPath::LOGACTIONS_UNMERGED
);
1906 m_FileListCtrl
.Check(GITSLC_SHOWFILES
);
1907 bool hasSubmoduleChange
= false;
1908 for (int i
= 0; i
< m_FileListCtrl
.GetItemCount(); i
++)
1910 CTGitPath
*entry
= (CTGitPath
*)m_FileListCtrl
.GetItemData(i
);
1911 if (entry
->IsDirectory())
1913 hasSubmoduleChange
= true;
1918 if (hasSubmoduleChange
)
1920 m_CtrlStatusText
.SetWindowText(m_sStatusText
+ _T(", ") + CString(MAKEINTRESOURCE(IDS_CARE_SUBMODULE_CHANGES
)));
1921 m_bStatusWarning
= true;
1922 m_CtrlStatusText
.Invalidate();
1926 m_CtrlStatusText
.SetWindowText(m_sStatusText
);
1927 m_bStatusWarning
= false;
1928 m_CtrlStatusText
.Invalidate();
1932 LRESULT
CRebaseDlg::OnRebaseUpdateUI(WPARAM
,LPARAM
)
1934 if (m_RebaseStage
== REBASE_FINISH
)
1939 UpdateCurrentStatus();
1940 if (m_RebaseStage
== REBASE_DONE
&& m_pTaskbarList
)
1941 m_pTaskbarList
->SetProgressState(m_hWnd
, TBPF_NOPROGRESS
); // do not show progress on taskbar any more to show we finished
1942 if(m_CurrentRebaseIndex
<0)
1944 if(m_CurrentRebaseIndex
>= m_CommitList
.GetItemCount() )
1946 GitRev
*curRev
=(GitRev
*)m_CommitList
.m_arShownList
[m_CurrentRebaseIndex
];
1948 switch(m_RebaseStage
)
1950 case REBASE_CONFLICT
:
1951 case REBASE_SQUASH_CONFLICT
:
1954 this->m_ctrlTabCtrl
.SetActiveTab(REBASE_TAB_CONFLICT
);
1956 m_pTaskbarList
->SetProgressState(m_hWnd
, TBPF_ERROR
);
1957 this->m_LogMessageCtrl
.Call(SCI_SETREADONLY
, FALSE
);
1959 g_GitAdminDir
.GetAdminDirPath(g_Git
.m_CurrentDir
, dotGitPath
);
1961 bool loadedMsg
= CGit::LoadTextFile(dotGitPath
+ _T("MERGE_MSG"), logMessage
);
1963 logMessage
= curRev
->GetSubject() + _T("\n") + curRev
->GetBody();
1964 this->m_LogMessageCtrl
.SetText(logMessage
);
1968 this->m_ctrlTabCtrl
.SetActiveTab(REBASE_TAB_MESSAGE
);
1970 m_pTaskbarList
->SetProgressState(m_hWnd
, TBPF_PAUSED
);
1971 this->m_LogMessageCtrl
.Call(SCI_SETREADONLY
, FALSE
);
1972 if (m_bAddCherryPickedFrom
)
1974 // Since the new commit is done and the HEAD points to it,
1975 // just using the new body modified by git self.
1976 GitRev headRevision
;
1977 headRevision
.GetCommit(_T("HEAD"));
1978 m_LogMessageCtrl
.SetText(headRevision
.GetSubject() + _T("\n") + headRevision
.GetBody());
1981 m_LogMessageCtrl
.SetText(curRev
->GetSubject() + _T("\n") + curRev
->GetBody());
1983 case REBASE_SQUASH_EDIT
:
1984 this->m_ctrlTabCtrl
.SetActiveTab(REBASE_TAB_MESSAGE
);
1985 this->m_LogMessageCtrl
.Call(SCI_SETREADONLY
, FALSE
);
1986 this->m_LogMessageCtrl
.SetText(this->m_SquashMessage
);
1988 m_pTaskbarList
->SetProgressState(m_hWnd
, TBPF_PAUSED
);
1991 this->m_ctrlTabCtrl
.SetActiveTab(REBASE_TAB_LOG
);
1995 void CRebaseDlg::OnCancel()
1999 void CRebaseDlg::OnBnClickedAbort()
2002 m_pTaskbarList
->SetProgressState(m_hWnd
, TBPF_NOPROGRESS
);
2007 CString pron
= m_OrigUpstreamHash
.ToString();
2008 if(m_OrigUpstreamHash
.IsEmpty())
2010 __super::OnCancel();
2013 if(m_RebaseStage
== CHOOSE_BRANCH
|| m_RebaseStage
== CHOOSE_COMMIT_PICK_MODE
)
2018 if(CMessageBox::Show(NULL
, IDS_PROC_REBASE_ABORT
, IDS_APPNAME
, MB_YESNO
) != IDYES
)
2021 if(this->m_IsFastForward
)
2023 cmd
.Format(_T("git.exe reset --hard %s --"),this->m_OrigBranchHash
.ToString());
2027 if (g_Git
.Run(cmd
, &out
, CP_UTF8
))
2030 if (CMessageBox::Show(m_hWnd
, _T("Retry?\nUnrecoverable error on cleanup:\n") + out
, _T("TortoiseGit"), MB_YESNO
| MB_ICONERROR
) != IDYES
)
2036 __super::OnCancel();
2040 if (m_IsCherryPick
) // there are not "branch" at cherry pick mode
2042 cmd
.Format(_T("git.exe reset --hard %s --"), m_OrigUpstreamHash
.ToString());
2046 if (g_Git
.Run(cmd
, &out
, CP_UTF8
))
2049 if (CMessageBox::Show(m_hWnd
, _T("Retry?\nUnrecoverable error on cleanup:\n") + out
, _T("TortoiseGit"), MB_YESNO
| MB_ICONERROR
) != IDYES
)
2056 __super::OnCancel();
2060 if (m_OrigHEADBranch
== m_BranchCtrl
.GetString())
2062 if (IsLocalBranch(m_OrigHEADBranch
))
2063 cmd
.Format(_T("git.exe checkout -f -B %s %s --"), m_BranchCtrl
.GetString(), m_OrigBranchHash
.ToString());
2065 cmd
.Format(_T("git.exe checkout -f %s --"), m_OrigBranchHash
.ToString());
2066 if (g_Git
.Run(cmd
, &out
, CP_UTF8
))
2069 ::MessageBox(m_hWnd
, _T("Unrecoverable error on cleanup:\n") + out
, _T("TortoiseGit"), MB_ICONERROR
);
2070 __super::OnCancel();
2074 cmd
.Format(_T("git.exe reset --hard %s --"), m_OrigBranchHash
.ToString());
2078 if (g_Git
.Run(cmd
, &out
, CP_UTF8
))
2081 if (CMessageBox::Show(m_hWnd
, _T("Retry?\nUnrecoverable error on cleanup:\n") + out
, _T("TortoiseGit"), MB_YESNO
| MB_ICONERROR
) != IDYES
)
2090 if (m_OrigHEADBranch
!= g_Git
.GetCurrentBranch(true))
2092 if (IsLocalBranch(m_OrigHEADBranch
))
2093 cmd
.Format(_T("git.exe checkout -f -B %s %s --"), m_OrigHEADBranch
, m_OrigHEADHash
.ToString());
2095 cmd
.Format(_T("git.exe checkout -f %s --"), m_OrigHEADHash
.ToString());
2096 if (g_Git
.Run(cmd
, &out
, CP_UTF8
))
2099 ::MessageBox(m_hWnd
, _T("Unrecoverable error on cleanup:\n") + out
, _T("TortoiseGit"), MB_ICONERROR
);
2100 // continue to restore moved branch
2104 cmd
.Format(_T("git.exe reset --hard %s --"), m_OrigHEADHash
.ToString());
2108 if (g_Git
.Run(cmd
, &out
, CP_UTF8
))
2111 if (CMessageBox::Show(m_hWnd
, _T("Retry?\nUnrecoverable error on cleanup:\n") + out
, _T("TortoiseGit"), MB_YESNO
| MB_ICONERROR
) != IDYES
)
2118 // restore moved branch
2119 if (IsLocalBranch(m_BranchCtrl
.GetString()))
2121 cmd
.Format(_T("git.exe branch -f %s %s --"), m_BranchCtrl
.GetString(), m_OrigBranchHash
.ToString());
2122 if (g_Git
.Run(cmd
, &out
, CP_UTF8
))
2125 ::MessageBox(m_hWnd
, _T("Unrecoverable error on cleanup:\n") + out
, _T("TortoiseGit"), MB_ICONERROR
);
2126 __super::OnCancel();
2131 __super::OnCancel();
2133 CheckRestoreStash();
2136 void CRebaseDlg::OnBnClickedButtonReverse()
2138 CString temp
= m_BranchCtrl
.GetString();
2139 m_BranchCtrl
.AddString(m_UpstreamCtrl
.GetString());
2140 m_UpstreamCtrl
.AddString(temp
);
2141 OnCbnSelchangeUpstream();
2144 void CRebaseDlg::OnBnClickedButtonBrowse()
2146 if(CBrowseRefsDlg::PickRefForCombo(&m_UpstreamCtrl
, gPickRef_NoTag
))
2147 OnCbnSelchangeUpstream();
2150 void CRebaseDlg::OnBnClickedRebaseCheckForce()
2153 this->FetchLogList();
2156 void CRebaseDlg::OnBnClickedRebasePostButton()
2158 this->m_Upstream
=this->m_UpstreamCtrl
.GetString();
2159 this->m_Branch
=this->m_BranchCtrl
.GetString();
2161 this->EndDialog((int)(IDC_REBASE_POST_BUTTON
+this->m_PostButton
.GetCurrentEntry()));
2164 LRESULT
CRebaseDlg::OnGitStatusListCtrlNeedsRefresh(WPARAM
, LPARAM
)
2170 void CRebaseDlg::Refresh()
2172 if (m_RebaseStage
== REBASE_CONFLICT
|| m_RebaseStage
== REBASE_SQUASH_CONFLICT
)
2178 if(this->m_IsCherryPick
)
2181 if(this->m_RebaseStage
== CHOOSE_BRANCH
)
2184 this->FetchLogList();
2188 void CRebaseDlg::OnBnClickedButtonUp2()
2191 pos
= m_CommitList
.GetFirstSelectedItemPosition();
2193 // do nothing if the first selected item is the first item in the list
2194 int idx
= m_CommitList
.GetNextSelectedItem(pos
);
2198 bool moveToTop
= !!(GetAsyncKeyState(VK_SHIFT
) & 0x8000);
2199 int move
= moveToTop
? idx
: 1;
2200 pos
= m_CommitList
.GetFirstSelectedItemPosition();
2202 bool changed
= false;
2205 int index
=m_CommitList
.GetNextSelectedItem(pos
);
2208 CGitHash old
= m_CommitList
.m_logEntries
[index
- move
];
2209 m_CommitList
.m_logEntries
[index
- move
] = m_CommitList
.m_logEntries
[index
];
2210 m_CommitList
.m_logEntries
[index
] = old
;
2211 m_CommitList
.RecalculateShownList(&m_CommitList
.m_arShownList
);
2212 m_CommitList
.SetItemState(index
- move
, LVIS_SELECTED
, LVIS_SELECTED
);
2213 m_CommitList
.SetItemState(index
, 0, LVIS_SELECTED
);
2219 pos
= m_CommitList
.GetFirstSelectedItemPosition();
2220 m_CommitList
.EnsureVisible(m_CommitList
.GetNextSelectedItem(pos
), false);
2221 m_CommitList
.Invalidate();
2222 m_CommitList
.SetFocus();
2226 void CRebaseDlg::OnBnClickedButtonDown2()
2228 if (m_CommitList
.GetSelectedCount() == 0)
2231 bool moveToBottom
= !!(GetAsyncKeyState(VK_SHIFT
) & 0x8000);
2233 pos
= m_CommitList
.GetFirstSelectedItemPosition();
2234 bool changed
= false;
2235 // use an array to store all selected item indexes; the user won't select too much items
2236 int* indexes
= NULL
;
2237 indexes
= new int[m_CommitList
.GetSelectedCount()];
2241 indexes
[i
++] = m_CommitList
.GetNextSelectedItem(pos
);
2243 int distanceToBottom
= m_CommitList
.GetItemCount() - 1 - indexes
[m_CommitList
.GetSelectedCount() - 1];
2244 int move
= moveToBottom
? distanceToBottom
: 1;
2245 // don't move any item if the last selected item is the last item in the m_CommitList
2246 // (that would change the order of the selected items)
2247 if (distanceToBottom
> 0)
2249 // iterate over the indexes backwards in order to correctly move multiselected items
2250 for (i
= m_CommitList
.GetSelectedCount() - 1; i
>= 0; i
--)
2252 int index
= indexes
[i
];
2253 CGitHash old
= m_CommitList
.m_logEntries
[index
+ move
];
2254 m_CommitList
.m_logEntries
[index
+ move
] = m_CommitList
.m_logEntries
[index
];
2255 m_CommitList
.m_logEntries
[index
] = old
;
2256 m_CommitList
.RecalculateShownList(&m_CommitList
.m_arShownList
);
2257 m_CommitList
.SetItemState(index
, 0, LVIS_SELECTED
);
2258 m_CommitList
.SetItemState(index
+ move
, LVIS_SELECTED
, LVIS_SELECTED
);
2262 m_CommitList
.EnsureVisible(indexes
[m_CommitList
.GetSelectedCount() - 1] + move
, false);
2267 m_CommitList
.Invalidate();
2268 m_CommitList
.SetFocus();
2272 LRESULT
CRebaseDlg::OnTaskbarBtnCreated(WPARAM
/*wParam*/, LPARAM
/*lParam*/)
2274 m_pTaskbarList
.Release();
2275 m_pTaskbarList
.CoCreateInstance(CLSID_TaskbarList
);
2276 SetUUIDOverlayIcon(m_hWnd
);
2280 void CRebaseDlg::OnLvnItemchangedLoglist(NMHDR
*pNMHDR
, LRESULT
*pResult
)
2282 LPNMLISTVIEW pNMLV
= reinterpret_cast<LPNMLISTVIEW
>(pNMHDR
);
2284 if(m_CommitList
.m_bNoDispUpdates
)
2286 if (pNMLV
->iItem
>= 0)
2288 this->m_CommitList
.m_nSearchIndex
= pNMLV
->iItem
;
2289 if (pNMLV
->iSubItem
!= 0)
2291 if ((pNMLV
->iItem
== m_CommitList
.m_arShownList
.GetCount()))
2293 // remove the selected state
2294 if (pNMLV
->uChanged
& LVIF_STATE
)
2296 m_CommitList
.SetItemState(pNMLV
->iItem
, 0, LVIS_SELECTED
);
2297 FillLogMessageCtrl();
2301 if (pNMLV
->uChanged
& LVIF_STATE
)
2303 FillLogMessageCtrl();
2308 FillLogMessageCtrl();
2312 void CRebaseDlg::FillLogMessageCtrl()
2314 int selCount
= m_CommitList
.GetSelectedCount();
2315 if (selCount
== 1 && (m_RebaseStage
== CHOOSE_BRANCH
|| m_RebaseStage
== CHOOSE_COMMIT_PICK_MODE
))
2317 POSITION pos
= m_CommitList
.GetFirstSelectedItemPosition();
2318 int selIndex
= m_CommitList
.GetNextSelectedItem(pos
);
2319 GitRev
* pLogEntry
= reinterpret_cast<GitRev
*>(m_CommitList
.m_arShownList
.SafeGetAt(selIndex
));
2320 m_FileListCtrl
.UpdateWithGitPathList(pLogEntry
->GetFiles(&m_CommitList
));
2321 m_FileListCtrl
.m_CurrentVersion
= pLogEntry
->m_CommitHash
;
2322 m_FileListCtrl
.Show(GITSLC_SHOWVERSIONED
);
2323 m_LogMessageCtrl
.Call(SCI_SETREADONLY
, FALSE
);
2324 m_LogMessageCtrl
.SetText(pLogEntry
->GetSubject() + _T("\n") + pLogEntry
->GetBody());
2325 m_LogMessageCtrl
.Call(SCI_SETREADONLY
, TRUE
);
2328 void CRebaseDlg::OnBnClickedCheckCherryPickedFrom()
2333 LRESULT
CRebaseDlg::OnRebaseActionMessage(WPARAM
, LPARAM
)
2335 if (m_RebaseStage
== REBASE_ERROR
|| m_RebaseStage
== REBASE_CONFLICT
)
2337 GitRev
*pRev
= (GitRev
*)m_CommitList
.m_arShownList
[m_CurrentRebaseIndex
];
2338 int mode
= pRev
->GetRebaseAction() & CGitLogListBase::LOGACTIONS_REBASE_MODE_MASK
;
2339 if (mode
== CGitLogListBase::LOGACTIONS_REBASE_SKIP
)
2342 bool resetOK
= false;
2346 if (g_Git
.Run(_T("git.exe reset --hard"), &out
, CP_UTF8
))
2349 if (CMessageBox::Show(m_hWnd
, _T("Retry?\nUnrecoverable error on cleanup:\n") + out
, _T("TortoiseGit"), MB_YESNO
| MB_ICONERROR
) != IDYES
)
2358 m_FileListCtrl
.Clear();
2359 m_RebaseStage
= REBASE_CONTINUE
;
2360 UpdateCurrentStatus();
2368 void CRebaseDlg::OnBnClickedSplitAllOptions()
2370 switch (m_SplitAllOptions
.GetCurrentEntry())
2373 SetAllRebaseAction(CGitLogListBase::LOGACTIONS_REBASE_PICK
);
2376 SetAllRebaseAction(CGitLogListBase::LOGACTIONS_REBASE_SQUASH
);
2379 SetAllRebaseAction(CGitLogListBase::LOGACTIONS_REBASE_EDIT
);
2386 void CRebaseDlg::OnBnClickedRebaseSplitCommit()