diff options
author | Daniele E. Domenichelli <daniele.domenichelli@iit.it> | 2013-11-18 10:36:18 (GMT) |
---|---|---|
committer | Brad King <brad.king@kitware.com> | 2014-04-01 14:51:58 (GMT) |
commit | f2128d4c2886ed4ac2532834f53b9522e6586601 (patch) | |
tree | 3992d9027b2b8bb55893c2a4919fe6460e182edc /Modules/ExternalProject.cmake | |
parent | ff2451dc2483df34a70c611836b0ea887bfa3c82 (diff) | |
download | CMake-f2128d4c2886ed4ac2532834f53b9522e6586601.zip CMake-f2128d4c2886ed4ac2532834f53b9522e6586601.tar.gz CMake-f2128d4c2886ed4ac2532834f53b9522e6586601.tar.bz2 |
ExternalProject: Improve handling of git remote branches
ExternalProject handles git remote branches by commit hash. Due to
this, the git repository ends in detached states, and local commits
are discarded.
Use "git rebase" for remote branches instead of "git checkout". If
there are uncommitted changes, use "git stash save/pop" to save changes
and restore them after the rebase. If any of these operations fails,
try to restore the original status and exit with a fatal error, asking
the user to resolve the conflicts manually.
This also makes the behaviour of ExternalProject using git more similar
to the svn version, and probably more likely to what the user expects
by setting GIT_TAG to a branch.
Diffstat (limited to 'Modules/ExternalProject.cmake')
-rw-r--r-- | Modules/ExternalProject.cmake | 106 |
1 files changed, 99 insertions, 7 deletions
diff --git a/Modules/ExternalProject.cmake b/Modules/ExternalProject.cmake index e56cc37..e490e69 100644 --- a/Modules/ExternalProject.cmake +++ b/Modules/ExternalProject.cmake @@ -473,6 +473,17 @@ else() set(is_remote_ref 0) endif() +# Tag is in the form <remote>/<tag> (i.e. origin/master) we must strip +# the remote from the tag. +if(\"\${show_ref_output}\" MATCHES \"refs/remotes/${git_tag}\") + string(REGEX MATCH \"^([^/]+)/(.+)$\" _unused \"${git_tag}\") + set(git_remote \"\${CMAKE_MATCH_1}\") + set(git_tag \"\${CMAKE_MATCH_2}\") +else() + set(git_remote \"origin\") + set(git_tag \"${git_tag}\") +endif() + # This will fail if the tag does not exist (it probably has not been fetched # yet). execute_process( @@ -494,13 +505,94 @@ if(error_code OR is_remote_ref OR NOT (\"\${tag_sha}\" STREQUAL \"\${head_sha}\" message(FATAL_ERROR \"Failed to fetch repository '${git_repository}'\") endif() - execute_process( - COMMAND \"${git_EXECUTABLE}\" checkout ${git_tag} - WORKING_DIRECTORY \"${work_dir}\" - RESULT_VARIABLE error_code - ) - if(error_code) - message(FATAL_ERROR \"Failed to checkout tag: '${git_tag}'\") + if(is_remote_ref) + # Check if stash is needed + execute_process( + COMMAND \"${git_EXECUTABLE}\" status --porcelain + WORKING_DIRECTORY \"${work_dir}\" + RESULT_VARIABLE error_code + OUTPUT_VARIABLE repo_status + ) + if(error_code) + message(FATAL_ERROR \"Failed to get the status\") + endif() + string(LENGTH \"\${repo_status}\" need_stash) + + # If not in clean state, stash changes in order to be able to be able to + # perform git pull --rebase + if(need_stash) + execute_process( + COMMAND \"${git_EXECUTABLE}\" stash save --all --quiet + WORKING_DIRECTORY \"${work_dir}\" + RESULT_VARIABLE error_code + ) + if(error_code) + message(FATAL_ERROR \"Failed to stash changes\") + endif() + endif() + + # Pull changes from the remote branch + execute_process( + COMMAND \"${git_EXECUTABLE}\" rebase \${git_remote}/\${git_tag} + WORKING_DIRECTORY \"${work_dir}\" + RESULT_VARIABLE error_code + ) + if(error_code) + # Rebase failed: Restore previous state. + execute_process( + COMMAND \"${git_EXECUTABLE}\" rebase --abort + WORKING_DIRECTORY \"${work_dir}\" + ) + if(need_stash) + execute_process( + COMMAND \"${git_EXECUTABLE}\" stash pop --index --quiet + WORKING_DIRECTORY \"${work_dir}\" + ) + endif() + message(FATAL_ERROR \"\\nFailed to rebase in: '${work_dir}/${src_name}'.\\nYou will have to resolve the conflicts manually\") + endif() + + if(need_stash) + execute_process( + COMMAND \"${git_EXECUTABLE}\" stash pop --index --quiet + WORKING_DIRECTORY \"${work_dir}\" + RESULT_VARIABLE error_code + ) + if(error_code) + # Stash pop --index failed: Try again dropping the index + execute_process( + COMMAND \"${git_EXECUTABLE}\" reset --hard --quiet + WORKING_DIRECTORY \"${work_dir}\" + RESULT_VARIABLE error_code + ) + execute_process( + COMMAND \"${git_EXECUTABLE}\" stash pop --quiet + WORKING_DIRECTORY \"${work_dir}\" + RESULT_VARIABLE error_code + ) + if(error_code) + # Stash pop failed: Restore previous state. + execute_process( + COMMAND \"${git_EXECUTABLE}\" reset --hard --quiet \${head_sha} + WORKING_DIRECTORY \"${work_dir}\" + ) + execute_process( + COMMAND \"${git_EXECUTABLE}\" stash pop --index --quiet + WORKING_DIRECTORY \"${work_dir}\" + ) + message(FATAL_ERROR \"\\nFailed to unstash changes in: '${work_dir}/${src_name}'.\\nYou will have to resolve the conflicts manually\") + endif() + endif() + endif() + else() + execute_process( + COMMAND \"${git_EXECUTABLE}\" checkout ${git_tag} + WORKING_DIRECTORY \"${work_dir}\" + RESULT_VARIABLE error_code + ) + if(error_code) + message(FATAL_ERROR \"Failed to checkout tag: '${git_tag}'\") + endif() endif() execute_process( |