Práctica combinada de githooks y gestión de sucursales.

archivo

Este artículo se publicó por primera vez en: https://github.com/bigo-frontend/blog/ Bienvenido a seguirlo y volver a publicarlo.

introducción

Durante el desarrollo del proyecto, existen ramas de desarrollo, ramas de prueba, ramas troncales, etc. Generalmente, la rama de prueba no se puede fusionar con otras ramas, pero puede fusionarse accidentalmente (mano temblorosa) o incluso agregar cosas nuevas sin saberlo, y se descubrirá cuando se conecte más tarde (o si no se encuentra). , simplemente coloque la rama de prueba directamente (el código de la rama se pone en línea), las consecuencias pueden ser grandes o pequeñas y es problemático revertir.

¿Puede prohibir directamente la fusión de sucursales ilegales durante la fase de fusión? La respuesta es sí. Simplemente resuelve los siguientes problemas.

  • ¿Se está fusionando?
  • ¿Cómo se llama la sucursal actual?
  • ¿Cómo se llama la sucursal a la que se fusionará?
  • Si la rama actual y la rama que se fusionará cumplen con las condiciones [por ejemplo, la rama que se fusionará no puede ser una rama de prueba]

Conocimiento previo

ganchos git

git hooks , en pocas palabras, es una función de enlace (programa de script) que se activará durante la ejecución de los comandos de git. Siempre que sepa qué enlaces se activarán con un comando git específico, puede realizar el procesamiento correspondiente; por ejemplo, puede usarse para verificar si la información enviada se ajusta a la especificación (como commitlint) y para evitar la fusión . de ciertas ramas que se discutirán en este artículo.

git fusionar

Orden:git merge <branch>

