KiCad PCB EDA Suite
Loading...
Searching...
No Matches
git_status_handler.cpp
Go to the documentation of this file.
1/*
2 * This program source code file is part of KiCad, a free EDA CAD application.
3 *
4 * Copyright The KiCad Developers, see AUTHORS.TXT for contributors.
5 *
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 3
9 * of the License, or (at your option) any later version.
10 *
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.
15 *
16 * You should have received a copy of the GNU General Public License
17 * along with this program; if not, you may find one here:
18 * http://www.gnu.org/licenses/gpl-3.0.html
19 * or you may search the http://www.gnu.org website for the version 3 license,
20 * or you may write to the Free Software Foundation, Inc.,
21 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
22 */
23
24#include "git_status_handler.h"
27#include <trace_helpers.h>
28#include <wx/log.h>
29
31{}
32
34{}
35
37{
38 git_repository* repo = GetRepo();
39
40 if( !repo )
41 return false;
42
43 git_status_options opts;
44 git_status_init_options( &opts, GIT_STATUS_OPTIONS_VERSION );
45
46 opts.show = GIT_STATUS_SHOW_INDEX_AND_WORKDIR;
47 opts.flags = GIT_STATUS_OPT_INCLUDE_UNTRACKED | GIT_STATUS_OPT_RENAMES_HEAD_TO_INDEX
48 | GIT_STATUS_OPT_SORT_CASE_SENSITIVELY;
49
50 git_status_list* status_list = nullptr;
51
52 if( git_status_list_new( &status_list, repo, &opts ) != GIT_OK )
53 {
54 wxLogTrace( traceGit, "Failed to get status list: %s", KIGIT_COMMON::GetLastGitError() );
55 return false;
56 }
57
58 KIGIT::GitStatusListPtr status_list_ptr( status_list );
59 bool hasChanges = ( git_status_list_entrycount( status_list ) > 0 );
60
61 return hasChanges;
62}
63
64std::map<wxString, FileStatus> GIT_STATUS_HANDLER::GetFileStatus( const wxString& aPathspec )
65{
66 std::map<wxString, FileStatus> fileStatusMap;
67 git_repository* repo = GetRepo();
68
69 if( !repo )
70 return fileStatusMap;
71
72 git_status_options status_options;
73 git_status_init_options( &status_options, GIT_STATUS_OPTIONS_VERSION );
74 status_options.show = GIT_STATUS_SHOW_INDEX_AND_WORKDIR;
75 status_options.flags = GIT_STATUS_OPT_INCLUDE_UNTRACKED | GIT_STATUS_OPT_INCLUDE_UNMODIFIED;
76
77 // Set up pathspec if provided
78 std::string pathspec_str;
79 std::vector<const char*> pathspec_ptrs;
80
81 if( !aPathspec.IsEmpty() )
82 {
83 pathspec_str = aPathspec.ToStdString();
84 pathspec_ptrs.push_back( pathspec_str.c_str() );
85
86 status_options.pathspec.strings = const_cast<char**>( pathspec_ptrs.data() );
87 status_options.pathspec.count = pathspec_ptrs.size();
88 }
89
90 git_status_list* status_list = nullptr;
91
92 if( git_status_list_new( &status_list, repo, &status_options ) != GIT_OK )
93 {
94 wxLogTrace( traceGit, "Failed to get git status list: %s", KIGIT_COMMON::GetLastGitError() );
95 return fileStatusMap;
96 }
97
98 KIGIT::GitStatusListPtr statusListPtr( status_list );
99
100 size_t count = git_status_list_entrycount( status_list );
101 wxString repoWorkDir( git_repository_workdir( repo ) );
102
103 for( size_t ii = 0; ii < count; ++ii )
104 {
105 const git_status_entry* entry = git_status_byindex( status_list, ii );
106 std::string path( entry->head_to_index ? entry->head_to_index->old_file.path
107 : entry->index_to_workdir->old_file.path );
108
109 wxString absPath = repoWorkDir + path;
110
111 FileStatus fileStatus;
112 fileStatus.filePath = absPath;
113 fileStatus.gitStatus = entry->status;
114 fileStatus.status = ConvertStatus( entry->status );
115
116 fileStatusMap[absPath] = fileStatus;
117 }
118
119 return fileStatusMap;
120}
121
123{
124 git_repository* repo = GetRepo();
125
126 if( !repo )
127 return wxEmptyString;
128
129 git_reference* currentBranchReference = nullptr;
130 int rc = git_repository_head( &currentBranchReference, repo );
131 KIGIT::GitReferencePtr currentBranchReferencePtr( currentBranchReference );
132
133 if( currentBranchReference )
134 {
135 return git_reference_shorthand( currentBranchReference );
136 }
137 else if( rc == GIT_EUNBORNBRANCH )
138 {
139 // Unborn branch - could return empty or a default name
140 return wxEmptyString;
141 }
142 else
143 {
144 wxLogTrace( traceGit, "Failed to lookup current branch: %s", KIGIT_COMMON::GetLastGitError() );
145 return wxEmptyString;
146 }
147}
148
149void GIT_STATUS_HANDLER::UpdateRemoteStatus( const std::set<wxString>& aLocalChanges,
150 const std::set<wxString>& aRemoteChanges,
151 std::map<wxString, FileStatus>& aFileStatus )
152{
153 git_repository* repo = GetRepo();
154
155 if( !repo )
156 return;
157
158 wxString repoWorkDir( git_repository_workdir( repo ) );
159
160 // Update status based on local/remote changes
161 for( auto& [absPath, fileStatus] : aFileStatus )
162 {
163 // Convert absolute path to relative path for comparison
164 wxString relativePath = absPath;
165 if( relativePath.StartsWith( repoWorkDir ) )
166 {
167 relativePath = relativePath.Mid( repoWorkDir.length() );
168#ifdef _WIN32
169 relativePath.Replace( wxS( "\\" ), wxS( "/" ) );
170#endif
171 }
172
173 std::string relativePathStd = relativePath.ToStdString();
174
175 // Only update if the file is not already modified/added/deleted
176 if( fileStatus.status == KIGIT_COMMON::GIT_STATUS::GIT_STATUS_CURRENT )
177 {
178 if( aLocalChanges.count( relativePathStd ) )
179 {
181 }
182 else if( aRemoteChanges.count( relativePathStd ) )
183 {
185 }
186 }
187 }
188}
189
191{
192 git_repository* repo = GetRepo();
193
194 if( !repo )
195 return wxEmptyString;
196
197 const char* workdir = git_repository_workdir( repo );
198
199 if( !workdir )
200 return wxEmptyString;
201
202 return wxString( workdir );
203}
204
206{
207 if( aGitStatus & GIT_STATUS_IGNORED )
208 {
210 }
211 else if( aGitStatus & ( GIT_STATUS_INDEX_MODIFIED | GIT_STATUS_WT_MODIFIED ) )
212 {
214 }
215 else if( aGitStatus & ( GIT_STATUS_INDEX_NEW | GIT_STATUS_WT_NEW ) )
216 {
218 }
219 else if( aGitStatus & ( GIT_STATUS_INDEX_DELETED | GIT_STATUS_WT_DELETED ) )
220 {
222 }
223 else if( aGitStatus & ( GIT_STATUS_CONFLICTED ) )
224 {
226 }
227 else
228 {
230 }
231}
232
233void GIT_STATUS_HANDLER::UpdateProgress( int aCurrent, int aTotal, const wxString& aMessage )
234{
235 ReportProgress( aCurrent, aTotal, aMessage );
236}
void ReportProgress(int aCurrent, int aTotal, const wxString &aMessage)
Definition: git_progress.h:45
void UpdateProgress(int aCurrent, int aTotal, const wxString &aMessage) override
GIT_STATUS_HANDLER(KIGIT_COMMON *aCommon)
wxString GetCurrentBranchName()
Get the current branch name.
void UpdateRemoteStatus(const std::set< wxString > &aLocalChanges, const std::set< wxString > &aRemoteChanges, std::map< wxString, FileStatus > &aFileStatus)
Get status for modified files based on local/remote changes.
KIGIT_COMMON::GIT_STATUS ConvertStatus(unsigned int aGitStatus)
Convert git status flags to KIGIT_COMMON::GIT_STATUS.
wxString GetWorkingDirectory()
Get the repository working directory path.
bool HasChangedFiles()
Check if the repository has any changed files.
std::map< wxString, FileStatus > GetFileStatus(const wxString &aPathspec=wxEmptyString)
Get detailed file status for all files in the specified path.
static wxString GetLastGitError()
git_repository * GetRepo() const
Get a pointer to the git repository.
const wxChar *const traceGit
Flag to enable Git debugging output.
std::unique_ptr< git_status_list, decltype([](git_status_list *aList) { git_status_list_free(aList) GitStatusListPtr
A unique pointer for git_status_list objects with automatic cleanup.
std::unique_ptr< git_reference, decltype([](git_reference *aRef) { git_reference_free(aRef) GitReferencePtr
A unique pointer for git_reference objects with automatic cleanup.
wxString filePath
KIGIT_COMMON::GIT_STATUS status
unsigned int gitStatus
wxLogTrace helper definitions.