headhash=g_Git.GetHash(CString(_T("HEAD")));\r
headhash=headhash.Left(40); \r
\r
+ GitRev* pFirstEntry = reinterpret_cast<GitRev*>(m_arShownList.GetAt(FirstSelect));\r
GitRev* pLastEntry = reinterpret_cast<GitRev*>(m_arShownList.GetAt(LastSelect));\r
- if(pLastEntry->m_CommitHash != hash)\r
- {\r
- CMessageBox::Show(NULL,_T("Only combine top continuous commit"),_T("TortoiseGit"),MB_OK);\r
- }\r
+// if(pLastEntry->m_CommitHash != hash)\r
+// {\r
+// CMessageBox::Show(NULL,_T("Only combine top continuous commit"),_T("TortoiseGit"),MB_OK);\r
+// }\r
if(!g_Git.CheckCleanWorkTree())\r
{\r
- CMessageBox::Show(NULL,_T("Combine need clean work tree"),_T("TortoiseGit"),MB_OK);\r
+ CMessageBox::Show(NULL,_T("Combine needs a clean work tree"),_T("TortoiseGit"),MB_OK);\r
break;\r
}\r
CString cmd,out;\r
\r
- cmd.Format(_T("git.exe reset --mixed %s"),hash);\r
- if(g_Git.Run(cmd,&out,CP_UTF8))\r
- {\r
- CMessageBox::Show(NULL,out,_T("TortoiseGit"),MB_OK);\r
- }\r
- CCommitDlg dlg;\r
- for(int i=FirstSelect;i<=LastSelect;i++)\r
+ //Use throw to abort this process (reset back to original HEAD)\r
+ try\r
{\r
- GitRev* pRev = reinterpret_cast<GitRev*>(m_arShownList.GetAt(i));\r
- dlg.m_sLogMessage+=pRev->m_Subject+_T("\n")+pRev->m_Body;\r
- dlg.m_sLogMessage+=_T("\n");\r
- }\r
- dlg.m_bWholeProject=true;\r
- dlg.m_bSelectFilesForCommit = true;\r
- dlg.m_bCommitAmend=true;\r
- dlg.m_AmendStr=dlg.m_sLogMessage;\r
+ cmd.Format(_T("git.exe reset --hard %s"),pFirstEntry->m_CommitHash);\r
+ if(g_Git.Run(cmd,&out,CP_UTF8))\r
+ {\r
+ CMessageBox::Show(NULL,out,_T("TortoiseGit"),MB_OK);\r
+ throw std::exception(CUnicodeUtils::GetUTF8(_T("Could not reset to first commit (first step) aborting...\r\n\r\n")+out));\r
+ }\r
+ cmd.Format(_T("git.exe reset --mixed %s"),hash);\r
+ if(g_Git.Run(cmd,&out,CP_UTF8))\r
+ {\r
+ CMessageBox::Show(NULL,out,_T("TortoiseGit"),MB_OK);\r
+ throw std::exception(CUnicodeUtils::GetUTF8(_T("Could not reset to last commit (second step) aborting...\r\n\r\n")+out));\r
+ }\r
+ CCommitDlg dlg;\r
+ for(int i=FirstSelect;i<=LastSelect;i++)\r
+ {\r
+ GitRev* pRev = reinterpret_cast<GitRev*>(m_arShownList.GetAt(i));\r
+ dlg.m_sLogMessage+=pRev->m_Subject+_T("\n")+pRev->m_Body;\r
+ dlg.m_sLogMessage+=_T("\n");\r
+ }\r
+ dlg.m_bWholeProject=true;\r
+ dlg.m_bSelectFilesForCommit = true;\r
+ dlg.m_bCommitAmend=true;\r
+ dlg.m_AmendStr=dlg.m_sLogMessage;\r
\r
- if (dlg.DoModal() == IDOK)\r
- {\r
- \r
- }else\r
+ bool abort=false;\r
+ if (dlg.DoModal() == IDOK)\r
+ {\r
+ if(pFirstEntry->m_CommitHash!=headhash)\r
+ {\r
+ //Commitrange firstEntry..headhash (from top of combine to original head) needs to be 'cherry-picked'\r
+ //on top of new commit.\r
+ //Use the rebase --onto command for it.\r
+ //\r
+ //All this can be done in one step using the following command:\r
+ //cmd.Format(_T("git.exe format-patch --stdout --binary --full-index -k %s..%s | git am -k -3"),\r
+ // pFirstEntry->m_CommitHash,\r
+ // headhash);\r
+ //But I am not sure if a '|' is going to work in a CreateProcess() call.\r
+ //\r
+ //Later the progress dialog could be used to execute these steps.\r
+\r
+ CString currentBranch=g_Git.GetCurrentBranch();\r
+ cmd.Format(_T("git.exe rebase --onto \"%s\" %s %s"),\r
+ currentBranch,\r
+ pFirstEntry->m_CommitHash,\r
+ headhash);\r
+ if(g_Git.Run(cmd,&out,CP_UTF8)!=0)\r
+ {\r
+ CString msg;\r
+ msg.Format(_T("Error while rebasing commits on top of combined commits. Aborting.\r\n\r\n%s"),out);\r
+// CMessageBox::Show(NULL,msg,_T("TortoiseGit"),MB_OK);\r
+ g_Git.Run(_T("git.exe rebase --abort"),&out,CP_UTF8);\r
+ throw std::exception(CUnicodeUtils::GetUTF8(msg));\r
+ }\r
+\r
+ //HEAD is now on <no branch>. \r
+ //The following steps are to get HEAD back on the original branch and reset the branch to the new HEAD\r
+ //To avoid 2 working copy changes, we could use git branch -f <original branch> <hash new head> \r
+ //And then git checkout <original branch>\r
+ //But I don't know if 'git branch -f' removes tracking options. So for now, do a checkout and a reset.\r
+ \r
+ //Store new HEAD\r
+ CString newHead=g_Git.GetHash(CString(_T("HEAD")));\r
+\r
+ //Checkout working branch\r
+ cmd.Format(_T("git.exe checkout -f \"%s\""),currentBranch);\r
+ if(g_Git.Run(cmd,&out,CP_UTF8))\r
+ throw std::exception(CUnicodeUtils::GetUTF8(_T("Could not checkout original branch. Aborting...\r\n\r\n")+out));\r
+\r
+ //Reset to new HEAD\r
+ cmd.Format(_T("git.exe reset --hard %s"),newHead);\r
+ if(g_Git.Run(cmd,&out,CP_UTF8))\r
+ throw std::exception(CUnicodeUtils::GetUTF8(_T("Could not reset to new head. Aborting...\r\n\r\n")+out));\r
+ }\r
+ }\r
+ else\r
+ throw std::exception("User aborted the combine process");\r
+ }\r
+ catch(std::exception& e)\r
{\r
+ CMessageBox::Show(NULL,CUnicodeUtils::GetUnicode(CStringA(e.what())),_T("TortoiseGit: Combine error"),MB_OK|MB_ICONERROR);\r
cmd.Format(_T("git.exe reset --hard %s"),headhash);\r
out.Empty();\r
if(g_Git.Run(cmd,&out,CP_UTF8))\r
{\r
- CMessageBox::Show(NULL,out,_T("TortoiseGit"),MB_OK);\r
+ CMessageBox::Show(NULL,_T("Could not reset to original HEAD\r\n\r\n")+out,_T("TortoiseGit"),MB_OK);\r
}\r
}\r
Refresh();\r