Hay 3 posibles casos de fusión

  • fusión de avance rápido : al fusionar, la rama actual y la rama que se fusionará no tienen bifurcación en el historial de la rama [el entendimiento simple es que la rama que se fusionará se basa en la rama actual, y la rama actual nunca ha sucedido desde entonces se creó la nueva sucursal cambio】. git merge --no-ff <branch>Se puede cambiar al segundo caso de fusión mediante

fusión de avance rápido |  Atlas

  • sin combinación de avance rápido : agregue un nuevo nodo de historial cuyo padre directo apunte a las dos ramas que se fusionarán

sin fusión de avance rápido |  Atlas

  • Conflicto de fusión : Hay un conflicto de fusión. En este momento, el conflicto debe resolverse y luego agregarse y confirmarse nuevamente.

Imagen de: https://www.atlassian.com/git/tutorials/using-branches/git-merge

Instrucciones previas
El proyecto aquí es un proyecto front-end que utiliza husky para administrar los ganchos de git.

Preguntas más frecuentes

¿Se está fusionando?

Al referirnos a los ganchos de git , podemos ver que la etapa de fusión puede activar los siguientes ganchos [la razón para decir esto puede deberse a que hay muchas situaciones en la fusión y los ganchos activados en cada situación no son consistentes]:

  • pre-merge-commit
  • prepare-commit-msg
  • commit-msg
  • post-merge
Fusionar casos\Ganchos de gatillo pre-merge-commit prepare-commit-msg commit-msg post-merge
fast-forward merge
no fast-forward merge
merge conflictAgregar y confirmar después de resolver el conflicto

merge conflictHabrá un estado intermedio (当前分支 | MERGING), desde el estado inicial hasta el estado intermedio, y no se activarán los enlaces relacionados con la fusión. Cuando se resuelva el conflicto y se inicie add&commit, se activará el enlace correspondiente

Según la situación de fusión, los ganchos utilizados son los siguientes:

  • fast-forward mergey no fast-forward merge: utilizar post-mergeganchos para el procesamiento lógico
  • merge conflict: Úselo prepare-commit-msgpara procesamiento lógico [Debido a que commit-msgel enlace no puede obtener el nombre de la rama fusionada, solo se puede usar prepare-commit-msg]

Obtener el nombre de la sucursal actual

git rev-parse --abbrev-ref HEAD

REF: https://stackoverflow.com/questions/6245570/how-to-get-the-current-branch-name-in-git

Obtener el nombre de la rama fusionada

post-fusión

Este gancho maneja no fast-forward mergey fast-forward mergefusiona.

post-mergeCuando se activa el gancho, la rama se fusionó y el reflog se actualizó, por lo que la git refloginformación de la rama fusionada se puede obtener a través de

Para los dos primeros casos de fusión, git reflog -1el formato de registro devuelto es el siguiente

  • no fast-forward merge:e7cb874 HEAD@{0}: merge feat/no-fast-forward: Merge made by the 'recursive' strategy.
  • fast-forward merge:724446f HEAD@{0}: merge feat/fast-forward: Fast-forward

El nombre de la rama correspondiente se puede extraer mediante una coincidencia regular, el código es el siguiente

const {
    
     execSync } = require('child_process');

function getMergeBranch() {
    
    
  // 从 reflog 提取合并进来的分支名
  function getBranchNameFromReflog(reflogMessage) {
    
    
    const reg = /@\{\d+\}: merge (.*):/;
    return reg.exec(reflogMessage)[1];
  }

  const reflogMessage = execSync('git reflog -1', {
    
     encoding: 'utf8' });
  const mergedBranchName = getBranchNameFromReflog(reflogMessage);
  return mergedBranchName;
}

preparar-compromiso-msg

Este gancho maneja casos de conflictos de fusión.

Debido a que el conflicto no se resuelve, el reflog no se actualizará, por lo que la rama fusionada no se puede obtener a través del reflog.

Sin embargo, durante la fase de conflicto de fusión, .git/MERGE_HEADse conservará el hash de la rama fusionada.
Cuando prepare-commit-msgse activa, puede leer el archivo para obtener el contenido correspondiente y luego usar git name-rev [hash]el comando para obtener el nombre de la rama correspondiente.

const {
    
     execSync } = require('child_process');
const path = require('path');
const fs = require('fs');

// 从 .git/MERGE_HEAD (sha) 提取合并进来的分支名
function getMergeBranch() {
    
    
  try {
    
    
    const mergeHeadPath = path.resolve(process.cwd(), '.git/MERGE_HEAD');
    const mergeHeadSha = fs.readFileSync(mergeHeadPath, {
    
     encoding: 'utf8' });
    const mergeBranchInfo = execSync(`git name-rev ${
      
      mergeHeadSha}`);
    return / (.*?)\n/.exec(mergeBranchInfo)[1];
  } catch (err) {
    
    
    return '';
  }
}

¿La sucursal fusionada cumple con los requisitos?

Esto se puede manejar según cada escena. Por ejemplo, después de fusionar la rama incorrecta, se muestra un mensaje que permite al operador decidir si desea retroceder, etc.

const {
    
     execSync } = require('child_process');
const readline = require('readline');

function showConfirm(currentBranch, mergeBranch, inConflict) {
    
    
  log(`检测到非法合并: ${
      
      mergeBranch} ==into==> ${
      
      currentBranch}`);

  const rl = readline.createInterface({
    
    
    input: process.stdin,
    output: process.stdout,
  });

  rl.question(`是否撤销本次合并?(y/n) `, (answer) => {
    
    
    if (answer === 'y') {
    
    
      log('撤销合并中...');
      if (inConflict) {
    
    
        log(`exec: git merge --abort`);
        execSync('git merge --abort');
        log('已撤销合并 done');
        rl.close();
        process.exit(-1);
      } else {
    
    
        log(`exec: git reset --merge HEAD@{1}`);
        execSync('git reset --merge HEAD@{1}');
        log('已撤销合并 done');
        rl.close();
        process.exit(0);
      }
    } else {
    
    
      rl.close();
      process.exit(0);
    }
  });
};

otros problemas

post-mergeEn la primera pregunta [si se está fusionando], finalmente se usan dos ganchos prepare-commit-msgpara realizar el procesamiento de interceptación correspondiente, pero estos dos ganchos no fast-forward mergese activarán en el caso de, es decir, el procesamiento de interceptación se ejecutará repetidamente. En este punto, se requiere juicio y la lógica de interceptación en el gancho se ejecuta
si y solo si está en . Se garantiza que cada situación de fusión solo activará la lógica de interceptación una vez.merge conflictprepare-commit-msg

La idea es detectar .git/MERGE_MSGsi el archivo existe y si su contenido es información contradictoria.

const {
    
     execSync } = require('child_process');
const path = require('path');
const fs = require('fs');

function isMergingConflict() {
    
    
  // 是否合并中
  const mergeMsgPath = path.resolve(process.cwd(), '.git/MERGE_MSG');
  const isMerging = fs.existsSync(mergeMsgPath);
  if (!isMerging) {
    
    
    return false;
  }

  try {
    
    
    const mergeMsg = fs.readFileSync(mergeMsgPath, {
    
     encoding: 'utf8' });
    return /\n# Conflicts:\n/.test(mergeMsg); // 如果是冲突则能匹配上
  } catch (err) {
    
    }
  return false;
}

Resumir

git-hooks-prevenir-fusión-resumen

referencia

https://git-scm.com/docs/githooks
https://www.atlassian.com/git/tutorials/using-branches/git-merge

Bienvenidos a todos a dejar un mensaje para discutir. ¡Les deseo un buen trabajo y una vida feliz!

Soy el front-end de bigo, nos vemos en el próximo número.

Supongo que te gusta

Origin blog.csdn.net/yeyeye0525/article/details/124590479
Recomendado
Clasificación