43#include <wx/filename.h> 
   53    if( aMessage.empty() )
 
   56    size_t firstLineEnd = aMessage.find_first_of( 
'\n' );
 
   58    if( firstLineEnd != std::string::npos )
 
   59        return aMessage.substr( 0, firstLineEnd );
 
 
   67    time_t time = 
static_cast<time_t
>( aTime.time );
 
   70    localtime_s( &timeInfo, &time );
 
   72    gmtime_r( &time, &timeInfo );
 
   74    strftime( dateBuffer, 
sizeof( dateBuffer ), 
"%Y-%b-%d %H:%M:%S", &timeInfo );
 
 
   85    git_libgit2_shutdown();
 
 
   90#if ( LIBGIT2_VER_MAJOR >= 1 ) || ( LIBGIT2_VER_MINOR >= 99 ) 
   91    int major = 0, minor = 0, rev = 0;
 
   92    return git_libgit2_version( &major, &minor, &rev ) == GIT_OK;
 
 
  102    std::unique_lock<std::mutex> lock( common->
m_gitActionMutex, std::try_to_lock );
 
  104    if( !lock.owns_lock() )
 
  106        wxLogTrace( 
traceGit, 
"GIT_CLONE_HANDLER::PerformClone() could not lock" );
 
  112    if( !clonePath.DirExists() )
 
  114        if( !clonePath.Mkdir( wxS_DIR_DEFAULT, wxPATH_MKDIR_FULL ) )
 
  116            aHandler->
