1 // TortoiseGit - a Windows shell extension for easy version control
3 // Copyright (C) 2003-2008 - TortoiseSVN
4 // Copyright (C) 2008-2011 - TortoiseGit
6 // This program is free software; you can redistribute it and/or
7 // modify it under the terms of the GNU General Public License
8 // as published by the Free Software Foundation; either version 2
9 // of the License, or (at your option) any later version.
11 // This program is distributed in the hope that it will be useful,
12 // but WITHOUT ANY WARRANTY; without even the implied warranty of
13 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 // GNU General Public License for more details.
16 // You should have received a copy of the GNU General Public License
17 // along with this program; if not, write to the Free Software Foundation,
18 // 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
25 #include "MessageBox.h"
26 #include "FileDiffDlg.h"
28 CGitDiff::CGitDiff(void)
32 CGitDiff::~CGitDiff(void)
35 int CGitDiff::Parser(git_revnum_t
&rev
)
37 if(rev
== GIT_REV_ZERO
)
39 if(rev
.GetLength() > 40)
42 cmd
.Format(_T("git.exe rev-parse %s"),rev
);
44 if(!g_Git
.Run(cmd
,&output
,CP_UTF8
))
46 //int start=output.Find(_T('\n'));
53 int CGitDiff::SubmoduleDiffNull(CTGitPath
*pPath
, git_revnum_t
&/*rev1*/)
55 CString oldhash
= GIT_REV_ZERO
;
62 cmd
.Format(_T("git.exe ls-tree HEAD -- \"%s\""), pPath
->GetGitPathString());
64 if(g_Git
.Run(cmd
,&output
,CP_ACP
))
66 CMessageBox::Show(NULL
,output
,_T("TortoiseGit"),MB_OK
|MB_ICONERROR
);
71 start
=output
.Find(_T(' '),start
);
74 start
=output
.Find(_T(' '),start
+1);
76 newhash
=output
.Mid(start
+1, 40);
79 subgit
.m_CurrentDir
=g_Git
.m_CurrentDir
+_T("\\")+pPath
->GetWinPathString();
80 int encode
=CAppUtils::GetLogOutputEncode(&subgit
);
82 cmd
.Format(_T("git.exe log -n1 --pretty=format:\"%%s\" %s"),newhash
);
83 subgit
.Run(cmd
,&newsub
,encode
);
86 msg
.Format(_T("Submodule <b>%s</b> Change\r\n\r\n<b>From:</b> %s\r\n\t%s\r\n\r\n<b>To%s:</b> %s\r\n\t\t%s"),
93 CMessageBox::Show(NULL
,msg
,_T("TortoiseGit"),MB_OK
);
97 CMessageBox::Show(NULL
,_T("ls-tree output format error"),_T("TortoiseGit"),MB_OK
|MB_ICONERROR
);
101 int CGitDiff::DiffNull(CTGitPath
*pPath
, git_revnum_t rev1
,bool bIsAdd
)
104 GetTempPath(temppath
);
110 if(pPath
->IsDirectory())
113 return SubmoduleDiffNull(pPath
,rev1
);
116 if(rev1
!= GIT_REV_ZERO
)
118 TCHAR szTempName
[MAX_PATH
];
119 GetTempFileName(temppath
, pPath
->GetBaseFilename(), 0, szTempName
);
120 CString
temp(szTempName
);
121 DeleteFile(szTempName
);
122 CreateDirectory(szTempName
, NULL
);
123 file1
.Format(_T("%s\\%s-%s%s"),
125 pPath
->GetBaseFilename(),
127 pPath
->GetFileExtension());
129 g_Git
.GetOneFile(rev1
,*pPath
,file1
);
133 file1
=g_Git
.m_CurrentDir
+_T("\\")+pPath
->GetWinPathString();
136 // preserve FileExtension, needed especially for diffing deleted images (detection on new filename extension)
137 CString tempfile
=::GetTempFile() + pPath
->GetFileExtension();
138 CStdioFile
file(tempfile
,CFile::modeReadWrite
|CFile::modeCreate
);
139 //file.WriteString();
142 CAppUtils::DiffFlags flags
;
145 CAppUtils::StartExtDiff(tempfile
,file1
,
146 pPath
->GetGitPathString(),
147 pPath
->GetGitPathString()+_T(":")+rev1
.Left(6)
150 CAppUtils::StartExtDiff(file1
,tempfile
,
151 pPath
->GetGitPathString()+_T(":")+rev1
.Left(6)
152 ,pPath
->GetGitPathString(),flags
);
157 int CGitDiff::SubmoduleDiff(CTGitPath
* pPath
,CTGitPath
* /*pPath2*/, git_revnum_t rev1
, git_revnum_t rev2
, bool /*blame*/, bool /*unified*/)
164 if( rev2
== GIT_REV_ZERO
|| rev1
== GIT_REV_ZERO
)
166 oldhash
= GIT_REV_ZERO
;
167 newhash
= GIT_REV_ZERO
;
170 if( rev2
!= GIT_REV_ZERO
)
172 if( rev1
!= GIT_REV_ZERO
)
175 workingcopy
= _T(" (Work Copy)");
177 cmd
.Format(_T("git.exe diff %s -- \"%s\""),
178 rev
,pPath
->GetGitPathString());
181 if(g_Git
.Run(cmd
,&output
,CP_ACP
))
183 CMessageBox::Show(NULL
,output
,_T("TortoiseGit"),MB_OK
|MB_ICONERROR
);
187 int oldstart
= output
.Find(_T("-Subproject commit"),start
);
190 CMessageBox::Show(NULL
,_T("Subproject Diff Format error") ,_T("TortoiseGit"),MB_OK
|MB_ICONERROR
);
193 oldhash
= output
.Mid(oldstart
+ CString(_T("-Subproject commit")).GetLength()+1,40);
195 int newstart
= output
.Find(_T("+Subproject commit"),start
);
198 CMessageBox::Show(NULL
,_T("Subproject Diff Format error") ,_T("TortoiseGit"),MB_OK
|MB_ICONERROR
);
201 newhash
= output
.Mid(newstart
+ CString(_T("+Subproject commit")).GetLength()+1,40);
206 cmd
.Format(_T("git.exe diff-tree -r -z %s %s -- \"%s\""),
207 rev2
,rev1
,pPath
->GetGitPathString());
210 if(g_Git
.Run(cmd
,&bytes
))
213 g_Git
.StringAppend(&err
,&bytes
[0],CP_ACP
);
214 CMessageBox::Show(NULL
,err
,_T("TortoiseGit"),MB_OK
|MB_ICONERROR
);
218 g_Git
.StringAppend(&oldhash
,&bytes
[15],CP_ACP
,40);
219 g_Git
.StringAppend(&newhash
,&bytes
[15+41],CP_ACP
,40);
227 subgit
.m_CurrentDir
=g_Git
.m_CurrentDir
+_T("\\")+pPath
->GetWinPathString();
229 if(pPath
->HasAdminDir())
231 int encode
=CAppUtils::GetLogOutputEncode(&subgit
);
233 if(oldhash
!= GIT_REV_ZERO
)
235 cmd
.Format(_T("git log -n1 --pretty=format:\"%%s\" %s"),oldhash
);
236 subgit
.Run(cmd
,&oldsub
,encode
);
238 if(newsub
!= GIT_REV_ZERO
)
240 cmd
.Format(_T("git log -n1 --pretty=format:\"%%s\" %s"),newhash
);
241 subgit
.Run(cmd
,&newsub
,encode
);
245 msg
.Format(_T("Submodule <b>%s</b> Change\r\n\r\n<b>From:</b> %s\r\n\t%s\r\n\r\n<b>To%s:</b> %s\r\n\t\t%s"),
252 CMessageBox::Show(NULL
,msg
,_T("TortoiseGit"),MB_OK
);
257 int CGitDiff::Diff(CTGitPath
* pPath
,CTGitPath
* pPath2
, git_revnum_t rev1
, git_revnum_t rev2
, bool /*blame*/, bool /*unified*/)
260 GetTempPath(temppath
);
267 if(pPath
->IsDirectory() || pPath2
->IsDirectory())
269 return SubmoduleDiff(pPath
,pPath2
,rev1
,rev2
);
272 if(rev1
!= GIT_REV_ZERO
)
274 TCHAR szTempName
[MAX_PATH
];
275 GetTempFileName(temppath
, pPath
->GetBaseFilename(), 0, szTempName
);
276 CString
temp(szTempName
);
277 DeleteFile(szTempName
);
278 CreateDirectory(szTempName
, NULL
);
279 // use original file extension, an external diff tool might need it
280 file1
.Format(_T("%s\\%s-%s-right%s"),
282 pPath
->GetBaseFilename(),
284 pPath
->GetFileExtension());
285 title1
= pPath
->GetFileOrDirectoryName()+_T(":")+rev1
.Left(6);
286 g_Git
.GetOneFile(rev1
,*pPath
,file1
);
291 file1
=g_Git
.m_CurrentDir
+_T("\\")+pPath
->GetWinPathString();
292 title1
.Format( IDS_DIFF_WCNAME
, pPath
->GetFileOrDirectoryName() );
297 if(rev2
!= GIT_REV_ZERO
)
299 TCHAR szTempName
[MAX_PATH
];
300 GetTempFileName(temppath
, pPath2
->GetBaseFilename(), 0, szTempName
);
301 CString
temp(szTempName
);
302 DeleteFile(szTempName
);
303 CreateDirectory(szTempName
, NULL
);
304 // use original file extension, an external diff tool might need it
305 file2
.Format(_T("%s\\%s-%s-left%s"),
307 pPath2
->GetBaseFilename(),
309 pPath2
->GetFileExtension());
310 title2
= pPath2
->GetFileOrDirectoryName()+_T(":")+rev2
.Left(6);
311 g_Git
.GetOneFile(rev2
,*pPath2
,file2
);
315 file2
=g_Git
.m_CurrentDir
+_T("\\")+pPath2
->GetWinPathString();
316 title2
.Format( IDS_DIFF_WCNAME
, pPath2
->GetFileOrDirectoryName() );
319 if (pPath
->m_Action
== pPath
->LOGACTIONS_ADDED
)
321 CGitDiff::DiffNull(pPath
, rev1
, true);
323 else if (pPath
->m_Action
== pPath
->LOGACTIONS_DELETED
)
325 CGitDiff::DiffNull(pPath
, rev2
, false);
329 CAppUtils::DiffFlags flags
;
330 CAppUtils::StartExtDiff(file2
,file1
,
338 int CGitDiff::DiffCommit(CTGitPath
&path
, GitRev
*r1
, GitRev
*r2
)
340 if( path
.GetWinPathString().IsEmpty() || path
.IsDirectory() )
343 dlg
.SetDiff(NULL
,*r1
,*r2
);
348 Diff(&path
,&path
,r1
->m_CommitHash
.ToString(),r2
->m_CommitHash
.ToString());
353 int CGitDiff::DiffCommit(CTGitPath
&path
, CString r1
, CString r2
)
355 if( path
.GetWinPathString().IsEmpty() || path
.IsDirectory() )
358 dlg
.SetDiff(NULL
,r1
,r2
);
363 Diff(&path
,&path
,r1
,r2
);