2016-04-27 1 views
1

Я делаю Pre-Receive Hook на BitBucket, который должен подтвердить, что все нажатия, сделанные в ветке, являются актуальными с родительскими ветвями.Тестовые конфликты толчков при нажатии git с помощью приемного крюка

Я имею в виду, во временной эволюции, у нас есть несколько филиалов творения:

Branch creation during time

В примере выше зева 3 ветви, Dev, feature1, и мой местный, я хочу, прежде чем сделать толчок от Local to remote/originins/Feature1, сделайте git слияние с последним Feature1 с недавним локальным кодом на месте. Таким образом, я могу подтвердить, что тот, кто делает push, использует последнюю версию feature1, и конфликта не будет. Если бы это был какой-то конфликт, я бы вернулся 1, чтобы избежать толчка! и обязуйте Разработчика вытащить из Feature перед нажатием код.

Это мой сценарий на приемном крюке.

while read from_ref to_ref ref_name; do 
    echo "Ref update:" 
     echo " Old value: $from_ref" 
     echo " New value: $to_ref" 
     echo " Ref name: $ref_name" 
     echo " Diff:" 
     git clone --progress -v $GIT_URL $CLONE_DIR1 
     cd $CLONE_DIR1 
     git checkout -b test remotes/origin/Feature1 
     git merge --no-commit -m "Merging feature with local on-push code" $ref_name 
     (....) 
done 

Я пробовал с ref_name, to_ref и не имел успеха.

Кто-нибудь может мне помочь?

Как я могу получить доступ к последнему нажатому коду и объединить по родительской ветке с помощью этого кода?

Большое спасибо, Нуну

+0

RESOLVED! благодаря –

ответ

0

Это кажется очень странным, что нужно сделать, и это, вероятно, обречены на провал. Это, безусловно, будет сложно, и вы захотите изменить свое тестовое поведение на основе того, какие ref (-ы) обновляются и будут ли эти обновления добавлять слияния (-ы) слияния.

Тем не менее, есть некоторые специальные правила для предварительного приема и обновления крючков, и если вы будете подчиняться им, вы получите несколько дальше:

  1. Не chdir или cd от текущего каталога. Или, если вы это сделаете, убедитесь, что вы ответили chdir, но обычно не слишком сложно убедиться, что операции, которые должны выполняться в другом каталоге, выполняются как отдельный процесс: либо под-оболочка, либо другой скрипт.
  2. Удалите $GIT_DIR из среды, прежде чем пытаться выполнить команды git, которым необходимо использовать другой репозиторий. Причина заключается в том, что крючок запускается в каталоге верхнего уровня с $GIT_DIR, установленным либо .git (не-голый репо), либо . (голый репозиторий).

Положив эти два вместе, вы можете переместить весь код верификатор в отдельный скрипт и сделать что-то вроде этого:

exitstatus=0 
while read from_ref to_ref ref_name; do 
    ... maybe some setup code here to see if $ref_name 
     is being created or destroyed ...' 

    case "$ref_name" in 
    ... add cases as needed to choose action based on ref ... 
     if (unset GIT_DIR; /path/to/check_script arg1 arg2 ...); then 
      echo "push being rejected because ..." 
      exitstatus=1 
     fi 
    ... 
    esac 
    ... 
done 
exit $exitstatus 

Там есть еще одна очень большая проблема здесь. Вы хотите, чтобы check_script получил доступ к любым предлагаемым новым обязательствам, которые достигнут от $ref_name, если скрипт hook завершает 0, так что предлагаемое обновление к нему разрешено. Это обновление еще не произошло: $ref_name все еще указывает на старый SHA-1 $from_ref.Между тем, новый SHA-1 в $to_refможет не иметь никакого имени, указывающего на него (хотя он все еще существует в базовом репозитории).