AddErrorString( wxString::Format( 
_( 
"Could not create directory '%s'" ),
 
  122    git_clone_options cloneOptions;
 
  123    git_clone_init_options( &cloneOptions, GIT_CLONE_OPTIONS_VERSION );
 
  124    cloneOptions.checkout_opts.checkout_strategy = GIT_CHECKOUT_SAFE;
 
  126    cloneOptions.checkout_opts.progress_payload = aHandler;
 
  129    cloneOptions.fetch_opts.callbacks.payload = aHandler;
 
  133    git_repository* newRepo = 
nullptr;
 
  136    if( git_clone( &newRepo, remote.mbc_str(), aHandler->
GetClonePath().mbc_str(),
 
  137                   &cloneOptions ) != 0 )
 
  139        aHandler->
AddErrorString( wxString::Format( 
_( 
"Could not clone repository '%s'" ), remote ) );
 
 
  149                                     const std::vector<wxString>& aFiles,
 
  150                                     const wxString& aMessage,
 
  151                                     const wxString& aAuthorName,
 
  152                                     const wxString& aAuthorEmail )
 
  154    git_repository* repo = aHandler->
GetRepo();
 
  159    git_index* index = 
nullptr;
 
  161    if( git_repository_index( &index, repo ) != 0 )
 
  163        aHandler->
AddErrorString( wxString::Format( 
_( 
"Failed to get repository index: %s" ),
 
  170    for( 
const wxString& file : aFiles )
 
  172        if( git_index_add_bypath( index, file.mb_str() ) != 0 )
 
  174            aHandler->
AddErrorString( wxString::Format( 
_( 
"Failed to add file to index: %s" ),
 
  180    if( git_index_write( index ) != 0 )
 
  182        aHandler->
AddErrorString( wxString::Format( 
_( 
"Failed to write index: %s" ),
 
  189    if( git_index_write_tree( &tree_id, index ) != 0 )
 
  191        aHandler->
AddErrorString( wxString::Format( 
_( 
"Failed to write tree: %s" ),
 
  196    git_tree* tree = 
nullptr;
 
  198    if( git_tree_lookup( &tree, repo, &tree_id ) != 0 )
 
  200        aHandler->
AddErrorString( wxString::Format( 
_( 
"Failed to lookup tree: %s" ),
 
  206    git_commit* parent = 
nullptr;
 
  208    if( git_repository_head_unborn( repo ) == 0 )
 
  210        git_reference* headRef = 
nullptr;
 
  212        if( git_repository_head( &headRef, repo ) != 0 )
 
  214            aHandler->
AddErrorString( wxString::Format( 
_( 
"Failed to get HEAD reference: %s" ),
 
  221        if( git_reference_peel( (git_object**) &parent, headRef, GIT_OBJECT_COMMIT ) != 0 )
 
  223            aHandler->
AddErrorString( wxString::Format( 
_( 
"Failed to get commit: %s" ),
 
  231    git_signature* author = 
nullptr;
 
  233    if( git_signature_now( &author, aAuthorName.mb_str(), aAuthorEmail.mb_str() ) != 0 )
 
  235        aHandler->
AddErrorString( wxString::Format( 
_( 
"Failed to create author signature: %s" ),
 
  242    size_t                 parentsCount = parent ? 1 : 0;
 
  243#if( LIBGIT2_VER_MAJOR == 1 && LIBGIT2_VER_MINOR == 8 \ 
  244    && ( LIBGIT2_VER_REVISION < 2 || LIBGIT2_VER_REVISION == 3 ) ) 
  245    git_commit* 
const parents[1] = { parent };
 
  246    git_commit** 
const parentsPtr = parent ? parents : 
nullptr;
 
  248    const git_commit* parents[1] = { parent };
 
  249    const git_commit** parentsPtr = parent ? parents : 
nullptr;
 
  254    if( git_commit_create( &oid, repo, 
"HEAD", author, author, 
nullptr,
 
  255                           aMessage.mb_str(), tree, parentsCount, parentsPtr ) != 0 )
 
  257        aHandler->
AddErrorString( wxString::Format( 
_( 
"Failed to create commit: %s" ),
 
 
  268    std::unique_lock<std::mutex> lock( common->
m_gitActionMutex, std::try_to_lock );
 
  270    if(!lock.owns_lock())
 
  272        wxLogTrace(
traceGit, 
"GIT_PUSH_HANDLER::PerformPush: Could not lock mutex");
 
  278    git_remote* remote = 
nullptr;
 
  280    if(git_remote_lookup(&remote, aHandler->
GetRepo(), 
"origin") != 0)
 
  288    git_remote_callbacks remoteCallbacks;
 
  289    git_remote_init_callbacks(&remoteCallbacks, GIT_REMOTE_CALLBACKS_VERSION);
 
  295    remoteCallbacks.payload = aHandler;
 
  301    if( git_remote_connect( remote, GIT_DIRECTION_PUSH, &remoteCallbacks, 
nullptr, 
nullptr ) )
 
  303        aHandler->
AddErrorString( wxString::Format( 
_( 
"Could not connect to remote: %s" ),
 
  308    git_push_options pushOptions;
 
  309    git_push_init_options( &pushOptions, GIT_PUSH_OPTIONS_VERSION );
 
  310    pushOptions.callbacks = remoteCallbacks;
 
  312    git_reference* head = 
nullptr;
 
  314    if( git_repository_head( &head, aHandler->
GetRepo() ) != 0 )
 
  316        git_remote_disconnect( remote );
 
  324    refs[0] = git_reference_name( head );
 
  325    const git_strarray refspecs = { (
char**) refs, 1 };
 
  327    if( git_remote_push( remote, &refspecs, &pushOptions ) )
 
  329        aHandler->
AddErrorString( wxString::Format( 
_( 
"Could not push to remote: %s" ),
 
  331        git_remote_disconnect( remote );
 
  335    git_remote_disconnect( remote );
 
 
  342    git_repository* repo = aHandler->
GetRepo();
 
  347    git_status_options opts;
 
  348    git_status_init_options( &opts, GIT_STATUS_OPTIONS_VERSION );
 
  350    opts.show = GIT_STATUS_SHOW_INDEX_AND_WORKDIR;
 
  351    opts.flags = GIT_STATUS_OPT_INCLUDE_UNTRACKED | GIT_STATUS_OPT_RENAMES_HEAD_TO_INDEX
 
  352                 | GIT_STATUS_OPT_SORT_CASE_SENSITIVELY;
 
  354    git_status_list* status_list = 
nullptr;
 
  356    if( git_status_list_new( &status_list, repo, &opts ) != GIT_OK )
 
  363    bool hasChanges = ( git_status_list_entrycount( status_list ) > 0 );
 
 
  369                                                              const wxString& aPathspec )
 
  371    std::map<wxString, FileStatus> fileStatusMap;
 
  372    git_repository* repo = aHandler->
GetRepo();
 
  375        return fileStatusMap;
 
  377    git_status_options status_options;
 
  378    git_status_init_options( &status_options, GIT_STATUS_OPTIONS_VERSION );
 
  379    status_options.show = GIT_STATUS_SHOW_INDEX_AND_WORKDIR;
 
  380    status_options.flags = GIT_STATUS_OPT_INCLUDE_UNTRACKED | GIT_STATUS_OPT_INCLUDE_UNMODIFIED;
 
  382    std::string pathspec_str;
 
  383    std::vector<const char*> pathspec_ptrs;
 
  385    if( !aPathspec.IsEmpty() )
 
  387        pathspec_str = aPathspec.ToStdString();
 
  388        pathspec_ptrs.push_back( pathspec_str.c_str() );
 
  390        status_options.pathspec.strings = 
const_cast<char**
>( pathspec_ptrs.data() );
 
  391        status_options.pathspec.count = pathspec_ptrs.size();
 
  394    git_status_list* status_list = 
nullptr;
 
  396    if( git_status_list_new( &status_list, repo, &status_options ) != GIT_OK )
 
  399        return fileStatusMap;
 
  404    size_t count = git_status_list_entrycount( status_list );
 
  405    wxString repoWorkDir( git_repository_workdir( repo ) );
 
  407    for( 
size_t ii = 0; ii < count; ++ii )
 
  409        const git_status_entry* entry = git_status_byindex( status_list, ii );
 
  410        std::string 
path( entry->head_to_index ? entry->head_to_index->old_file.path
 
  411                                               : entry->index_to_workdir->old_file.path );
 
  413        wxString absPath = repoWorkDir + 
path;
 
  414        fileStatusMap[absPath] = 
FileStatus{ absPath, aHandler->
ConvertStatus( entry->status ), 
static_cast<unsigned int>( entry->status ) };
 
  417    return fileStatusMap;
 
 
  422    git_repository* repo = aHandler->
GetRepo();
 
  425        return wxEmptyString;
 
  427    git_reference* currentBranchReference = 
nullptr;
 
  428    int rc = git_repository_head( ¤tBranchReference, repo );
 
  431    if( currentBranchReference )
 
  433        return git_reference_shorthand( currentBranchReference );
 
  435    else if( rc == GIT_EUNBORNBRANCH )
 
  437        return wxEmptyString;
 
  442        return wxEmptyString;
 
 
  447                                         const std::set<wxString>& aLocalChanges,
 
  448                                         const std::set<wxString>& aRemoteChanges,
 
  449                                         std::map<wxString, FileStatus>& aFileStatus )
 
  451    git_repository* repo = aHandler->
GetRepo();
 
  456    wxString repoWorkDir( git_repository_workdir( repo ) );
 
  458    for( 
auto& [absPath, fileStatus] : aFileStatus )
 
  460        wxString relativePath = absPath;
 
  461        if( relativePath.StartsWith( repoWorkDir ) )
 
  463            relativePath = relativePath.Mid( repoWorkDir.length() );
 
  465            relativePath.Replace( wxS( 
"\\" ), wxS( 
"/" ) );
 
  469        std::string relativePathStd = relativePath.ToStdString();
 
  473            if( aLocalChanges.count( relativePathStd ) )
 
  477            else if( aRemoteChanges.count( relativePathStd ) )
 
 
  487    git_repository* repo = aHandler->
GetRepo();
 
  490        return wxEmptyString;
 
  492    const char* workdir = git_repository_workdir( repo );
 
  495        return wxEmptyString;
 
  497    return wxString( workdir );
 
 
  502    git_repository* repo = aHandler->
GetRepo();
 
  505        return wxEmptyString;
 
  507    const char* workdir = git_repository_workdir( repo );
 
  510        return wxEmptyString;
 
  512    return wxString( workdir );
 
 
  518    git_repository* repo = aHandler->
GetRepo();
 
  523    git_config* 
config = 
nullptr;
 
  525    if( git_repository_config( &
config, repo ) != GIT_OK )
 
  533    git_config_entry* entry = 
nullptr;
 
  534    int result = git_config_get_entry( &entry, 
config, aKey.mb_str() );
 
  537    if( 
result != GIT_OK || entry == 
nullptr )
 
  539        wxLogTrace( 
traceGit, 
"Config key '%s' not found", aKey );
 
  543    aValue = wxString( entry->value );
 
 
  549    git_repository* repo = 
nullptr;
 
  550    int error = git_repository_open( &repo, aPath.mb_str() );
 
  554        git_repository_free( repo );
 
 
  568    git_repository* repo = 
nullptr;
 
  570    if( git_repository_init( &repo, aPath.mb_str(), 0 ) != GIT_OK )
 
  573            git_repository_free( repo );
 
  575        aHandler->
AddErrorString( wxString::Format( 
_( 
"Failed to initialize Git repository: %s" ),
 
  582    wxLogTrace( 
traceGit, 
"Successfully initialized Git repository at %s", aPath );
 
 
  588    if( aConfig.
url.IsEmpty() )
 
  591    git_repository* repo = aHandler->
GetRepo();
 
  595        aHandler->
AddErrorString( 
_( 
"No repository available to set up remote" ) );
 
  603    git_remote* remote = 
nullptr;
 
  612        fullURL = aConfig.
url.StartsWith( 
"https" ) ? 
"https://" : 
"http://";
 
  620                fullURL.append( wxS( 
":" ) );
 
  624            fullURL.append( wxS( 
"@" ) );
 
  627        wxString bareURL = aConfig.
url;
 
  628        if( bareURL.StartsWith( 
"https://" ) )
 
  629            bareURL = bareURL.Mid( 8 );
 
  630        else if( bareURL.StartsWith( 
"http://" ) )
 
  631            bareURL = bareURL.Mid( 7 );
 
  633        fullURL.append( bareURL );
 
  637        fullURL = aConfig.
url;
 
  640    int error = git_remote_create_with_fetchspec( &remote, repo, 
"origin",
 
  641                                                  fullURL.ToStdString().c_str(),
 
  642                                                  "+refs/heads/*:refs/remotes/origin/*" );
 
  646    if( error != GIT_OK )
 
  648        aHandler->
AddErrorString( wxString::Format( 
_( 
"Failed to create remote: %s" ),
 
  653    wxLogTrace( 
traceGit, 
"Successfully set up remote origin" );
 
 
  658                                     git_reference** aReference )
 
  660    if( git_reference_lookup( aReference, repo, aBranchName.mb_str() ) == GIT_OK )
 
  663    if( git_reference_dwim( aReference, repo, aBranchName.mb_str() ) == GIT_OK )
 
 
  671    git_repository* repo = aHandler->
GetRepo();
 
  679    git_reference* branchRef = 
nullptr;
 
  683        aHandler->
AddErrorString( wxString::Format( 
_( 
"Failed to lookup branch '%s': %s" ),
 
  689    const char* branchRefName = git_reference_name( branchRef );
 
  690    git_object* branchObj = 
nullptr;
 
  692    if( git_revparse_single( &branchObj, repo, aBranchName.mb_str() ) != GIT_OK )
 
  694        aHandler->
AddErrorString( wxString::Format( 
_( 
"Failed to find branch head for '%s': %s" ),
 
  701    if( git_checkout_tree( repo, branchObj, 
nullptr ) != GIT_OK )
 
  703        aHandler->
AddErrorString( wxString::Format( 
_( 
"Failed to switch to branch '%s': %s" ),
 
  708    if( git_repository_set_head( repo, branchRefName ) != GIT_OK )
 
  710        aHandler->
AddErrorString( wxString::Format( 
_( 
"Failed to update HEAD reference for branch '%s': %s" ),
 
  715    wxLogTrace( 
traceGit, 
"Successfully switched to branch '%s'", aBranchName );
 
 
  721    git_repository* repo = aHandler->
GetRepo();
 
  726    git_reference* branchRef = 
nullptr;
 
  730        git_reference_free( branchRef );
 
 
  741        wxLogTrace( 
traceGit, 
"GIT_PULL_HANDLER::PerformFetch() - No repository found" );
 
  747    if( !aSkipLock && !lock.owns_lock() )
 
  749        wxLogTrace( 
traceGit, 
"GIT_PULL_HANDLER::PerformFetch() - Could not lock mutex" );
 
  753    git_remote* remote = 
nullptr;
 
  755    if( git_remote_lookup( &remote, aHandler->
GetRepo(), 
"origin" ) != 0 )
 
  757        wxLogTrace( 
traceGit, 
"GIT_PULL_HANDLER::PerformFetch() - Failed to lookup remote 'origin'" );
 
  758        aHandler->
AddErrorString( wxString::Format( 
_( 
"Could not lookup remote '%s'" ), 
"origin" ) );
 
  764    git_remote_callbacks remoteCallbacks;
 
  765    git_remote_init_callbacks( &remoteCallbacks, GIT_REMOTE_CALLBACKS_VERSION );
 
  769    remoteCallbacks.payload = aHandler;
 
  775    if( git_remote_connect( remote, GIT_DIRECTION_FETCH, &remoteCallbacks, 
nullptr, 
nullptr ) )
 
  778        wxLogTrace( 
traceGit, 
"GIT_PULL_HANDLER::PerformFetch() - Failed to connect to remote: %s", errorMsg );
 
  779        aHandler->
AddErrorString( wxString::Format( 
_( 
"Could not connect to remote '%s': %s" ), 
"origin", errorMsg ) );
 
  783    git_fetch_options fetchOptions;
 
  784    git_fetch_init_options( &fetchOptions, GIT_FETCH_OPTIONS_VERSION );
 
  785    fetchOptions.callbacks = remoteCallbacks;
 
  787    if( git_remote_fetch( remote, 
nullptr, &fetchOptions, 
nullptr ) )
 
  790        wxLogTrace( 
traceGit, 
"GIT_PULL_HANDLER::PerformFetch() - Failed to fetch from remote: %s", errorMsg );
 
  791        aHandler->
AddErrorString( wxString::Format( 
_( 
"Could not fetch data from remote '%s': %s" ), 
"origin", errorMsg ) );
 
  795    wxLogTrace( 
traceGit, 
"GIT_PULL_HANDLER::PerformFetch() - Fetch completed successfully" );
 
 
  804    if( !lock.owns_lock() )
 
  806        wxLogTrace( 
traceGit, 
"GIT_PULL_HANDLER::PerformPull() - Could not lock mutex" );
 
  813    git_oid pull_merge_oid = {};
 
  822    git_annotated_commit* fetchhead_commit;
 
  824    if( git_annotated_commit_lookup( &fetchhead_commit, aHandler->
GetRepo(), &pull_merge_oid ) )
 
  831    const git_annotated_commit* merge_commits[] = { fetchhead_commit };
 
  832    git_merge_analysis_t        merge_analysis;
 
  833    git_merge_preference_t      merge_preference = GIT_MERGE_PREFERENCE_NONE;
 
  835    if( git_merge_analysis( &merge_analysis, &merge_preference, aHandler->
GetRepo(), merge_commits, 1 ) )
 
  841    if( merge_analysis & GIT_MERGE_ANALYSIS_UNBORN )
 
  847    if( merge_analysis & GIT_MERGE_ANALYSIS_UP_TO_DATE )
 
  849        wxLogTrace( 
traceGit, 
"GIT_PULL_HANDLER::PerformPull() - Repository is up to date" );
 
  850        git_repository_state_cleanup( aHandler->
GetRepo() );
 
  854    if( merge_analysis & GIT_MERGE_ANALYSIS_FASTFORWARD )
 
  856        wxLogTrace( 
traceGit, 
"GIT_PULL_HANDLER::PerformPull() - Fast-forward merge" );
 
  860    if( merge_analysis & GIT_MERGE_ANALYSIS_NORMAL )
 
  862        wxLogTrace( 
traceGit, 
"GIT_PULL_HANDLER::PerformPull() - Normal merge" );
 
  864        git_config* 
config = 
nullptr;
 
  866        if( git_repository_config( &
config, aHandler->
GetRepo() ) != GIT_OK )
 
  868            wxLogTrace( 
traceGit, 
"GIT_PULL_HANDLER::PerformPull() - Failed to get repository config" );
 
  869            aHandler->
AddErrorString( 
_( 
"Could not access repository configuration" ) );
 
  875        int rebase_value = 0;
 
  876        int ret = git_config_get_bool( &rebase_value, 
config, 
"pull.rebase" );
 
  878        if( ret == GIT_OK && rebase_value )
 
  880            wxLogTrace( 
traceGit, 
"GIT_PULL_HANDLER::PerformPull() - Using rebase based on config" );
 
  884        wxLogTrace( 
traceGit, 
"GIT_PULL_HANDLER::PerformPull() - Using merge based on config" );
 
  888    wxLogTrace( 
traceGit, 
"GIT_PULL_HANDLER::PerformPull() - Merge needs resolution" );
 
 
  894    git_reference* rawRef = 
nullptr;
 
  896    if( git_repository_head( &rawRef, aHandler->
GetRepo() ) )
 
  904    git_oid     updatedRefOid;
 
  905    const char* currentBranchName = git_reference_name( rawRef );
 
  906    const char* branch_shorthand = git_reference_shorthand( rawRef );
 
  908    wxString remoteBranchName = wxString::Format( 
"refs/remotes/%s/%s", remote_name, branch_shorthand );
 
  910    if( git_reference_name_to_id( &updatedRefOid, aHandler->
GetRepo(), remoteBranchName.c_str() ) != GIT_OK )
 
  912        aHandler->
AddErrorString( wxString::Format( 
_( 
"Could not get reference OID for reference '%s'" ),
 
  913                                                   remoteBranchName ) );
 
  917    git_commit* targetCommit = 
nullptr;
 
  919    if( git_commit_lookup( &targetCommit, aHandler->
GetRepo(), &updatedRefOid ) != GIT_OK )
 
  927    git_tree* targetTree = 
nullptr;
 
  929    if( git_commit_tree( &targetTree, targetCommit ) != GIT_OK )
 
  931        git_commit_free( targetCommit );
 
  932        aHandler->
AddErrorString( 
_( 
"Could not get tree from target commit" ) );
 
  938    git_checkout_options checkoutOptions;
 
  939    git_checkout_init_options( &checkoutOptions, GIT_CHECKOUT_OPTIONS_VERSION );
 
  940    auto notify_cb = []( git_checkout_notify_t why, 
const char* 
path, 
const git_diff_file* baseline,
 
  941                         const git_diff_file* target, 
const git_diff_file* workdir, 
void* payload ) -> 
int 
  945        case GIT_CHECKOUT_NOTIFY_CONFLICT:
 
  948        case GIT_CHECKOUT_NOTIFY_DIRTY:
 
  951        case GIT_CHECKOUT_NOTIFY_UPDATED:
 
  954        case GIT_CHECKOUT_NOTIFY_UNTRACKED:
 
  957        case GIT_CHECKOUT_NOTIFY_IGNORED:
 
  967    checkoutOptions.checkout_strategy = GIT_CHECKOUT_SAFE | GIT_CHECKOUT_ALLOW_CONFLICTS;
 
  968    checkoutOptions.notify_flags = GIT_CHECKOUT_NOTIFY_ALL;
 
  969    checkoutOptions.notify_cb = notify_cb;
 
  971    if( git_checkout_tree( aHandler->
GetRepo(), 
reinterpret_cast<git_object*
>( targetTree ), &checkoutOptions ) != GIT_OK )
 
  973        aHandler->
AddErrorString( 
_( 
"Failed to perform checkout operation." ) );
 
  977    git_reference* updatedRef = 
nullptr;
 
  979    if( git_reference_set_target( &updatedRef, rawRef, &updatedRefOid, 
nullptr ) != GIT_OK )
 
  981        aHandler->
AddErrorString( wxString::Format( 
_( 
"Failed to update reference '%s' to point to '%s'" ),
 
  982                                                   currentBranchName, git_oid_tostr_s( &updatedRefOid ) ) );
 
  988    if( git_repository_state_cleanup( aHandler->
GetRepo() ) != GIT_OK )
 
  990        aHandler->
AddErrorString( 
_( 
"Failed to clean up repository state after fast-forward." ) );
 
  994    git_revwalk* revWalker = 
nullptr;
 
  996    if( git_revwalk_new( &revWalker, aHandler->
GetRepo() ) != GIT_OK )
 
  998        aHandler->
AddErrorString( 
_( 
"Failed to initialize revision walker." ) );
 
 1003    git_revwalk_sorting( revWalker, GIT_SORT_TIME );
 
 1005    if( git_revwalk_push_glob( revWalker, currentBranchName ) != GIT_OK )
 
 1007        aHandler->
AddErrorString( 
_( 
"Failed to push reference to revision walker." ) );
 
 1011    std::pair<std::string, std::vector<CommitDetails>>& branchCommits = aHandler->
m_fetchResults.emplace_back();
 
 1012    branchCommits.first = currentBranchName;
 
 1016    while( git_revwalk_next( &commitOid, revWalker ) == GIT_OK )
 
 1018        git_commit* commit = 
nullptr;
 
 1020        if( git_commit_lookup( &commit, aHandler->
GetRepo(), &commitOid ) )
 
 1022            aHandler->
AddErrorString( wxString::Format( 
_( 
"Could not lookup commit '%s'" ),
 
 1023                                                        git_oid_tostr_s( &commitOid ) ) );
 
 1030        details.
m_sha = git_oid_tostr_s( &commitOid );
 
 1032        details.
m_author = git_commit_author( commit )->name;
 
 1035        branchCommits.second.push_back( details );
 
 
 1042                                        const git_annotated_commit** aMergeHeads,
 
 1043                                        size_t aMergeHeadsCount )
 
 1045    if( git_merge( aHandler->
GetRepo(), aMergeHeads, aMergeHeadsCount, 
nullptr, 
nullptr ) )
 
 
 1055                                         const git_annotated_commit** aMergeHeads,
 
 1056                                         size_t aMergeHeadsCount )
 
 1058    git_rebase_options rebase_opts;
 
 1059    git_rebase_init_options( &rebase_opts, GIT_REBASE_OPTIONS_VERSION );
 
 1061    git_rebase* rebase = 
nullptr;
 
 1063    if( git_rebase_init( &rebase, aHandler->
GetRepo(), 
nullptr, aMergeHeads[0], 
nullptr, &rebase_opts ) )
 
 1073        git_rebase_operation* op = 
nullptr;
 
 1074        if( git_rebase_next( &op, rebase ) != 0 )
 
 1077        if( git_rebase_commit( 
nullptr, rebase, 
nullptr, 
nullptr, 
nullptr, 
nullptr ) )
 
 1084    if( git_rebase_finish( rebase, 
nullptr ) )
 
 
 1095    git_object* head_commit = NULL;
 
 1096    git_checkout_options opts;
 
 1097    git_checkout_init_options( &opts, GIT_CHECKOUT_OPTIONS_VERSION );
 
 1099    if( git_revparse_single( &head_commit, aHandler->
m_repository, 
"HEAD" ) != 0 )
 
 1104    opts.checkout_strategy = GIT_CHECKOUT_FORCE;
 
 1115    opts.progress_cb = 
nullptr;
 
 1116    opts.notify_cb = 
nullptr;
 
 1117    opts.notify_payload = 
static_cast<void*
>( aHandler );
 
 1119    if( git_checkout_tree( aHandler->
m_repository, head_commit, &opts ) != 0 )
 
 1121        const git_error* e = git_error_last();
 
 1125            wxLogTrace( 
traceGit, wxS( 
"Checkout failed: %d: %s" ), e->klass, e->message );
 
 1130        delete( paths[ii] );
 
 1134    git_object_free( head_commit );
 
 
 1139    git_repository* repo = 
nullptr;
 
 1142    if( git_repository_discover( &repo_path, aFilename, 0, 
nullptr ) != GIT_OK )
 
 1144        wxLogTrace( 
traceGit, 
"Can't repo discover %s: %s", aFilename,
 
 1151    if( git_repository_open( &repo, repo_path.ptr ) != GIT_OK )
 
 1153        wxLogTrace( 
traceGit, 
"Can't open repo for %s: %s", repo_path.ptr,
 
 
 1165    if( 
int error = git_reference_name_to_id( &head_oid, aRepo, 
"HEAD" ); error != GIT_OK )
 
 1167        wxLogTrace( 
traceGit, 
"Failed to lookup HEAD reference: %s",
 
 1172    git_commit* commit = 
nullptr;
 
 1174    if( 
int error = git_commit_lookup( &commit, aRepo, &head_oid ); error != GIT_OK )
 
 1176        wxLogTrace( 
traceGit, 
"Failed to lookup commit: %s",
 
 1182    git_reference* branchRef = 
nullptr;
 
 1184    if( 
int error = git_branch_create( &branchRef, aRepo, aBranchName.mb_str(), commit, 0 ); error != GIT_OK )
 
 1186        wxLogTrace( 
traceGit, 
"Failed to create branch: %s",
 
 1191    git_reference_free( branchRef );
 
 
 1196                                bool aRemoveGitDir, wxString* aErrors )
 
 1200        git_repository_free( aRepo );
 
 1206        wxFileName gitDir( aProjectPath, wxEmptyString );
 
 1207        gitDir.AppendDir( 
".git" );
 
 1209        if( gitDir.DirExists() )
 
 1217                wxLogTrace( 
traceGit, 
"Failed to remove .git directory: %s", errors );
 
 1223    wxLogTrace( 
traceGit, 
"Successfully removed VCS from project" );
 
 
 1229    git_repository* repo = aHandler->
GetRepo();
 
 1231    git_index* index = 
nullptr;
 
 1234    if( git_repository_index( &index, repo ) != 0 )
 
 1236        wxLogError( 
"Failed to get repository index" );
 
 1242    if( git_index_find( &at_pos, index, aFilePath.ToUTF8().data() ) == GIT_OK )
 
 1244        wxLogError( 
"%s already in index", aFilePath );
 
 
 1254    git_repository* repo = aHandler->
GetRepo();
 
 1255    git_index* index = 
nullptr;
 
 1259    if( git_repository_index( &index, repo ) != 0 )
 
 1261        wxLogError( 
"Failed to get repository index" );
 
 1271        if( git_index_add_bypath( index, file.ToUTF8().data() ) != 0 )
 
 1273            wxLogError( 
"Failed to add %s to index", file );
 
 1279    if( git_index_write( index ) != 0 )
 
 1281        wxLogError( 
"Failed to write index" );
 
 
 1292                                      const wxString& aFilePath )
 
 1294    git_repository* repo = aHandler->
GetRepo();
 
 1295    git_index*      index = 
nullptr;
 
 1298    if( git_repository_index( &index, repo ) != 0 )
 
 1300        wxLogError( 
"Failed to get repository index" );
 
 1306    if( git_index_find( &at_pos, index, aFilePath.ToUTF8().data() ) != 0 )
 
 1308        wxLogError( 
"Failed to find index entry for %s", aFilePath );
 
 
 1318    git_repository* repo = aHandler->
GetRepo();
 
 1322        git_index* index = 
nullptr;
 
 1325        if( git_repository_index( &index, repo ) != 0 )
 
 1327            wxLogError( 
"Failed to get repository index" );
 
 1333        if( git_index_remove_bypath( index, file.ToUTF8().data() ) != 0 )
 
 1335            wxLogError( 
"Failed to remove index entry for %s", file );
 
 1339        if( git_index_write( index ) != 0 )
 
 1341            wxLogError( 
"Failed to write index" );
 
 1345        if( git_index_write_tree( &oid, index ) != 0 )
 
 1347            wxLogError( 
"Failed to write index tree" );
 
 
std::vector< wxString > m_filesToAdd
 
std::vector< wxString > m_filesFailedToAdd
 
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)
 
git_repository * GetRepo() const
 
void SetCancelled(bool aCancel)
 
void SetPassword(const wxString &aPassword)
 
void SetRepo(git_repository *aRepo)
 
void AddErrorString(const wxString aErrorString)
 
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
 
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
 
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
 
PushResult Push(GIT_PUSH_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
 
wxString GetWorkingDirectory(GIT_STATUS_HANDLER *aHandler) override
 
bool BranchExists(GIT_BRANCH_HANDLER *aHandler, const wxString &aBranchName) 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 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.