43 git_remote* remote =
nullptr;
45 if( git_remote_lookup( &remote,
m_repo,
"origin" ) != 0 )
47 AddErrorString( wxString::Format(
_(
"Could not lookup remote '%s'" ),
"origin" ) );
51 git_remote_callbacks remoteCallbacks;
52 git_remote_init_callbacks( &remoteCallbacks, GIT_REMOTE_CALLBACKS_VERSION );
56 remoteCallbacks.payload =
this;
61 if( git_remote_connect( remote, GIT_DIRECTION_FETCH, &remoteCallbacks,
nullptr,
nullptr ) )
63 git_remote_free( remote );
64 AddErrorString( wxString::Format(
_(
"Could not connect to remote '%s': %s" ),
"origin",
65 git_error_last()->message ) );
69 git_fetch_options fetchOptions;
70 git_fetch_init_options( &fetchOptions, GIT_FETCH_OPTIONS_VERSION );
71 fetchOptions.callbacks = remoteCallbacks;
73 if( git_remote_fetch( remote,
nullptr, &fetchOptions,
nullptr ) )
75 git_remote_free( remote );
76 AddErrorString( wxString::Format(
_(
"Could not fetch data from remote '%s': %s" ),
77 "origin", git_error_last()->message ) );
81 git_remote_free( remote );
92 return PullResult::Error;
94 git_oid pull_merge_oid = {};
99 return PullResult::Error;
102 git_annotated_commit* fetchhead_commit;
104 if( git_annotated_commit_lookup( &fetchhead_commit,
m_repo, &pull_merge_oid ) )
107 return PullResult::Error;
110 const git_annotated_commit* merge_commits[] = { fetchhead_commit };
111 git_merge_analysis_t merge_analysis;
112 git_merge_preference_t merge_preference = GIT_MERGE_PREFERENCE_NONE;
114 if( git_merge_analysis( &merge_analysis, &merge_preference,
m_repo, merge_commits, 1 ) )
117 git_annotated_commit_free( fetchhead_commit );
118 return PullResult::Error;
121 if( !( merge_analysis & GIT_MERGE_ANALYSIS_NORMAL ) )
122 git_annotated_commit_free( fetchhead_commit );
124 if( merge_analysis & GIT_MERGE_ANALYSIS_UNBORN )
127 return PullResult::MergeFailed;
131 if( merge_analysis & GIT_MERGE_ANALYSIS_UP_TO_DATE )
133 git_repository_state_cleanup(
m_repo );
134 return PullResult::UpToDate;
138 if( merge_analysis & GIT_MERGE_ANALYSIS_FASTFORWARD )
143 if( merge_analysis & GIT_MERGE_ANALYSIS_NORMAL )
146 git_annotated_commit_free( fetchhead_commit );
155const std::vector<std::pair<std::string, std::vector<CommitDetails>>>&
164 size_t firstLineEnd = aMessage.find_first_of(
'\n' );
166 if( firstLineEnd != std::string::npos )
167 return aMessage.substr( 0, firstLineEnd );
176 time_t time =
static_cast<time_t
>( aTime.time );
177 strftime( dateBuffer,
sizeof( dateBuffer ),
"%Y-%b-%d %H:%M:%S", gmtime( &time ) );
185 auto git_reference_deleter =
188 git_reference_free(
static_cast<git_reference*
>( p ) );
191 git_reference* rawRef =
nullptr;
193 if( git_repository_head( &rawRef,
m_repo ) )
196 return PullResult::Error;
201 std::unique_ptr<git_reference,
decltype( git_reference_deleter )> updatedRef( rawRef );
203 const char* updatedRefName = git_reference_name( updatedRef.get() );
205 git_oid updatedRefOid;
207 if( git_reference_name_to_id( &updatedRefOid,
m_repo, updatedRefName ) )
209 AddErrorString( wxString::Format(
_(
"Could not get reference OID for reference '%s'" ),
211 return PullResult::Error;
214 git_checkout_options checkoutOptions;
215 git_checkout_init_options( &checkoutOptions, GIT_CHECKOUT_OPTIONS_VERSION );
216 checkoutOptions.checkout_strategy = GIT_CHECKOUT_SAFE;
218 if( git_checkout_head(
m_repo, &checkoutOptions ) )
221 return PullResult::Error;
225 git_revwalk* revWalker =
nullptr;
226 git_revwalk_new( &revWalker,
m_repo );
227 git_revwalk_sorting( revWalker, GIT_SORT_TIME );
228 git_revwalk_push_glob( revWalker, updatedRefName );
232 while( git_revwalk_next( &commitOid, revWalker ) == 0 )
234 git_commit* commit =
nullptr;
236 if( git_commit_lookup( &commit,
m_repo, &commitOid ) )
239 git_oid_tostr_s( &commitOid ) ) );
240 git_revwalk_free( revWalker );
241 return PullResult::Error;
245 details.
m_sha = git_oid_tostr_s( &commitOid );
247 details.
m_author = git_commit_author( commit )->name;
250 std::pair<std::string, std::vector<CommitDetails>>& branchCommits =
252 branchCommits.first = updatedRefName;
253 branchCommits.second.push_back( details );
256 git_commit_free( commit );
259 git_revwalk_free( revWalker );
261 git_repository_state_cleanup(
m_repo );
262 return PullResult::FastForward;
267 size_t aMergeHeadsCount )
269 git_merge_options merge_opts;
270 git_merge_options_init( &merge_opts, GIT_MERGE_OPTIONS_VERSION );
272 git_checkout_options checkout_opts;
273 git_checkout_init_options( &checkout_opts, GIT_CHECKOUT_OPTIONS_VERSION );
275 checkout_opts.checkout_strategy = GIT_CHECKOUT_SAFE;
277 if( git_merge(
m_repo, aMergeHeads, aMergeHeadsCount, &merge_opts, &checkout_opts ) )
280 return PullResult::Error;
284 git_index* index =
nullptr;
286 if( git_repository_index( &index,
m_repo ) )
289 return PullResult::Error;
293 git_index_conflict_iterator* conflicts =
nullptr;
295 if( git_index_conflict_iterator_new( &conflicts, index ) )
298 return PullResult::Error;
301 const git_index_entry* ancestor =
nullptr;
302 const git_index_entry* our =
nullptr;
303 const git_index_entry* their =
nullptr;
304 std::vector<ConflictData> conflict_data;
306 while( git_index_conflict_next( &ancestor, &our, &their, conflicts ) == 0 )
309 if( ancestor && our && their )
312 conflict_datum.
filename = our->path;
313 conflict_datum.
our_oid = our->id;
321 conflict_data.push_back( conflict_datum );
324 else if( !ancestor && our && their )
327 conflict_datum.
filename = our->path;
328 conflict_datum.
our_oid = our->id;
336 conflict_data.push_back( conflict_datum );
339 else if( their && !our )
342 git_index_add( index, their );
345 else if( our && !their )
348 git_index_add( index, our );
352 wxLogError( wxS(
"Unexpected conflict state" ) );
356 if( conflict_data.empty() )
358 git_index_conflict_cleanup( index );
359 git_index_write( index );
362 git_index_conflict_iterator_free( conflicts );
363 git_index_free( index );
365 return conflict_data.empty() ? PullResult::Success : PullResult::MergeFailed;
void ReportProgress(int aCurrent, int aTotal, const wxString &aMessage)
std::string getFirstLineFromCommitMessage(const std::string &aMessage)
PullResult handleFastForward()
PullResult handleMerge(const git_annotated_commit **aMergeHeads, size_t aMergeHeadsCount)
const std::vector< std::pair< std::string, std::vector< CommitDetails > > > & GetFetchResults() const
GIT_PULL_HANDLER(KIGIT_COMMON *aCommon)
void UpdateProgress(int aCurrent, int aTotal, const wxString &aMessage) override
std::string getFormattedCommitDate(const git_time &aTime)
std::vector< std::pair< std::string, std::vector< CommitDetails > > > m_fetchResults
void AddErrorString(const wxString aErrorString)
int fetchhead_foreach_cb(const char *, const char *, const git_oid *aOID, unsigned int aIsMerge, 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)
int progress_cb(const char *str, int len, void *data)
git_time_t their_commit_time
git_time_t our_commit_time