# Git Flow [![PyPI Version](https://img.shields.io/pypi/v/git-flow-envs)](https://pypi.org/project/git-flow-envs/) ![Python Version](https://img.shields.io/python/required-version-toml?tomlFilePath=https://git.jonathanteran.dev/jt/git-flow/raw/branch/main/pyproject.toml) Herramienta para establecer un workflow siguiendo [Conventional Commits (CC)](https://www.conventionalcommits.org), [Conventional Branch (CB)](https://conventional-branch.github.io/), y [SemVer](https://semver.org/). Esta diseñada para facilitar la creación de commits y branches en un formato estandar, que permite derivar versiones automaticamente de los merges sobre ramas principales. ## Instalación Se puede instalar con `pip` ejecutando el siguiente comando: `pip install git-flow-envs`. Sin embargo, se sugiere utilizar [pipx](https://github.com/pypa/pipx) (seguir la documentación para instalarlo), ya que aisla las dependencias de la herramienta en un `venv`. Una vez instalado, simplemente ejecutamos `pipx install git-flow-envs` Luego podemos verificar que se haya instalado correctamente ejecutando: `git-flow --help` ## Configuración Para poder usar la herramienta en un repositorio, necesitamos inicializarlo: ```sh git-flow init ``` El comando solicitará 2 opciones: - **Ramas principales**: Ramas que representan los entornos principales del proyecto. Por ejemplo: `dev,test,prod`. - **Remoto** (opcional): Nombre del remoto que se usará para crear PRs, y taggear merges automáticamente. Por el momento, se soportan los siguientes remotos: - [x] Bitbucket - [x] Github - [x] Gitea - [x] Gitlab La configuración del remoto requiere tener un Access Token para poder crear los PRs y tags automáticamente. Ver la sección [Remotos soportados](#remotos-soportados) para las instrucciones de cómo generar el token en cada proveedor. Una vez generado, el token se debe guardar dentro del repositorio a configurar, en el archivo `.repository-token`. De no especificarse, los merges y tags se harán de forma local. ## Utilización Git Flow cuenta con los siguientes comandos para guiar el workflow (ver `git-flow --help` para más información): - `init`: Inicializa el repositorio para utilizar git-flow (ramas principales y remoto). - `new`: Crea una nueva rama siguiendo CB. - `commit`: Crea un commit siguiendo CC. - `merge`: Mergea la rama actual a uno de los entornos. - `tag`: Crea un tag sobre el ultimo merge siguiendo SemVer (ver [Tag](#tag)). - `release`: Prepara la rama actual para pasarse al siguiente entorno configurado. - `branch ls`: Lista las ramas del repositorio, agrupadas por entorno objetivo. - `branch clean`: Elimina las ramas alcanzables desde HEAD (locales por defecto, o remotas con `--remote`), dejando un reporte CSV (`branch-clean-report.csv`) con nombre, commit, autor y fecha de cada rama eliminada. El workflow para el cual se penso la herramienta es el siguiente: 1. Sobre la primer rama principal configurada (por ejemplo, `dev`), se crea una nueva rama con `git-flow new` 2. Se realizan cambios y se commitean los mismos con `git-flow commit` (se repite hasta que se considere que la rama esté lista para mergear) 3. Se ejecuta `git-flow merge` para mergear la rama al entorno que corresponda (en este caso, `dev`). En caso de tener un remoto configurado, el comando crea un PR para integrar el cambio. Si no, simplemente se ejecuta un `git merge` simple. 4. Para versionar este último merge, se ejecuta `git-flow tag`, ya sea localmente o desde un pipeline para que se ejecute en cada merge. 5. Una vez que la rama fue correctamente integrada a un entorno (por ejemplo, `dev`), se usa `git-flow release` para crear una nueva rama para integrar unicamente los cambios de esa rama sobre el siguiente entorno (por ejemplo, `test`). Si la rama original era `feature/my-new-feature`, se crea la rama `release/test/feature/my-new-feature` sobre `test` que tiene los cambios de la rama original. En cualquier momento se puede usar `git-flow branch ls` para ver en qué entorno está cada rama, y cuáles están todavía en progreso (`wip/`) o descartadas (`trash/`). ### Tag `git-flow tag [--target=] [--token=] [--update-changelog]` - `--target`: rama principal sobre la que se taggea. Por defecto, la rama actual. Debe ser una de las ramas principales configuradas. - `--token`: Access Token del remoto. Si se pasa, se asume que corre en un pipeline: los commits y el último tag se obtienen por API del remoto y el tag se crea en el remoto (y también localmente). Si no, se usa `.repository-token` y todo se resuelve localmente. - `--update-changelog`: genera la entrada correspondiente en `CHANGELOG.md` y la commitea antes de taggear (en un pipeline, además hace push del commit). Comportamiento: - El tag se crea sobre el último merge (first-parent) de la rama. Si ese merge ya tiene un tag, no se hace nada. - La versión se calcula a partir de los tipos de commit (CC) del último merge. Si ningún commit implica un salto de versión, se avisa y el comando termina con código de salida 1. - Con más de un entorno configurado, cada rama versiona por separado con el nombre del entorno como sufijo (por ejemplo, `v1.2.0-prod`). Con un solo entorno no se agrega sufijo. - Si el merge viene del entorno anterior (por ejemplo, `dev` a `test`), no se calcula una nueva versión: se promueve la del entorno anterior cambiando el sufijo (si `dev` está en `v1.2.0-dev` y `test` en `v1.0.0-test`, el nuevo tag es `v1.2.0-test`), sin importar los tipos de commit. Si ese tag ya existe en el destino, el comando falla. En un pipeline, el merge se detecta por la rama origen del PR; localmente, porque el merge trae tags del entorno anterior que el destino no tenía. ## Remotos soportados Cada remoto necesita un Access Token con permisos para crear Pull/Merge Requests y tags. El token se guarda en el archivo `.repository-token` en la raíz del repositorio (una única línea con el valor del token), o se pasa por parámetro con `--token=` al comando `git-flow tag` (útil para no commitear el token y usarlo solo desde un pipeline mediante una variable secreta). ### Github 1. Ir a *Settings* del repositorio (o de la organización) > *Developer settings* > *Personal access tokens* > *Fine-grained tokens* > *Generate new token*. 2. Seleccionar el repositorio sobre el que se va a usar `git-flow`. 3. En *Repository permissions*, otorgar: - **Contents**: Read and write (necesario para crear tags). - **Pull requests**: Read and write (necesario para crear PRs). 4. Generar el token y guardarlo en `.repository-token`. Ejemplo de pipeline (GitHub Actions) para taggear automáticamente en cada push a una rama principal: ```yaml # .github/workflows/tag.yml name: Tag and publish on: push: branches: [main] jobs: tag: runs-on: ubuntu-latest steps: - uses: actions/checkout@v4 with: fetch-depth: 10 - uses: astral-sh/setup-uv@v3 - run: uv run git-flow tag --token=${{ secrets.GIT_FLOW_TOKEN }} - run: uv build - run: uv publish --token=${{ secrets.PYPI_TOKEN }} ``` ### Gitlab 1. Ir a *Settings* > *Access Tokens* del proyecto (o *Group access tokens* si se quiere usar a nivel grupo). 2. Crear un token con rol **Developer** o superior, y los scopes: - **api** (o al menos `write_repository` para tags y `api` para Merge Requests). 3. Generar el token y guardarlo en `.repository-token`. Ejemplo de pipeline (GitLab CI) para taggear automáticamente en cada push a una rama principal: ```yaml # .gitlab-ci.yml tag: image: python:3.14 variables: GIT_DEPTH: 10 rules: - if: $CI_COMMIT_BRANCH == "main" script: - pip install uv # GitLab hace checkout en detached HEAD, por lo que la rama se indica explícitamente - uv run git-flow tag --target=$CI_COMMIT_BRANCH --token=$GIT_FLOW_TOKEN - uv build - uv publish --token=$PYPI_TOKEN ``` El token debe guardarse como variable protegida y enmascarada (`GIT_FLOW_TOKEN`) en *Settings* > *CI/CD* > *Variables*. ### Bitbucket 1. Ir a *Repository settings* > *Access Tokens* > *Create access token* (o *Workspace settings* > *Access Tokens* para un token a nivel workspace). 2. Otorgar permiso de **Write** en *Pull requests* y *Repositories* (necesario para crear tags). 3. Generar el token y guardarlo en `.repository-token`. Este mismo repositorio usa Git Flow para el taggeo automático usando Bitbucket Pipelines, se puede ver el archivo `bitbucket-pipelines.yml` como ejemplo: ```yaml # bitbucket-pipelines.yml image: python:3.14 clone: depth: 10 pipelines: branches: 'main': - step: name: "Tag and publish package" caches: - pip script: - pip install uv - uv run git-flow tag --token=$BEARER - uv build - uv publish --token=$PYPI_TOKEN ``` El token se configura como variable segura del repositorio (`BEARER`) en *Repository settings* > *Repository variables*. ### Gitea 1. Ir a *Settings* del usuario (o de la organización) > *Applications* > *Manage Access Tokens* > *Generate New Token*. 2. Otorgar permiso de escritura sobre: - **repository** (necesario para crear tags). - **issue** (necesario para crear PRs, ya que Gitea expone los PRs bajo el mismo scope). 3. Generar el token y guardarlo en `.repository-token`. Ejemplo de pipeline (Gitea Actions) para taggear automáticamente en cada push a una rama principal: ```yaml # .gitea/workflows/tag.yml name: Tag and publish on: push: branches: [main] jobs: tag: runs-on: ubuntu-latest steps: - uses: actions/checkout@v4 with: fetch-depth: 10 - uses: astral-sh/setup-uv@v3 - run: uv run git-flow tag --token=${{ secrets.GIT_FLOW_TOKEN }} - run: uv build - run: uv publish --token=${{ secrets.PYPI_TOKEN }} ``` ## Taggeo automático por pipeline En todos los casos, al pasar `--token=` `git-flow tag` asume que se está ejecutando desde un pipeline: obtiene los commits del último PR / MR y el último tag por API del remoto, y usa el token tanto para crear el tag en el remoto como para pushear el commit del `CHANGELOG.md` generado (con `--update-changelog`), en vez de resolver todo en forma local.