OSDN Git Service

'Cherry-pick' commits after combined commits when combine is done
authorJohan t Hart <johanthart@gmail.com>
Sat, 21 Feb 2009 22:54:11 +0000 (23:54 +0100)
committerFrank Li <lznuaa@gmail.com>
Sun, 22 Feb 2009 03:45:41 +0000 (11:45 +0800)
src/Git/Git.cpp
src/TortoiseProc/GitLogListAction.cpp

index bb32abf..922b181 100644 (file)
@@ -599,7 +599,8 @@ git_revnum_t CGit::GetHash(CString &friendname)
        CString out;\r
        cmd.Format(_T("git.exe rev-parse %s" ),friendname);\r
        Run(cmd,&out,CP_UTF8);\r
-       int pos=out.ReverseFind(_T('\n'));\r
+//     int pos=out.ReverseFind(_T('\n'));\r
+       int pos=out.FindOneOf(_T("\r\n"));\r
        if(pos>0)\r
                return out.Left(pos);\r
        return out;\r
index 8bafa70..a05fe37 100644 (file)
@@ -202,45 +202,108 @@ void CGitLogList::ContextMenuAction(int cmd,int FirstSelect, int LastSelect)
                        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