diff --git a/common/git/git_pull_handler.cpp b/common/git/git_pull_handler.cpp index bedc30b0dd..fd0fcf21e2 100644 --- a/common/git/git_pull_handler.cpp +++ b/common/git/git_pull_handler.cpp @@ -378,6 +378,14 @@ PullResult GIT_PULL_HANDLER::handleFastForward() PullResult GIT_PULL_HANDLER::handleMerge( const git_annotated_commit** aMergeHeads, size_t aMergeHeadsCount ) { + if( hasUnstagedChanges( GetRepo() ) ) + { + AddErrorString( + _( "Cannot merge: you have unstaged changes. " + "Please commit or stash them before pulling." ) ); + return PullResult::DirtyWorkdir; + } + git_merge_options merge_opts; git_merge_options_init( &merge_opts, GIT_MERGE_OPTIONS_VERSION ); @@ -481,6 +489,14 @@ PullResult GIT_PULL_HANDLER::handleMerge( const git_annotated_commit** aMergeHea PullResult GIT_PULL_HANDLER::handleRebase( const git_annotated_commit** aMergeHeads, size_t aMergeHeadsCount ) { + if( hasUnstagedChanges( GetRepo() ) ) + { + AddErrorString( + _( "Cannot rebase: you have unstaged changes. " + "Please commit or stash them before pulling." ) ); + return PullResult::DirtyWorkdir; + } + // Get the current branch reference git_reference* head_ref = nullptr; @@ -563,6 +579,40 @@ PullResult GIT_PULL_HANDLER::handleRebase( const git_annotated_commit** aMergeHe } +bool GIT_PULL_HANDLER::hasUnstagedChanges( git_repository* aRepo ) +{ + if( !aRepo ) + return false; + + git_status_options opts; + git_status_init_options( &opts, GIT_STATUS_OPTIONS_VERSION ); + + opts.show = GIT_STATUS_SHOW_WORKDIR_ONLY; + opts.flags = GIT_STATUS_OPT_INCLUDE_UNTRACKED; + + git_status_list* status_list = nullptr; + + if( git_status_list_new( &status_list, aRepo, &opts ) != GIT_OK ) + { + wxLogTrace( traceGit, "Failed to get status list: %s", KIGIT_COMMON::GetLastGitError() ); + return false; + } + + KIGIT::GitStatusListPtr status_list_ptr( status_list ); + size_t count = git_status_list_entrycount( status_list ); + + for( size_t ii = 0; ii < count; ++ii ) + { + const git_status_entry* entry = git_status_byindex( status_list, ii ); + + if( entry->status & ( GIT_STATUS_WT_MODIFIED | GIT_STATUS_WT_DELETED | GIT_STATUS_WT_TYPECHANGE ) ) + return true; + } + + return false; +} + + void GIT_PULL_HANDLER::UpdateProgress( int aCurrent, int aTotal, const wxString& aMessage ) { diff --git a/common/git/git_pull_handler.h b/common/git/git_pull_handler.h index c553567c75..09174e8d8b 100644 --- a/common/git/git_pull_handler.h +++ b/common/git/git_pull_handler.h @@ -43,6 +43,7 @@ struct CommitDetails // Enum for result codes, error codes are negative, success codes are positive enum class PullResult : int { + DirtyWorkdir = -3, MergeFailed = -2, Error = -1, Success = 0, @@ -86,6 +87,8 @@ private: PullResult handleFastForward(); PullResult handleMerge( const git_annotated_commit** aMergeHeads, size_t aMergeHeadsCount ); PullResult handleRebase( const git_annotated_commit** aMergeHeads, size_t aMergeHeadsCount ); + + static bool hasUnstagedChanges( git_repository* aRepo ); }; #endif // _GIT_PULL_HANDLER_H_