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
- 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
- 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 conflict Agregar y confirmar después de resolver el conflicto |
❌ | ✅ | ✅ | ❌ |
merge conflict
Habrá 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 merge
yno fast-forward merge
: utilizarpost-merge
ganchos para el procesamiento lógicomerge conflict
: Úseloprepare-commit-msg
para procesamiento lógico [Debido a quecommit-msg
el enlace no puede obtener el nombre de la rama fusionada, solo se puede usarprepare-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 merge
y fast-forward merge
fusiona.
post-merge
Cuando se activa el gancho, la rama se fusionó y el reflog se actualizó, por lo que la git reflog
información de la rama fusionada se puede obtener a través de
Para los dos primeros casos de fusión, git reflog -1
el 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_HEAD
se conservará el hash de la rama fusionada.
Cuando prepare-commit-msg
se 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-merge
En la primera pregunta [si se está fusionando], finalmente se usan dos ganchos prepare-commit-msg
para realizar el procesamiento de interceptación correspondiente, pero estos dos ganchos no fast-forward merge
se 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 conflict
prepare-commit-msg
La idea es detectar .git/MERGE_MSG
si 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
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.