Test push conflict en git push a través de pre-Receive Hook

Estoy haciendo un gancho de pre-recepción en BitBucket que se supone que confirma que todos los empujes realizados en una twig están actualizados con las sucursales primarias.

Quiero decir, en una evolución temporal, tenemos varias creaciones de twigs:

Creación de twigs durante el time

Con el ejemplo anterior de OS 3 twigs, Dev, Feature1 y mi Local, quiero, antes de realizar una transferencia de Local a remote / orígenes / Feature1, hacer git merge desde la última Feature1 con el reciente código local on-push. De esta manera, puedo confirmar que, quienquiera que esté haciendo el push, está usando la última versión de feature1, y no habrá conflicto. Si hubiera algún conflicto, devolvería 1, ¡para evitar dar el empujón! y obliga al Desarrollador a extraer de la Función antes de enviar el código.

Este es mi script en Pre-Receive Hook.

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 

Lo he intentado con ref_name, to_ref y sin éxito.

¿Alguien puede ayudarme?

¿Cómo puedo acceder al código empujado recientemente y fusionarlo por la twig principal con este código?

Muchas gracias, Nuno

Esto parece algo muy extraño de hacer, y probablemente esté condenado al fracaso. Ciertamente será complicado y querrá cambiar el comportamiento de la testing en function de qué ref (s) se estén actualizando y si estas actualizaciones agregan commit (s) de fusión.

Dicho esto, existen algunas reglas especiales para los ganchos de pre-recepción y actualización, y si los obedeces obtendrás algo más:

  1. No chdir o cd lejos del directory actual. O bien, si lo hace, asegúrese de chdir , pero por lo general no es demasiado difícil asegurarse de que las operaciones que deben ejecutarse en otro directory se ejecuten como un process separado: un subcance u otro script.
  2. Elimine $GIT_DIR del entorno antes de intentar los commands de git que necesitan usar un repository diferente. La razón es que el gancho se ejecuta en el directory de nivel superior con $GIT_DIR configurado en .git (repository no vacío) o . (repository desnudo).

Poniendo esos dos juntos, puede mover todo su código de verificador en un script separado y hacer algo como esto:

 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 

Todavía hay un gran problema aquí. Desea que check_script pueda acceder a cualquier nueva confirmación propuesta que sea accesible desde $ref_name si la secuencia de commands hook sale de 0 para permitir la actualización propuesta. Esa actualización aún no se ha producido : $ref_name aún apunta al antiguo SHA-1 $from_ref . Mientras tanto, el nuevo SHA-1 en $to_ref podría no tener ningún nombre apuntando a él (aunque todavía existe en el repository subyacente).

Entre otras cosas, si $to_ref apunta a nuevas confirmaciones (el caso habitual), cualquier clon que hagas en este punto, a través de operaciones git normales, no contendrá esas confirmaciones, por lo que no podrás usarlas.

Hay dos forms obvias de manejar esto:

  • Haga una reference nueva (temporal) que apunte a $to_ref . Luego puede ver los commits propuestos en el clon.
  • No uses un clon Copie el repository de otra manera, o use directamente el repository original, por ejemplo, como un "alternativo", o creando un directory de tree de trabajo temporal y señalando $GIT_WORK_TREE allí, o usando algunas de las nuevas características de git worktree que han aparecido en git 2.6+. (Si elige el método manual de tree de trabajo temporal, asegúrese de pensar también en el $GIT_INDEX_FILE compartido normal).

Recuerde también verificar los empujes forzados que eliminan los commits de una twig, o incluso eliminar-some-and-add-others, todo de una vez.

ACTUALIZACIÓN: esta pregunta está resuelta para mí.

El código final es este:

 #!/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 

Muchas gracias.