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
, NULL
, 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
, &err
, CP_ACP
))
66 CMessageBox::Show(NULL
, output
+ L
"\n" + err
, _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();
141 ::SetFileAttributes(tempfile
, FILE_ATTRIBUTE_READONLY
);
143 CAppUtils::DiffFlags flags
;
146 CAppUtils::StartExtDiff(tempfile
,file1
,
147 pPath
->GetGitPathString(),
148 pPath
->GetGitPathString()+_T(":")+rev1
.Left(6)
151 CAppUtils::StartExtDiff(file1
,tempfile
,
152 pPath
->GetGitPathString()+_T(":")+rev1
.Left(6)
153 ,pPath
->GetGitPathString(),flags
);
158 int CGitDiff::SubmoduleDiff(CTGitPath
* pPath
,CTGitPath
* /*pPath2*/, git_revnum_t rev1
, git_revnum_t rev2
, bool /*blame*/, bool /*unified*/)
165 if( rev2
== GIT_REV_ZERO
|| rev1
== GIT_REV_ZERO
)
167 oldhash
= GIT_REV_ZERO
;
168 newhash
= GIT_REV_ZERO
;
171 if( rev2
!= GIT_REV_ZERO
)
173 if( rev1
!= GIT_REV_ZERO
)
176 workingcopy
= _T(" (Work Copy)");
178 cmd
.Format(_T("git.exe diff %s -- \"%s\""),
179 rev
,pPath
->GetGitPathString());
182 if (g_Git
.Run(cmd
, &output
, &err
, CP_ACP
))
184 CMessageBox::Show(NULL
, output
+ L
"\n" + err
, _T("TortoiseGit"), MB_OK
|MB_ICONERROR
);
188 int oldstart
= output
.Find(_T("-Subproject commit"),start
);
191 CMessageBox::Show(NULL
,_T("Subproject Diff Format error") ,_T("TortoiseGit"),MB_OK
|MB_ICONERROR
);
194 oldhash
= output
.Mid(oldstart
+ CString(_T("-Subproject commit")).GetLength()+1,40);
196 int newstart
= output
.Find(_T("+Subproject commit"),start
);
199 CMessageBox::Show(NULL
,_T("Subproject Diff Format error") ,_T("TortoiseGit"),MB_OK
|MB_ICONERROR
);
202 newhash
= output
.Mid(newstart
+ CString(_T("+Subproject commit")).GetLength()+1,40);
207 cmd
.Format(_T("git.exe diff-tree -r -z %s %s -- \"%s\""),
208 rev2
,rev1
,pPath
->GetGitPathString());
210 BYTE_VECTOR bytes
, errBytes
;
211 if(g_Git
.Run(cmd
, &bytes
, &errBytes
))
214 g_Git
.StringAppend(&err
,&errBytes
[0],CP_ACP
);
215 CMessageBox::Show(NULL
,err
,_T("TortoiseGit"),MB_OK
|MB_ICONERROR
);
219 g_Git
.StringAppend(&oldhash
,&bytes
[15],CP_ACP
,40);
220 g_Git
.StringAppend(&newhash
,&bytes
[15+41],CP_ACP
,40);
228 subgit
.m_CurrentDir
=g_Git
.m_CurrentDir
+_T("\\")+pPath
->GetWinPathString();
230 if(pPath
->HasAdminDir())
232 int encode
=CAppUtils::GetLogOutputEncode(&subgit
);
234 if(oldhash
!= GIT_REV_ZERO
)
236 cmd
.Format(_T("git log -n1 --pretty=format:\"%%s\" %s"),oldhash
);
237 subgit
.Run(cmd
,&oldsub
,encode
);
239 if(newsub
!= GIT_REV_ZERO
)
241 cmd
.Format(_T("git log -n1 --pretty=format:\"%%s\" %s"),newhash
);
242 subgit
.Run(cmd
,&newsub
,encode
);
246 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"),
253 CMessageBox::Show(NULL
,msg
,_T("TortoiseGit"),MB_OK
);
258 int CGitDiff::Diff(CTGitPath
* pPath
,CTGitPath
* pPath2
, git_revnum_t rev1
, git_revnum_t rev2
, bool /*blame*/, bool /*unified*/)
261 GetTempPath(temppath
);
268 if(pPath
->IsDirectory() || pPath2
->IsDirectory())
270 return SubmoduleDiff(pPath
,pPath2
,rev1
,rev2
);
273 if(rev1
!= GIT_REV_ZERO
)
275 TCHAR szTempName
[MAX_PATH
];
276 GetTempFileName(temppath
, pPath
->GetBaseFilename(), 0, szTempName
);
277 CString
temp(szTempName
);
278 DeleteFile(szTempName
);
279 CreateDirectory(szTempName
, NULL
);
280 // use original file extension, an external diff tool might need it
281 file1
.Format(_T("%s\\%s-%s-right%s"),
283 pPath
->GetBaseFilename(),
285 pPath
->GetFileExtension());
286 title1
= pPath
->GetFileOrDirectoryName()+_T(":")+rev1
.Left(6);
287 g_Git
.GetOneFile(rev1
,*pPath
,file1
);
288 ::SetFileAttributes(file1
, FILE_ATTRIBUTE_READONLY
);
292 file1
=g_Git
.m_CurrentDir
+_T("\\")+pPath
->GetWinPathString();
293 title1
.Format( IDS_DIFF_WCNAME
, pPath
->GetFileOrDirectoryName() );
298 if(rev2
!= GIT_REV_ZERO
)
300 TCHAR szTempName
[MAX_PATH
];
301 GetTempFileName(temppath
, pPath2
->GetBaseFilename(), 0, szTempName
);
302 CString
temp(szTempName
);
303 DeleteFile(szTempName
);
304 CreateDirectory(szTempName
, NULL
);
305 CTGitPath fileName
= *pPath2
;
306 if (rev1
== GIT_REV_ZERO
&& pPath2
->m_Action
& CTGitPath::LOGACTIONS_REPLACED
)
307 fileName
= CTGitPath(pPath2
->GetGitOldPathString());
309 // use original file extension, an external diff tool might need it
310 file2
.Format(_T("%s\\%s-%s-left%s"),
312 fileName
.GetBaseFilename(),
314 fileName
.GetFileExtension());
315 title2
= fileName
.GetFileOrDirectoryName() + _T(":") + rev2
.Left(6);
316 g_Git
.GetOneFile(rev2
, fileName
, file2
);
317 ::SetFileAttributes(file2
, FILE_ATTRIBUTE_READONLY
);
321 file2
=g_Git
.m_CurrentDir
+_T("\\")+pPath2
->GetWinPathString();
322 title2
.Format( IDS_DIFF_WCNAME
, pPath2
->GetFileOrDirectoryName() );
325 if (pPath
->m_Action
== pPath
->LOGACTIONS_ADDED
)
327 CGitDiff::DiffNull(pPath
, rev1
, true);
329 else if (pPath
->m_Action
== pPath
->LOGACTIONS_DELETED
)
331 CGitDiff::DiffNull(pPath
, rev2
, false);
335 CAppUtils::DiffFlags flags
;
336 CAppUtils::StartExtDiff(file2
,file1
,
344 int CGitDiff::DiffCommit(CTGitPath
&path
, GitRev
*r1
, GitRev
*r2
)
346 if (path
.GetWinPathString().IsEmpty())
349 dlg
.SetDiff(NULL
,*r1
,*r2
);
352 else if (path
.IsDirectory())
355 dlg
.SetDiff(&path
,*r1
,*r2
);
360 Diff(&path
,&path
,r1
->m_CommitHash
.ToString(),r2
->m_CommitHash
.ToString());
365 int CGitDiff::DiffCommit(CTGitPath
&path
, CString r1
, CString r2
)
367 if (path
.GetWinPathString().IsEmpty())
370 dlg
.SetDiff(NULL
,r1
,r2
);
373 else if (path
.IsDirectory())
376 dlg
.SetDiff(&path
,r1
,r2
);
381 Diff(&path
,&path
,r1
,r2
);