Среди других вещей, если $to_ref указывает на новых фиксаций (обычный случай), любой клон вы делаете в данный момент, с помощью обычных операций GIT, не будет содержать те коммиты, так что вы не сможете использовать их ,

Есть два очевидных способа справиться с этим:

  • Сделать новый (временный) ссылку, которая указывает на $to_ref. Затем вы можете увидеть предлагаемые фиксации в клоне.
  • Не используйте клон. Скопируйте репозиторий каким-либо другим способом или непосредственно используйте оригинальный репозиторий, например, как «альтернативный», или создав каталог временного рабочего дерева и указав там $GIT_WORK_TREE или используя некоторые из новых функций git worktree, появившихся в git 2.6 +. (Если вы выбираете временный метод ручной работы, дерево, обязательно думать о нормальном общем $GIT_INDEX_FILE а.)

Не забудьте также проверить вынужден выталкивает, что удалить коммитов из ветки, или даже удалить -все-и-еще-все в одном нажатии.

0

ОБНОВЛЕНИЕ: Этот вопрос разрешен для меня.

Конечный код это:

#!/bin/bash 
DIR=xpto/external-hooks/code_review 
CLONE_DIR=$DIR/test_conflict_push-$(date +%s) 
GIT_URL=myGitUrl 
exitStatus=0 

read oldrev newrev refname 
feature_branch=${refname##refs/heads/} 
echo "Feature branch-> $feature_branch" 
#Clone feature branch from remote repo to be update via merged. 
git clone --progress -v $GIT_URL $CLONE_DIR 
currentDir=$PWD 
cd $CLONE_DIR 
#create branch named 'latest' to put new and modify files 
git checkout -b latest remotes/origin/$feature_branch 
#go back to PWD otherwise cant make git diff 
cd $currentDir 
# Get the file names, without directory, of the files that have been modified 
# between the new revision and the old revision 
echo "Getting files" 
files=`git diff --name-only ${oldrev} ${newrev}` 
echo "Files -> $files" 
# Get a list of all objects in the new revision 
echo "Getting objects" 
objects=`git ls-tree --full-name -r ${newrev}` 
echo "objects -> $objects" 
# Iterate over each of these files 
for file in ${files}; do 
    # Search for the file name in the list of all objects 
    object=`echo -e "${objects}" | egrep "(\s)${file}\$" | awk '{ print $3 }'` 
    # If it's not present, then continue to the the next itteration 
    if [ -z ${object} ]; 
    then 
     continue; 
    fi 
    # Otherwise, create all the necessary sub directories in the new temp directory 
    mkdir -p "${CLONE_DIR}/`dirname ${file}`" &>/dev/null 
    # and output the object content into it's original file name 
    git cat-file blob ${object} > ${CLONE_DIR}/${file} 
done; 
echo "Ready for start merging." 
cd $CLONE_DIR 
#add new files to branch 
echo $(git add .) 
#commit added and modify files to branch 
echo $(git commit -a -m "Merge latest to original feature") 
#get generated commit id 
echo $(git log -1) 
#create branch named 'merged' to merge above commited files 
echo $(git checkout -b merged remotes/origin/$feature_branch) 
#merge only occurs for madded and modify files! 
echo "Merging committed files to 'merged' branch with from 'latest' branch." 
mergeResult=$(git merge --no-commit latest) 
echo "Merge Result -> $mergeResult" 
##to lower case 
if [[ "${mergeResult,,}" == *"conflict"* ]] 
then 
echo "Merge contains conflicts." 
echo "Update your $feature_branch branch!" 
exitStatus=1 
else 
echo "Merge don't contains conflict." 
echo "Push to $feature_branch can proceed." 
exitStatus=0 
fi 
#remove temporary branches 
echo $(git checkout master) 
echo $(git branch -D latest) 
echo $(git branch -D merged) 
#delete temporary clone dir 
rm -rf $CLONE_DIR 
exit $exitStatus 

Большое спасибо.

Смежные вопросы