39#include <wx/filename.h>
49 if( aMessage.empty() )
52 size_t firstLineEnd = aMessage.find_first_of(
'\n' );
54 if( firstLineEnd != std::string::npos )
55 return aMessage.substr( 0, firstLineEnd );
64 time_t time =
static_cast<time_t
>( aTime.time );
68 localtime_s( &timeInfo, &time );
70 gmtime_r( &time, &timeInfo );
73 strftime( dateBuffer,
sizeof( dateBuffer ),
"%Y-%b-%d %H:%M:%S", &timeInfo );
85#if ( LIBGIT2_VER_MAJOR > 1 ) || ( LIBGIT2_VER_MAJOR == 1 && LIBGIT2_VER_MINOR >= 7 )
86 constexpr int connectTimeoutMs = 10000;
87 constexpr int transferTimeoutMs = 30000;
89 if( git_libgit2_opts( GIT_OPT_SET_SERVER_CONNECT_TIMEOUT, connectTimeoutMs ) != GIT_OK
90 || git_libgit2_opts( GIT_OPT_SET_SERVER_TIMEOUT, transferTimeoutMs ) != GIT_OK )
92 wxLogTrace(
traceGit,
"LIBGIT_BACKEND::Init(): could not set server timeouts: %s",
108 constexpr auto kOrphanJoinTimeout = std::chrono::seconds( 5 );
113 wxLogTrace(
traceGit,
"LIBGIT_BACKEND::Shutdown(): %zu orphan git thread(s) did not finish within %lld ms; "
114 "skipping libgit2 shutdown",
115 stuck,
static_cast<long long>( kOrphanJoinTimeout.count() ) );
125 git_libgit2_shutdown();
131#if ( LIBGIT2_VER_MAJOR >= 1 ) || ( LIBGIT2_VER_MINOR >= 99 )
132 int major = 0, minor = 0, rev = 0;
133 return git_libgit2_version( &major, &minor, &rev ) == GIT_OK;
144 std::unique_lock<std::mutex> lock( common->
m_gitActionMutex, std::try_to_lock );
146 if( !lock.owns_lock() )
148 wxLogTrace(
traceGit,
"GIT_CLONE_HANDLER::PerformClone() could not lock" );
154 if( !clonePath.DirExists() )
156 if( !clonePath.Mkdir( wxS_DIR_DEFAULT, wxPATH_MKDIR_FULL ) )
158 aHandler->
AddErrorString( wxString::Format(
_(
"Could not create directory '%s'" ),
164 git_clone_options cloneOptions;
165 git_clone_init_options( &cloneOptions, GIT_CLONE_OPTIONS_VERSION );
166 cloneOptions.checkout_opts.checkout_strategy = GIT_CHECKOUT_SAFE;
168 cloneOptions.checkout_opts.progress_payload = aHandler;
171 cloneOptions.fetch_opts.callbacks.payload = aHandler;
172 cloneOptions.fetch_opts.proxy_opts.type = GIT_PROXY_AUTO;
176 git_repository* newRepo =
nullptr;
179 if( git_clone( &newRepo, remote.mbc_str(), aHandler->
GetClonePath().mbc_str(), &cloneOptions ) != 0 )
181 aHandler->
AddErrorString( wxString::Format(
_(
"Could not clone repository '%s' : %s" ),
194 const wxString& aMessage,
const wxString& aAuthorName,
195 const wxString& aAuthorEmail )
197 git_repository* repo = aHandler->
GetRepo();
202 git_index*
index =
nullptr;
204 if( git_repository_index( &
index, repo ) != 0 )
206 aHandler->
AddErrorString( wxString::Format(
_(
"Failed to get repository index: %s" ),
213 for(
const wxString& file : aFiles )
215 if( git_index_add_bypath(
index, file.mb_str() ) != 0 )
217 aHandler->
AddErrorString( wxString::Format(
_(
"Failed to add file to index: %s" ),
223 if( git_index_write(
index ) != 0 )
225 aHandler->
AddErrorString( wxString::Format(
_(
"Failed to write index: %s" ),
232 if( git_index_write_tree( &tree_id,
index ) != 0 )
234 aHandler->
AddErrorString( wxString::Format(
_(
"Failed to write tree: %s" ),
239 git_tree* tree =
nullptr;
241 if( git_tree_lookup( &tree, repo, &tree_id ) != 0 )
243 aHandler->
AddErrorString( wxString::Format(
_(
"Failed to lookup tree: %s" ),
249 git_commit* parent =
nullptr;
251 if( git_repository_head_unborn( repo ) == 0 )
253 git_reference* headRef =
nullptr;
255 if( git_repository_head( &headRef, repo ) != 0 )
257 aHandler->
AddErrorString( wxString::Format(
_(
"Failed to get HEAD reference: %s" ),
264 if( git_reference_peel( (git_object**) &parent, headRef, GIT_OBJECT_COMMIT ) != 0 )
266 aHandler->
AddErrorString( wxString::Format(
_(
"Failed to get commit: %s" ),
274 git_signature* author =
nullptr;
276 if( git_signature_now( &author, aAuthorName.mb_str(), aAuthorEmail.mb_str() ) != 0 )
278 aHandler->
AddErrorString( wxString::Format(
_(
"Failed to create author signature: %s" ),
285 size_t parentsCount = parent ? 1 : 0;
287#if( LIBGIT2_VER_MAJOR == 1 && LIBGIT2_VER_MINOR == 8 \
288 && ( LIBGIT2_VER_REVISION < 2 || LIBGIT2_VER_REVISION == 3 ) )
289 git_commit*
const parents[1] = { parent };
290 git_commit**
const parentsPtr = parent ? parents :
nullptr;
292 const git_commit* parents[1] = { parent };
293 const git_commit** parentsPtr = parent ? parents :
nullptr;
296 if( git_commit_create( &oid, repo,
"HEAD", author, author,
nullptr,
297 aMessage.mb_str(), tree, parentsCount, parentsPtr ) != 0 )
299 aHandler->
AddErrorString( wxString::Format(
_(
"Failed to create commit: %s" ),
309 const wxString& aMessage,
const wxString& aAuthorName,
310 const wxString& aAuthorEmail )
312 git_repository* repo = aHandler->
GetRepo();
317 if( git_repository_head_unborn( repo ) != 0 )
319 aHandler->
AddErrorString(
_(
"Cannot amend: the branch has no commits yet." ) );
323 git_reference* headRef =
nullptr;
325 if( git_repository_head( &headRef, repo ) != 0 )
327 aHandler->
AddErrorString( wxString::Format(
_(
"Failed to get HEAD reference: %s" ),
333 git_commit* headCommit =
nullptr;
335 if( git_reference_peel( (git_object**) &headCommit, headRef, GIT_OBJECT_COMMIT ) != 0 )
337 aHandler->
AddErrorString( wxString::Format(
_(
"Failed to get HEAD commit: %s" ),
343 git_index*
index =
nullptr;
345 if( git_repository_index( &
index, repo ) != 0 )
347 aHandler->
AddErrorString( wxString::Format(
_(
"Failed to get repository index: %s" ),
354 git_commit* parentCommit =
nullptr;
356 if( git_commit_parentcount( headCommit ) > 0 && git_commit_parent( &parentCommit, headCommit, 0 ) != 0 )
358 aHandler->
AddErrorString( wxString::Format(
_(
"Failed to get parent commit: %s" ),
367 git_tree* headTree =
nullptr;
369 if( git_commit_tree( &headTree, headCommit ) != 0 )
371 aHandler->
AddErrorString( wxString::Format(
_(
"Failed to get HEAD tree: %s" ),
378 if( git_index_read_tree(
index, headTree ) != 0 )
380 aHandler->
AddErrorString( wxString::Format(
_(
"Failed to reset index: %s" ),
390 git_tree* parentTree =
nullptr;
392 if( git_commit_tree( &parentTree, parentCommit ) != 0 )
394 aHandler->
AddErrorString( wxString::Format(
_(
"Failed to get parent tree: %s" ),
401 if( git_index_read_tree(
index, parentTree ) != 0 )
403 aHandler->
AddErrorString( wxString::Format(
_(
"Failed to reset index: %s" ),
411 git_index_clear(
index );
414 const char* workdir = git_repository_workdir( repo );
416 for(
const wxString& file : aFiles )
418 bool onDisk = workdir && wxFileName::FileExists( wxString::FromUTF8( workdir ) + file );
420 int rc = onDisk ? git_index_add_bypath(
index, file.mb_str() )
421 : git_index_remove_bypath(
index, file.mb_str() );
425 aHandler->
AddErrorString( wxString::Format(
_(
"Failed to add file to index: %s" ),
432 if( git_index_write(
index ) != 0 )
434 aHandler->
AddErrorString( wxString::Format(
_(
"Failed to write index: %s" ),
441 if( git_index_write_tree( &tree_id,
index ) != 0 )
443 aHandler->
AddErrorString( wxString::Format(
_(
"Failed to write tree: %s" ),
448 git_tree* tree =
nullptr;
450 if( git_tree_lookup( &tree, repo, &tree_id ) != 0 )
452 aHandler->
AddErrorString( wxString::Format(
_(
"Failed to lookup tree: %s" ),
458 git_signature* author =
nullptr;
460 if( git_signature_now( &author, aAuthorName.mb_str(), aAuthorEmail.mb_str() ) != 0 )
462 aHandler->
AddErrorString( wxString::Format(
_(
"Failed to create author signature: %s" ),
470 if( git_commit_amend( &oid, headCommit,
"HEAD", author, author,
nullptr, aMessage.mb_str(), tree ) != 0 )
472 aHandler->
AddErrorString( wxString::Format(
_(
"Failed to amend commit: %s" ),
484 std::unique_lock<std::mutex> lock( common->
m_gitActionMutex, std::try_to_lock );
486 if( !lock.owns_lock() )
488 wxLogTrace(
traceGit,
"GIT_PUSH_HANDLER::PerformPush: Could not lock mutex" );
495 std::string remoteNameUtf8 = remoteName.utf8_string();
496 git_remote* remote =
nullptr;
498 if( git_remote_lookup( &remote, aHandler->
GetRepo(), remoteNameUtf8.c_str() ) != 0 )
500 aHandler->
AddErrorString( wxString::Format(
_(
"Could not lookup remote '%s'" ), remoteName ) );
506 git_remote_callbacks remoteCallbacks;
507 git_remote_init_callbacks( &remoteCallbacks, GIT_REMOTE_CALLBACKS_VERSION );
513 remoteCallbacks.payload = aHandler;
515 git_proxy_options proxyOpts;
516 git_proxy_init_options( &proxyOpts, GIT_PROXY_OPTIONS_VERSION );
517 proxyOpts.type = GIT_PROXY_AUTO;
523 if( git_remote_connect( remote, GIT_DIRECTION_PUSH, &remoteCallbacks, &proxyOpts,
nullptr ) )
525 aHandler->
AddErrorString( wxString::Format(
_(
"Could not connect to remote: %s" ),
530 git_push_options pushOptions;
531 git_push_init_options( &pushOptions, GIT_PUSH_OPTIONS_VERSION );
532 pushOptions.callbacks = remoteCallbacks;
533 pushOptions.proxy_opts.type = GIT_PROXY_AUTO;
535 git_reference* head =
nullptr;
537 if( git_repository_head( &head, aHandler->
GetRepo() ) != 0 )
539 git_remote_disconnect( remote );
547 wxString refspec = ( aForce ? wxS(
"+" ) : wxS(
"" ) ) + wxString( git_reference_name( head ) );
548 std::string refspecUtf8 = refspec.utf8_string();
549 const char* refs[1] = { refspecUtf8.c_str() };
550 const git_strarray refspecs = { (
char**) refs, 1 };
552 if( git_remote_push( remote, &refspecs, &pushOptions ) )
555 aHandler->
AddErrorString( wxString::Format(
_(
"Could not push to remote: %s" ), errorMsg ) );
556 git_remote_disconnect( remote );
558 wxString lower = errorMsg.Lower();
560 if( lower.Contains( wxS(
"non-fast-forward" ) ) || lower.Contains( wxS(
"non-fastforwardable" ) )
561 || lower.Contains( wxS(
"would not be" ) ) )
570 if( git_reference_is_branch( head ) )
572 git_reference* upstreamRef =
nullptr;
573 int rc = git_branch_upstream( &upstreamRef, head );
575 if( rc == GIT_ENOTFOUND )
577 wxString upstreamName = wxString::Format(
"%s/%s", remoteName, git_reference_shorthand( head ) );
578 git_branch_set_upstream( head, upstreamName.utf8_string().c_str() );
580 else if( rc == GIT_OK )
586 git_remote_disconnect( remote );
594 git_repository* repo = aHandler->
GetRepo();
599 git_status_options opts;
600 git_status_init_options( &opts, GIT_STATUS_OPTIONS_VERSION );
602 opts.show = GIT_STATUS_SHOW_INDEX_AND_WORKDIR;
603 opts.flags = GIT_STATUS_OPT_INCLUDE_UNTRACKED | GIT_STATUS_OPT_RENAMES_HEAD_TO_INDEX
604 | GIT_STATUS_OPT_SORT_CASE_SENSITIVELY;
606 git_status_list* status_list =
nullptr;
608 if( git_status_list_new( &status_list, repo, &opts ) != GIT_OK )
615 bool hasChanges = ( git_status_list_entrycount( status_list ) > 0 );
622 const wxString& aPathspec )
624 std::map<wxString, FileStatus> fileStatusMap;
625 git_repository* repo = aHandler->
GetRepo();
628 return fileStatusMap;
630 git_status_options status_options;
631 git_status_init_options( &status_options, GIT_STATUS_OPTIONS_VERSION );
632 status_options.show = GIT_STATUS_SHOW_INDEX_AND_WORKDIR;
633 status_options.flags = GIT_STATUS_OPT_INCLUDE_UNTRACKED | GIT_STATUS_OPT_INCLUDE_UNMODIFIED
634 | GIT_STATUS_OPT_RECURSE_UNTRACKED_DIRS;
636 std::string pathspec_str;
637 std::vector<const char*> pathspec_ptrs;
639 if( !aPathspec.IsEmpty() )
641 pathspec_str = aPathspec.ToStdString();
642 pathspec_ptrs.push_back( pathspec_str.c_str() );
644 status_options.pathspec.strings =
const_cast<char**
>( pathspec_ptrs.data() );
645 status_options.pathspec.count = pathspec_ptrs.size();
648 git_status_list* status_list =
nullptr;
650 if( git_status_list_new( &status_list, repo, &status_options ) != GIT_OK )
653 return fileStatusMap;
658 size_t count = git_status_list_entrycount( status_list );
661 for(
size_t ii = 0; ii < count; ++ii )
663 const git_status_entry* entry = git_status_byindex( status_list, ii );
664 std::string
path( entry->head_to_index ? entry->head_to_index->old_file.path
665 : entry->index_to_workdir->old_file.path );
667 wxString absPath = repoWorkDir +
path;
670 static_cast<unsigned int>( entry->status ) };
673 return fileStatusMap;
679 git_repository* repo = aHandler->
GetRepo();
682 return wxEmptyString;
684 git_reference* currentBranchReference =
nullptr;
685 int rc = git_repository_head( ¤tBranchReference, repo );
688 if( currentBranchReference )
690 return git_reference_shorthand( currentBranchReference );
692 else if( rc == GIT_EUNBORNBRANCH )
694 return wxEmptyString;
699 return wxEmptyString;
705 const std::set<wxString>& aLocalChanges,
706 const std::set<wxString>& aRemoteChanges,
707 std::map<wxString, FileStatus>& aFileStatus )
709 git_repository* repo = aHandler->
GetRepo();
716 for(
auto& [absPath, fileStatus] : aFileStatus )
718 wxString relativePath = absPath;
719 if( relativePath.StartsWith( repoWorkDir ) )
721 relativePath = relativePath.Mid( repoWorkDir.length() );
724 relativePath.Replace( wxS(
"\\" ), wxS(
"/" ) );
728 std::string relativePathStd = relativePath.ToStdString();
732 if( aLocalChanges.count( relativePathStd ) )
734 else if( aRemoteChanges.count( relativePathStd ) )
755 git_repository* repo = aHandler->
GetRepo();
760 git_config*
config =
nullptr;
762 if( git_repository_config( &
config, repo ) != GIT_OK )
770 git_config_entry* entry =
nullptr;
771 int result = git_config_get_entry( &entry,
config, aKey.mb_str() );
774 if(
result != GIT_OK || entry ==
nullptr )
776 wxLogTrace(
traceGit,
"Config key '%s' not found", aKey );
780 aValue = wxString( entry->value );
787 git_repository* repo =
nullptr;
788 int error = git_repository_open( &repo, aPath.mb_str() );
792 git_repository_free( repo );
807 git_repository* repo =
nullptr;
809 if( git_repository_init( &repo, aPath.mb_str(), 0 ) != GIT_OK )
812 git_repository_free( repo );
814 aHandler->
AddErrorString( wxString::Format(
_(
"Failed to initialize Git repository: %s" ),
821 wxLogTrace(
traceGit,
"Successfully initialized Git repository at %s", aPath );
828 if( aConfig.
url.IsEmpty() )
831 git_repository* repo = aHandler->
GetRepo();
835 aHandler->
AddErrorString(
_(
"No repository available to set up remote" ) );
843 git_remote* remote =
nullptr;
850 if( !aConfig.
url.Contains(
"@" ) && !aConfig.
username.IsEmpty() )
851 userPrefix = aConfig.
username +
"@";
853 if( aConfig.
url.StartsWith(
"ssh://" ) )
854 fullURL =
"ssh://" + userPrefix + aConfig.
url.Mid( 6 );
855 else if( aConfig.
url.Contains(
":" ) )
856 fullURL = userPrefix + aConfig.
url;
858 fullURL =
"ssh://" + userPrefix + aConfig.
url;
862 fullURL = aConfig.
url.StartsWith(
"https" ) ?
"https://" :
"http://";
870 fullURL.append( wxS(
":" ) );
874 fullURL.append( wxS(
"@" ) );
877 wxString bareURL = aConfig.
url;
879 if( bareURL.StartsWith(
"https://" ) )
880 bareURL = bareURL.Mid( 8 );
881 else if( bareURL.StartsWith(
"http://" ) )
882 bareURL = bareURL.Mid( 7 );
884 fullURL.append( bareURL );
888 fullURL = aConfig.
url;
893 if( git_remote_lookup( &remote, repo,
"origin" ) == GIT_OK )
896 error = git_remote_set_url( repo,
"origin", fullURL.ToStdString().c_str() );
900 error = git_remote_create_with_fetchspec( &remote, repo,
"origin", fullURL.ToStdString().c_str(),
901 "+refs/heads/*:refs/remotes/origin/*" );
905 if( error != GIT_OK )
907 aHandler->
AddErrorString( wxString::Format(
_(
"Failed to set up remote: %s" ),
916 wxLogTrace(
traceGit,
"Successfully set up remote origin" );
923 if( git_reference_lookup( aReference, repo, aBranchName.mb_str() ) == GIT_OK )
926 if( git_reference_dwim( aReference, repo, aBranchName.mb_str() ) == GIT_OK )
935 git_repository* repo = aHandler->
GetRepo();
943 git_reference* branchRef =
nullptr;
947 aHandler->
AddErrorString( wxString::Format(
_(
"Failed to lookup branch '%s': %s" ),
953 const char* branchRefName = git_reference_name( branchRef );
954 git_object* branchObj =
nullptr;
956 if( git_revparse_single( &branchObj, repo, aBranchName.mb_str() ) != GIT_OK )
958 aHandler->
AddErrorString( wxString::Format(
_(
"Failed to find branch head for '%s': %s" ),
966 git_checkout_options checkoutOpts;
967 git_checkout_init_options( &checkoutOpts, GIT_CHECKOUT_OPTIONS_VERSION );
968 checkoutOpts.checkout_strategy = GIT_CHECKOUT_SAFE;
970 if( git_checkout_tree( repo, branchObj, &checkoutOpts ) != GIT_OK )
972 aHandler->
AddErrorString( wxString::Format(
_(
"Failed to switch to branch '%s': %s" ),
978 const char* headTarget = branchRefName;
980 if( git_reference_is_remote( branchRef ) )
982 wxString localName = wxString::FromUTF8( git_reference_shorthand( branchRef ) );
983 size_t slash = localName.find(
'/' );
985 if( slash != wxString::npos )
986 localName = localName.Mid( slash + 1 );
988 std::string localNameUtf8 = localName.utf8_string();
989 git_reference* localBranch =
nullptr;
991 if( git_branch_lookup( &localBranch, repo, localNameUtf8.c_str(), GIT_BRANCH_LOCAL ) != GIT_OK )
993 git_commit* target =
nullptr;
995 if( git_commit_lookup( &target, repo, git_object_id( branchObj ) ) != GIT_OK )
997 aHandler->
AddErrorString( wxString::Format(
_(
"Failed to switch to branch '%s': %s" ),
1005 if( git_branch_create( &localBranch, repo, localNameUtf8.c_str(), target, 0 ) != GIT_OK )
1007 aHandler->
AddErrorString( wxString::Format(
_(
"Failed to create local branch '%s': %s" ),
1013 git_branch_set_upstream( localBranch, git_reference_shorthand( branchRef ) );
1016 localBranchPtr.reset( localBranch );
1017 headTarget = git_reference_name( localBranch );
1020 if( git_repository_set_head( repo, headTarget ) != GIT_OK )
1022 aHandler->
AddErrorString( wxString::Format(
_(
"Failed to update HEAD reference for branch '%s': %s" ),
1028 wxLogTrace(
traceGit,
"Successfully switched to branch '%s'", aBranchName );
1035 git_repository* repo = aHandler->
GetRepo();
1040 git_reference* branchRef =
nullptr;
1044 git_reference_free( branchRef );
1056 wxLogTrace(
traceGit,
"GIT_PULL_HANDLER::PerformFetch() - No repository found" );
1062 if( !aSkipLock && !lock.owns_lock() )
1064 wxLogTrace(
traceGit,
"GIT_PULL_HANDLER::PerformFetch() - Could not lock mutex" );
1069 std::string remoteNameUtf8 = remoteName.utf8_string();
1070 git_remote* remote =
nullptr;
1072 if( git_remote_lookup( &remote, aHandler->
GetRepo(), remoteNameUtf8.c_str() ) != 0 )
1074 wxLogTrace(
traceGit,
"GIT_PULL_HANDLER::PerformFetch() - Failed to lookup remote '%s'", remoteName );
1075 aHandler->
AddErrorString( wxString::Format(
_(
"Could not lookup remote '%s'" ), remoteName ) );
1081 git_remote_callbacks remoteCallbacks;
1082 git_remote_init_callbacks( &remoteCallbacks, GIT_REMOTE_CALLBACKS_VERSION );
1086 remoteCallbacks.payload = aHandler;
1088 git_proxy_options proxyOpts;
1089 git_proxy_init_options( &proxyOpts, GIT_PROXY_OPTIONS_VERSION );
1090 proxyOpts.type = GIT_PROXY_AUTO;
1098 if( git_remote_connect( remote, GIT_DIRECTION_FETCH, &remoteCallbacks, &proxyOpts,
nullptr ) )
1101 wxLogTrace(
traceGit,
"GIT_PULL_HANDLER::PerformFetch() - Failed to connect to remote: %s", errorMsg );
1102 aHandler->
AddErrorString( wxString::Format(
_(
"Could not connect to remote '%s': %s" ),
1108 git_fetch_options fetchOptions;
1109 git_fetch_init_options( &fetchOptions, GIT_FETCH_OPTIONS_VERSION );
1110 fetchOptions.callbacks = remoteCallbacks;
1112 if( git_remote_fetch( remote,
nullptr, &fetchOptions,
nullptr ) )
1115 wxLogTrace(
traceGit,
"GIT_PULL_HANDLER::PerformFetch() - Failed to fetch from remote: %s", errorMsg );
1116 aHandler->
AddErrorString( wxString::Format(
_(
"Could not fetch data from remote '%s': %s" ),
1122 wxLogTrace(
traceGit,
"GIT_PULL_HANDLER::PerformFetch() - Fetch completed successfully" );
1132 if( !lock.owns_lock() )
1134 wxLogTrace(
traceGit,
"GIT_PULL_HANDLER::PerformPull() - Could not lock mutex" );
1141 git_oid pull_merge_oid = {};
1152#if ( LIBGIT2_VER_MAJOR >= 1 ) || ( LIBGIT2_VER_MINOR >= 99 )
1153 if( git_oid_is_zero( &pull_merge_oid ) )
1155 if( git_oid_iszero( &pull_merge_oid ) )
1158 git_reference* head_ref =
nullptr;
1160 if( git_repository_head( &head_ref, aHandler->
GetRepo() ) == GIT_OK )
1164 if( git_reference_is_branch( head_ref ) )
1166 const char* branch_shorthand = git_reference_shorthand( head_ref );
1168 wxString remoteRefName = wxString::Format(
"refs/remotes/%s/%s",
1172 if( git_reference_name_to_id( &pull_merge_oid, aHandler->
GetRepo(),
1173 remoteRefName.utf8_string().c_str() ) == GIT_OK )
1175 wxString upstream = wxString::Format(
"%s/%s", remoteName, branch_shorthand );
1176 git_branch_set_upstream( head_ref, upstream.utf8_string().c_str() );
1182#if ( LIBGIT2_VER_MAJOR >= 1 ) || ( LIBGIT2_VER_MINOR >= 99 )
1183 if( git_oid_is_zero( &pull_merge_oid ) )
1185 if( git_oid_iszero( &pull_merge_oid ) )
1188 aHandler->
AddErrorString(
_(
"Nothing to pull: the remote has no branch matching the current local "
1193 git_annotated_commit* fetchhead_commit;
1195 if( git_annotated_commit_lookup( &fetchhead_commit, aHandler->
GetRepo(), &pull_merge_oid ) )
1202 const git_annotated_commit* merge_commits[] = { fetchhead_commit };
1203 git_merge_analysis_t merge_analysis;
1204 git_merge_preference_t merge_preference = GIT_MERGE_PREFERENCE_NONE;
1206 if( git_merge_analysis( &merge_analysis, &merge_preference, aHandler->
GetRepo(), merge_commits, 1 ) )
1212 if( merge_analysis & GIT_MERGE_ANALYSIS_UNBORN )
1218 if( merge_analysis & GIT_MERGE_ANALYSIS_UP_TO_DATE )
1220 wxLogTrace(
traceGit,
"GIT_PULL_HANDLER::PerformPull() - Repository is up to date" );
1221 git_repository_state_cleanup( aHandler->
GetRepo() );
1225 if( merge_analysis & GIT_MERGE_ANALYSIS_FASTFORWARD )
1227 wxLogTrace(
traceGit,
"GIT_PULL_HANDLER::PerformPull() - Fast-forward merge" );
1231 if( merge_analysis & GIT_MERGE_ANALYSIS_NORMAL )
1233 wxLogTrace(
traceGit,
"GIT_PULL_HANDLER::PerformPull() - Normal merge" );
1235 git_config*
config =
nullptr;
1237 if( git_repository_config( &
config, aHandler->
GetRepo() ) != GIT_OK )
1239 wxLogTrace(
traceGit,
"GIT_PULL_HANDLER::PerformPull() - Failed to get repository config" );
1240 aHandler->
AddErrorString(
_(
"Could not access repository configuration" ) );
1246 int rebase_value = 0;
1247 int ret = git_config_get_bool( &rebase_value,
config,
"pull.rebase" );
1249 if( ret == GIT_OK && rebase_value )
1251 wxLogTrace(
traceGit,
"GIT_PULL_HANDLER::PerformPull() - Using rebase based on config" );
1255 wxLogTrace(
traceGit,
"GIT_PULL_HANDLER::PerformPull() - Using merge based on config" );
1259 wxLogTrace(
traceGit,
"GIT_PULL_HANDLER::PerformPull() - Merge needs resolution" );
1266 git_reference* rawRef =
nullptr;
1268 if( git_repository_head( &rawRef, aHandler->
GetRepo() ) )
1276 git_oid updatedRefOid;
1277 const char* currentBranchName = git_reference_name( rawRef );
1278 const char* branch_shorthand = git_reference_shorthand( rawRef );
1280 wxString remoteBranchName = wxString::Format(
"refs/remotes/%s/%s", remote_name, branch_shorthand );
1282 if( git_reference_name_to_id( &updatedRefOid, aHandler->
GetRepo(), remoteBranchName.c_str() ) != GIT_OK )
1284 aHandler->
AddErrorString( wxString::Format(
_(
"Could not get reference OID for reference '%s'" ),
1285 remoteBranchName ) );
1289 git_commit* targetCommit =
nullptr;
1291 if( git_commit_lookup( &targetCommit, aHandler->
GetRepo(), &updatedRefOid ) != GIT_OK )
1299 git_tree* targetTree =
nullptr;
1301 if( git_commit_tree( &targetTree, targetCommit ) != GIT_OK )
1303 git_commit_free( targetCommit );
1304 aHandler->
AddErrorString(
_(
"Could not get tree from target commit" ) );
1310 git_checkout_options checkoutOptions;
1311 git_checkout_init_options( &checkoutOptions, GIT_CHECKOUT_OPTIONS_VERSION );
1313 []( git_checkout_notify_t why,
const char*
path,
const git_diff_file* baseline,
1314 const git_diff_file* target,
const git_diff_file* workdir,
void* payload ) ->
int
1318 case GIT_CHECKOUT_NOTIFY_CONFLICT:
1321 case GIT_CHECKOUT_NOTIFY_DIRTY:
1324 case GIT_CHECKOUT_NOTIFY_UPDATED:
1327 case GIT_CHECKOUT_NOTIFY_UNTRACKED:
1330 case GIT_CHECKOUT_NOTIFY_IGNORED:
1340 checkoutOptions.checkout_strategy = GIT_CHECKOUT_SAFE | GIT_CHECKOUT_ALLOW_CONFLICTS;
1341 checkoutOptions.notify_flags = GIT_CHECKOUT_NOTIFY_ALL;
1342 checkoutOptions.notify_cb = notify_cb;
1344 if( git_checkout_tree( aHandler->
GetRepo(),
reinterpret_cast<git_object*
>( targetTree ),
1345 &checkoutOptions ) != GIT_OK )
1347 aHandler->
AddErrorString(
_(
"Failed to perform checkout operation." ) );
1351 git_reference* updatedRef =
nullptr;
1353 if( git_reference_set_target( &updatedRef, rawRef, &updatedRefOid,
nullptr ) != GIT_OK )
1355 aHandler->
AddErrorString( wxString::Format(
_(
"Failed to update reference '%s' to point to '%s'" ),
1356 currentBranchName, git_oid_tostr_s( &updatedRefOid ) ) );
1362 if( git_repository_state_cleanup( aHandler->
GetRepo() ) != GIT_OK )
1364 aHandler->
AddErrorString(
_(
"Failed to clean up repository state after fast-forward." ) );
1368 git_revwalk* revWalker =
nullptr;
1370 if( git_revwalk_new( &revWalker, aHandler->
GetRepo() ) != GIT_OK )
1372 aHandler->
AddErrorString(
_(
"Failed to initialize revision walker." ) );
1377 git_revwalk_sorting( revWalker, GIT_SORT_TIME );
1379 if( git_revwalk_push_glob( revWalker, currentBranchName ) != GIT_OK )
1381 aHandler->
AddErrorString(
_(
"Failed to push reference to revision walker." ) );
1385 std::pair<std::string, std::vector<CommitDetails>>& branchCommits = aHandler->
m_fetchResults.emplace_back();
1386 branchCommits.first = currentBranchName;
1390 while( git_revwalk_next( &commitOid, revWalker ) == GIT_OK )
1392 git_commit* commit =
nullptr;
1394 if( git_commit_lookup( &commit, aHandler->
GetRepo(), &commitOid ) )
1396 aHandler->
AddErrorString( wxString::Format(
_(
"Could not lookup commit '%s'" ),
1397 git_oid_tostr_s( &commitOid ) ) );
1404 details.
m_sha = git_oid_tostr_s( &commitOid );
1406 details.
m_author = git_commit_author( commit )->name;
1409 branchCommits.second.push_back( details );
1421 git_status_options opts;
1422 git_status_init_options( &opts, GIT_STATUS_OPTIONS_VERSION );
1425 opts.show = GIT_STATUS_SHOW_WORKDIR_ONLY;
1426 opts.flags = GIT_STATUS_OPT_INCLUDE_UNTRACKED;
1428 git_status_list* status_list =
nullptr;
1430 if( git_status_list_new( &status_list, aRepo, &opts ) != GIT_OK )
1437 size_t count = git_status_list_entrycount( status_list );
1440 for(
size_t ii = 0; ii < count; ++ii )
1442 const git_status_entry* entry = git_status_byindex( status_list, ii );
1445 if( entry->status & ( GIT_STATUS_WT_MODIFIED | GIT_STATUS_WT_DELETED | GIT_STATUS_WT_TYPECHANGE ) )
1454 size_t aMergeHeadsCount )
1459 aHandler->
AddErrorString(
_(
"Cannot merge: you have unstaged changes. Please commit or stash them "
1460 "before pulling." ) );
1464 git_repository* repo = aHandler->
GetRepo();
1466 if( git_merge( repo, aMergeHeads, aMergeHeadsCount,
nullptr,
nullptr ) )
1469 aHandler->
AddErrorString( wxString::Format(
_(
"Merge failed: %s" ), errorMsg ) );
1473 git_index*
index =
nullptr;
1475 if( git_repository_index( &
index, repo ) != GIT_OK )
1477 aHandler->
AddErrorString(
_(
"Could not read repository index after merge." ) );
1483 if( git_index_has_conflicts(
index ) )
1486 git_object* head_obj =
nullptr;
1488 if( git_revparse_single( &head_obj, repo,
"HEAD" ) == GIT_OK )
1491 git_reset( repo, head_obj, GIT_RESET_HARD,
nullptr );
1494 git_repository_state_cleanup( repo );
1500 git_tree* tree =
nullptr;
1501 git_reference* head_ref =
nullptr;
1503 git_commit* head_commit =
nullptr;
1504 git_commit* merge_commit =
nullptr;
1505 git_signature* signature =
nullptr;
1507 if( git_index_write_tree( &tree_oid,
index ) != GIT_OK || git_tree_lookup( &tree, repo, &tree_oid ) != GIT_OK )
1515 if( git_repository_head( &head_ref, repo ) != GIT_OK )
1517 aHandler->
AddErrorString(
_(
"Could not get the repository head." ) );
1523 if( git_reference_name_to_id( &head_oid, repo,
"HEAD" ) != GIT_OK
1524 || git_commit_lookup( &head_commit, repo, &head_oid ) != GIT_OK
1525 || git_commit_lookup( &merge_commit, repo, git_annotated_commit_id( aMergeHeads[0] ) ) != GIT_OK )
1527 aHandler->
AddErrorString(
_(
"Could not look up the commits to merge." ) );
1534 if( git_signature_default( &signature, repo ) != GIT_OK )
1536 aHandler->
AddErrorString(
_(
"Could not create a commit signature. Set user.name and user.email in your "
1537 "git configuration." ) );
1543 const git_commit* parents[] = { head_commit, merge_commit };
1544 wxString message = wxString::Format(
_(
"Merge remote-tracking branch into %s" ),
1545 git_reference_shorthand( head_ref ) );
1546 git_oid merge_commit_oid;
1548 if( git_commit_create( &merge_commit_oid, repo,
"HEAD", signature, signature,
nullptr,
1549 message.utf8_string().c_str(), tree, 2, parents ) != GIT_OK )
1551 aHandler->
AddErrorString( wxString::Format(
_(
"Could not create merge commit: %s" ),
1556 git_repository_state_cleanup( repo );
1562 size_t aMergeHeadsCount )
1567 aHandler->
AddErrorString(
_(
"Cannot pull with rebase: you have unstaged changes. Please commit or stash "
1568 "them before pulling." ) );
1572 git_rebase_options rebase_opts;
1573 git_rebase_init_options( &rebase_opts, GIT_REBASE_OPTIONS_VERSION );
1575 git_rebase* rebase =
nullptr;
1577 if( git_rebase_init( &rebase, aHandler->
GetRepo(),
nullptr, aMergeHeads[0],
nullptr, &rebase_opts ) )
1580 aHandler->
AddErrorString( wxString::Format(
_(
"Rebase failed to start: %s" ), errorMsg ) );
1588 git_rebase_operation* op =
nullptr;
1590 if( git_rebase_next( &op, rebase ) != 0 )
1593 if( git_rebase_commit(
nullptr, rebase,
nullptr,
nullptr,
nullptr,
nullptr ) )
1596 aHandler->
AddErrorString( wxString::Format(
_(
"Rebase commit failed: %s" ), errorMsg ) );
1601 if( git_rebase_finish( rebase,
nullptr ) )
1604 aHandler->
AddErrorString( wxString::Format(
_(
"Rebase finish failed: %s" ), errorMsg ) );
1614 git_repository* repo = aHandler->
GetRepo();
1615 git_reference* head_ref =
nullptr;
1617 if( git_repository_head( &head_ref, repo ) != GIT_OK )
1622 wxString remoteRef = wxString::Format(
"refs/remotes/%s/%s",
1624 git_reference_shorthand( head_ref ) );
1626 return git_reference_lookup( aUpstreamRef, repo, remoteRef.utf8_string().c_str() ) == GIT_OK;
1632 git_repository* repo = aHandler->
GetRepo();
1639 if( !lock.owns_lock() )
1641 aHandler->
AddErrorString(
_(
"Another git operation is in progress." ) );
1645 git_reference* upstream_ref =
nullptr;
1649 aHandler->
AddErrorString(
_(
"Could not find the matching remote branch." ) );
1654 git_object* target =
nullptr;
1656 if( git_reference_peel( &target, upstream_ref, GIT_OBJECT_COMMIT ) != GIT_OK )
1664 if( git_reset( repo, target, GIT_RESET_HARD,
nullptr ) != GIT_OK )
1666 aHandler->
AddErrorString( wxString::Format(
_(
"Could not reset to the remote branch: %s" ),
1671 git_repository_state_cleanup( repo );
1678 git_repository* repo = aHandler->
GetRepo();
1685 if( !lock.owns_lock() )
1687 aHandler->
AddErrorString(
_(
"Another git operation is in progress." ) );
1693 aHandler->
AddErrorString(
_(
"Cannot rebase: you have unstaged changes. Please commit or stash them "
1698 git_reference* upstream_ref =
nullptr;
1702 aHandler->
AddErrorString(
_(
"Could not find the matching remote branch." ) );
1707 git_annotated_commit* onto =
nullptr;
1709 if( git_annotated_commit_from_ref( &onto, repo, upstream_ref ) != GIT_OK )
1716 git_signature* signature =
nullptr;
1718 if( git_signature_default( &signature, repo ) != GIT_OK )
1720 aHandler->
AddErrorString(
_(
"Could not create a commit signature. Set user.name and user.email in your "
1721 "git configuration." ) );
1726 git_rebase_options rebase_opts;
1727 git_rebase_init_options( &rebase_opts, GIT_REBASE_OPTIONS_VERSION );
1728 git_rebase* rebase =
nullptr;
1730 if( git_rebase_init( &rebase, repo,
nullptr, onto,
nullptr, &rebase_opts ) != GIT_OK )
1732 aHandler->
AddErrorString( wxString::Format(
_(
"Rebase failed to start: %s" ),
1738 git_rebase_operation* op =
nullptr;
1740 while( git_rebase_next( &op, rebase ) == GIT_OK )
1742 git_index*
index =
nullptr;
1744 if( git_repository_index( &
index, repo ) == GIT_OK )
1748 if( git_index_has_conflicts(
index ) )
1750 git_rebase_abort( rebase );
1751 aHandler->
AddErrorString(
_(
"The rebase ran into conflicts. This is best resolved from a "
1752 "git command line." ) );
1759 if( git_rebase_commit( &commit_oid, rebase,
nullptr, signature,
nullptr,
nullptr ) != GIT_OK )
1761 git_rebase_abort( rebase );
1762 aHandler->
AddErrorString(
_(
"The rebase ran into conflicts. This is best resolved from a git "
1763 "command line." ) );
1768 if( git_rebase_finish( rebase, signature ) != GIT_OK )
1770 git_rebase_abort( rebase );
1771 aHandler->
AddErrorString( wxString::Format(
_(
"Rebase finish failed: %s" ),
1782 git_object* head_commit =
nullptr;
1783 git_checkout_options opts;
1784 git_checkout_init_options( &opts, GIT_CHECKOUT_OPTIONS_VERSION );
1786 if( git_revparse_single( &head_commit, aHandler->
m_repository,
"HEAD" ) != 0 )
1789 opts.checkout_strategy = GIT_CHECKOUT_FORCE;
1798 opts.progress_cb =
nullptr;
1799 opts.notify_cb =
nullptr;
1800 opts.notify_payload =
static_cast<void*
>( aHandler );
1802 if( git_checkout_tree( aHandler->
m_repository, head_commit, &opts ) != 0 )
1804 const git_error* e = git_error_last();
1807 wxLogTrace(
traceGit, wxS(
"Checkout failed: %d: %s" ), e->klass, e->message );
1811 delete( paths[ii] );
1815 git_object_free( head_commit );
1821 git_repository* repo =
nullptr;
1824 if( git_repository_discover( &repo_path, aFilename, 0,
nullptr ) != GIT_OK )
1826 wxLogTrace(
traceGit,
"Can't repo discover %s: %s", aFilename,
1833 if( git_repository_open( &repo, repo_path.ptr ) != GIT_OK )
1847 if(
int error = git_reference_name_to_id( &head_oid, aRepo,
"HEAD" ); error != GIT_OK )
1853 git_commit* commit =
nullptr;
1855 if(
int error = git_commit_lookup( &commit, aRepo, &head_oid ); error != GIT_OK )
1862 git_reference* branchRef =
nullptr;
1864 if(
int error = git_branch_create( &branchRef, aRepo, aBranchName.mb_str(), commit, 0 ); error != GIT_OK )
1870 git_reference_free( branchRef );
1880 git_repository_free( aRepo );
1886 wxFileName gitDir( aProjectPath, wxEmptyString );
1887 gitDir.AppendDir(
".git" );
1889 if( gitDir.DirExists() )
1898 wxLogTrace(
traceGit,
"Failed to remove .git directory: %s", errors );
1904 wxLogTrace(
traceGit,
"Successfully removed VCS from project" );
1911 git_repository* repo = aHandler->
GetRepo();
1913 git_index*
index =
nullptr;
1916 if( git_repository_index( &
index, repo ) != 0 )
1918 wxLogError(
"Failed to get repository index" );
1924 if( git_index_find( &at_pos,
index, aFilePath.ToUTF8().data() ) == GIT_OK )
1926 wxLogError(
"%s already in index", aFilePath );
1937 git_repository* repo = aHandler->
GetRepo();
1938 git_index*
index =
nullptr;
1942 if( git_repository_index( &
index, repo ) != 0 )
1944 wxLogError(
"Failed to get repository index" );
1954 if( git_index_add_bypath(
index, file.ToUTF8().data() ) != 0 )
1956 wxLogError(
"Failed to add %s to index", file );
1962 if( git_index_write(
index ) != 0 )
1964 wxLogError(
"Failed to write index" );
1977 git_repository* repo = aHandler->
GetRepo();
1978 git_index*
index =
nullptr;
1981 if( git_repository_index( &
index, repo ) != 0 )
1983 wxLogError(
"Failed to get repository index" );
1989 if( git_index_find( &at_pos,
index, aFilePath.ToUTF8().data() ) != 0 )
1991 wxLogError(
"Failed to find index entry for %s", aFilePath );
2002 git_repository* repo = aHandler->
GetRepo();
2006 git_index*
index =
nullptr;
2009 if( git_repository_index( &
index, repo ) != 0 )
2011 wxLogError(
"Failed to get repository index" );
2017 if( git_index_remove_bypath(
index, file.ToUTF8().data() ) != 0 )
2019 wxLogError(
"Failed to remove index entry for %s", file );
2023 if( git_index_write(
index ) != 0 )
2025 wxLogError(
"Failed to write index" );
2029 if( git_index_write_tree( &oid,
index ) != 0 )
2031 wxLogError(
"Failed to write index tree" );
std::vector< wxString > m_filesToAdd
std::vector< wxString > m_filesFailedToAdd
KIGIT_ORPHAN_REGISTRY m_orphanRegistry
wxString GetClonePath() const
void AddErrorString(const wxString &aErrorString)
std::vector< std::pair< std::string, std::vector< CommitDetails > > > m_fetchResults
std::vector< wxString > m_filesToRemove
std::vector< wxString > m_filesToRevert
git_repository * m_repository
KIGIT_COMMON::GIT_STATUS ConvertStatus(unsigned int aGitStatus)
Convert git status flags to KIGIT_COMMON::GIT_STATUS.
std::mutex m_gitActionMutex
static wxString GetLastGitError()
void SetSSHKey(const wxString &aSSHKey)
void SetUsername(const wxString &aUsername)
wxString GetRemoteNameOrDefault() const
Returns GetRemotename() when non-empty, otherwise "origin".
git_repository * GetRepo() const
void SetCancelled(bool aCancel)
void SetPassword(const wxString &aPassword)
void SetRemote(const wxString &aRemote)
void SetRepo(git_repository *aRepo)
void AddErrorString(const wxString aErrorString)
wxString GetProjectDir() const
Get the project directory path, preserving symlinks if set.
git_repository * GetRepo() const
Get a pointer to the git repository.
unsigned & TestedTypes()
Return the connection types that have been tested for authentication.
KIGIT_COMMON * GetCommon() const
Get the common object.
wxString GetRemotename() const
Get the remote name.
void ResetNextKey()
Reset the next public key to test.
bool PerformAddToIndex(GIT_ADD_TO_INDEX_HANDLER *aHandler) override
void PerformRevert(GIT_REVERT_HANDLER *aHandler) override
PullResult handleMerge(GIT_PULL_HANDLER *aHandler, const git_annotated_commit **aMergeHeads, size_t aMergeHeadsCount)
bool PerformFetch(GIT_PULL_HANDLER *aHandler, bool aSkipLock) override
static bool hasUnstagedChanges(git_repository *aRepo)
bool Clone(GIT_CLONE_HANDLER *aHandler) override
PullResult handleRebase(GIT_PULL_HANDLER *aHandler, const git_annotated_commit **aMergeHeads, size_t aMergeHeadsCount)
void PerformRemoveFromIndex(GIT_REMOVE_FROM_INDEX_HANDLER *aHandler) override
bool RemoveVCS(git_repository *&aRepo, const wxString &aProjectPath, bool aRemoveGitDir, wxString *aErrors) override
bool RemoveFromIndex(GIT_REMOVE_FROM_INDEX_HANDLER *aHandler, const wxString &aFilePath) override
BranchResult SwitchToBranch(GIT_BRANCH_HANDLER *aHandler, const wxString &aBranchName) override
PullResult handleFastForward(GIT_PULL_HANDLER *aHandler)
CommitResult Commit(GIT_COMMIT_HANDLER *aHandler, const std::vector< wxString > &aFiles, const wxString &aMessage, const wxString &aAuthorName, const wxString &aAuthorEmail) override
std::map< wxString, FileStatus > GetFileStatus(GIT_STATUS_HANDLER *aHandler, const wxString &aPathspec) override
bool HasChangedFiles(GIT_STATUS_HANDLER *aHandler) override
PullResult RebaseOntoUpstream(GIT_PULL_HANDLER *aHandler) override
void UpdateRemoteStatus(GIT_STATUS_HANDLER *aHandler, const std::set< wxString > &aLocalChanges, const std::set< wxString > &aRemoteChanges, std::map< wxString, FileStatus > &aFileStatus) override
wxString GetCurrentBranchName(GIT_STATUS_HANDLER *aHandler) override
bool GetConfigString(GIT_CONFIG_HANDLER *aHandler, const wxString &aKey, wxString &aValue) override
git_repository * GetRepositoryForFile(const char *aFilename) override
bool AddToIndex(GIT_ADD_TO_INDEX_HANDLER *aHandler, const wxString &aFilePath) override
bool SetupRemote(GIT_INIT_HANDLER *aHandler, const RemoteConfig &aConfig) override
bool IsRepository(GIT_INIT_HANDLER *aHandler, const wxString &aPath) override
bool IsLibraryAvailable() override
bool ResetToUpstream(GIT_PULL_HANDLER *aHandler) override
PushResult Push(GIT_PUSH_HANDLER *aHandler, bool aForce=false) override
wxString GetWorkingDirectory(GIT_STATUS_HANDLER *aHandler) override
bool BranchExists(GIT_BRANCH_HANDLER *aHandler, const wxString &aBranchName) override
CommitResult Amend(GIT_COMMIT_HANDLER *aHandler, const std::vector< wxString > &aFiles, const wxString &aMessage, const wxString &aAuthorName, const wxString &aAuthorEmail) override
InitResult InitializeRepository(GIT_INIT_HANDLER *aHandler, const wxString &aPath) override
PullResult PerformPull(GIT_PULL_HANDLER *aHandler) override
int CreateBranch(git_repository *aRepo, const wxString &aBranchName) override
bool RmDirRecursive(const wxString &aFileName, wxString *aErrors)
Remove the directory aDirName and all its contents including subdirectories and their files.
const wxChar *const traceGit
Flag to enable Git debugging output.
int fetchhead_foreach_cb(const char *, const char *, const git_oid *aOID, unsigned int aIsMerge, void *aPayload)
int progress_cb(const char *str, int len, void *aPayload)
int update_cb(const char *aRefname, const git_oid *aFirst, const git_oid *aSecond, void *aPayload)
int transfer_progress_cb(const git_transfer_progress *aStats, void *aPayload)
int credentials_cb(git_cred **aOut, const char *aUrl, const char *aUsername, unsigned int aAllowedTypes, void *aPayload)
void clone_progress_cb(const char *aStr, size_t aLen, size_t aTotal, void *aPayload)
int push_transfer_progress_cb(unsigned int aCurrent, unsigned int aTotal, size_t aBytes, void *aPayload)
static bool lookup_branch_reference(git_repository *repo, const wxString &aBranchName, git_reference **aReference)
static bool lookup_upstream_ref(GIT_PULL_HANDLER *aHandler, git_reference **aUpstreamRef)
static std::string getFormattedCommitDate(const git_time &aTime)
static std::string getFirstLineFromCommitMessage(const std::string &aMessage)
std::unique_ptr< git_tree, decltype([](git_tree *aTree) { git_tree_free(aTree); })> GitTreePtr
A unique pointer for git_tree objects with automatic cleanup.
std::unique_ptr< git_revwalk, decltype([](git_revwalk *aWalker) { git_revwalk_free(aWalker); })> GitRevWalkPtr
A unique pointer for git_revwalk objects with automatic cleanup.
std::unique_ptr< git_commit, decltype([](git_commit *aCommit) { git_commit_free(aCommit); })> GitCommitPtr
A unique pointer for git_commit objects with automatic cleanup.
std::unique_ptr< git_buf, decltype([](git_buf *aBuf) { git_buf_free(aBuf); })> GitBufPtr
A unique pointer for git_buf objects with automatic cleanup.
std::unique_ptr< git_annotated_commit, decltype([](git_annotated_commit *aCommit) { git_annotated_commit_free(aCommit); })> GitAnnotatedCommitPtr
A unique pointer for git_annotated_commit objects with automatic cleanup.
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_config, decltype([](git_config *aConfig) { git_config_free(aConfig); })> GitConfigPtr
A unique pointer for git_config 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.
std::unique_ptr< git_config_entry, decltype([](git_config_entry *aEntry) { git_config_entry_free(aEntry); })> GitConfigEntryPtr
A unique pointer for git_config_entry objects with automatic cleanup.
std::unique_ptr< git_signature, decltype([](git_signature *aSignature) { git_signature_free(aSignature); })> GitSignaturePtr
A unique pointer for git_signature objects with automatic cleanup.
std::unique_ptr< git_rebase, decltype([](git_rebase *aRebase) { git_rebase_free(aRebase); })> GitRebasePtr
A unique pointer for git_rebase objects with automatic cleanup.
std::unique_ptr< git_index, decltype([](git_index *aIndex) { git_index_free(aIndex); })> GitIndexPtr
A unique pointer for git_index objects with automatic cleanup.
std::unique_ptr< git_object, decltype([](git_object *aObject) { git_object_free(aObject); })> GitObjectPtr
A unique pointer for git_object objects with automatic cleanup.
std::unique_ptr< git_remote, decltype([](git_remote *aRemote) { git_remote_free(aRemote); })> GitRemotePtr
A unique pointer for git_remote objects with automatic cleanup.
KIGIT_COMMON::GIT_CONN_TYPE connType
wxString result
Test unit parsing edge cases and error handling.
wxLogTrace helper definitions.