---
weight: 4
title: "Apuntes de Git"
date: 2022-07-28T20:30:52+0200
draft: false
summary: "Pues eso, apuntes sueltos de git"
categories:
- notes
tags:
- git
---


## Detached-HEAD

Lo normal es que te enteres después de hacer uno o varios *commits* en *Detached*

### Con rama temporal

```bash
git branch tmp
git checkout main
git merge tmp
git branch -d tmp
```

### Directamente

```bash
git checkout main
git merge HEAD@{1}
```

## Dejar de seguir un fichero

### Sin borrarlo del directorio de trabajo

1. Primero añadimos el fichero o directorio que quieres ignorar al .gitignore.
2. Ejecutamos:

   ```bash
   git rm -r --cached <file>
   git add .
   ```

   Vale para ficheros o directorios, la opción `-r` es para hacerlo recursivo, la opción `--cached` esta para que no borre nada en el _working tree_ solo borra en _index_

   __OJO__: Este método borra los ficheros para el resto del equipo cuando hagan un `git pull`

### Queremos hacer modificaciones del fichero en local sin propagarlas al resto del equipo

```bash
git --update-index --skip-worktree <file>
```



## Hacer un merge

1. Asegúrate de completar todas las tareas para dejar lista la rama que vas a fusionar
2. Asegúrate de cambiár a la rama receptora (`git checkout`) y de que estás en ella (`git status`)
3. Actualiza la rama receptora con el _remote_ (puedes usar `git fetch` y `git pull`)
4. Ejecuta el _merge_ con `git merge`

## Borrar submódulo

La forma correcta de hacerlo, conservando el contenido del módulo si es necesario.

```bash
mv a/submodule a/submodule_tmp  # keeps a backup of module contents
                                # do this only if keeping the contents

git submodule deinit -f a/submodule # removes submodule from repo
rm -rf .git/modules/a/submodule     # removes submodule reference
git rm -f a/submodule               # Note: a/submodule (no trailing slash)

# or, if you want to leave it in your working tree and have done step 0
git rm --cached a/submodule
mv a/submodule_tmp a/submodule
```


## Clonar cuando hay submódulos

La opción `-jn` asigna n recursos para las tareas de clonado.

```bash
git clone --recursive -j8 git://github.com/foo/bar.git
```

## Deshacer un _amend_

Siempre y cuando no la hayas pifiado ya en la historia compartida.

```bash
git reset --soft HEAD@{1}
git commit -C HEAD@{1}
```

La primera orden mueve el _HEAD_ a donde estaba apuntando el _commit_ antiguo. Además dejamos el _index_ intacto para poder hacer otra vez un _commit_ con los cambios pendientes.

`HEAD@{1}` nos da el _commit_ al que _HEAD_ estaba apuntando antes de apuntar al que está apuntando (léelo un par de veces más). No es lo mismo que `HEAD~1` que devuelve el _commit_ padre del _commit_ al que está apuntando _HEAD_.

La segunda sentencia es más retorcida. Significa: _haz un commit del tree actual, usando los detalles del commit erroneo_. Fíjate que `HEAD@{1}` ahora apunta al _commit_ erróneo, puesto que apunta al _commit_ al que apuntaba _HEAD_ antes de apuntar a donde apunta ahora mismo.

## _Revert_ a un _commit_ previo

### _Detached Head_

```bash
git checkout <old-commit-hash>
```

__¡Ojo!__ ahora mismo estás en un _detached head_ es decir no estás en ningún _branch_. Si haces cambios en el _commit_ `<old-commit-hash>` vas a tener muchos problemas. Antes de hacer cambios puedes crear una nueva rama:

```bash
git switch -c <new-branch-name>
```

O volver a donde estabas con `git checkout`

### Con una rama

Si quieres hacer cambios es lo más recomendable:

```bash
git checkout -b old-state <old-commit-hash>
```

### A fuego (quemando las naves)

__Si no tienes nada en la historia compartida__ puedes hacer reset:

```bash
# Perderás todos los cambios locales!
git reset --hard <old-commit-hash>

# Si quieres guardar cambios pendientes
git stash
git reset --hard <old-commit-hash>
git stash pop
# Salvar modificaciones y reaplicar
```


__Si ya has compartido la historia__ tendrás que trabajar con _revert_.

Esta también es la forma más segura y recomendable si quieres conservar la historia completa:

```bash
git revert --no-commit <old-commit-hash>..HEAD
git commit
```

El _flag_ `--no-commit` permite hacer un _revert_ de todos los _commits_ de un golpe, si no lo pasas hará un nuevo _commit_ por cada _commit_ "revertido" y la historia va a quedar un poco enrevesada.

## Cambiar el nombre a una rama

En _Gitlab_ hay que usar _main_ en lugar de _master_.


```bash
git branch -m <New_Branch_Name>
git push origin :<Old_Branch_Name> <New_Branch_Name>
git push --set-upstream origin <New_Branch_Name>
```


## Cambiar de master a main (otro método)

En local:

```bash
git branch -m master main
git status
git push -u origin main
git push origin --delete master
```

Resto del equipo:

```bash
git checkout master
git branch -m master main
git fetch
git branch --unset-upstream
git branch -u origin/main
```



## Crear una nueva rama

```bash
git branch <newbranch_name>          # Crea una nueva rama
git checkout <newbranch_name>        # Cambia a la nueva rama
git switch <newbranch_name>          # También cambia a la nueva rama
git push -u origin <newbranch_name>  # Sube la nueva rama al repo remoto
```

Hay otras alternativas:

```bash
git branch <new_branch> ffeeddaa                      # Crea una rama a partir de un commit
git branch <new_branch> v1.2                          # Crea una rama a partir de un tag
git branch --track <new_branch> origin/<base_branch>  # Crea una rama a partir de una rama remota
```

## Borrar un fichero con información sensible de la historia del repo


### Usando solo git
```bash
git filter-branch --force --index-filter \
  "git rm --cached --ignore-unmatch PATH-TO-YOUR-FILE-WITH-SENSITIVE-DATA" \
  --prune-empty --tag-name-filter cat -- --all
git push --force --verbose --dry-run
git push --force
```

### Usando git-filter-repo

Es una herramienta escrita en Python (ver [github](https://github.com/newren/git-filter-repo))


## rebase interactive

- <https://jordanelver.co.uk/blog/2020/06/04/fixing-commits-with-git-commit-fixup-and-git-rebase-autosquash/>


## Escribir mensajes de commit significativos

- <https://www.freecodecamp.org/news/how-to-write-better-git-commit-messages/>

**Mis tipos de _commit_**

Para usar con este formato:

```bash
<type>[optional scope]: <description>

[optional body]

[optional footer(s)]
```


| Type  | Tipo   | Descripción   |
|:--|:--|:--|
| dev  | desarrollo  | Es un _commit_ de desarrollo en las fases iniciales del proyecto   |
| fix  | fix  | Se arregla un _bug_  |
| chore  | mantenimiento   | El _commit_ no implica ni cambios de código ni de test   |
| refactor  |    | refactorización de código que no arregla un _bug_ ni añade features  |
| docs  |   | Añade o retoca documentación del proyecto  |
| style  |   | Cambios que no afectan el significado del código, probablemente relacionados con el formateado del código, y similares   |
| test  |   |  Crea nuevos test o corrige test existentes   |
| perf  |   | mejoras de _performance_  |
| ci  |   | Relacionados con integración contínua (_continuous integration_)  |
| build  |   | cambios que afecta al _build_ del proyecto, p.ej. cambios de dependencias  |
| revert  |   |  Vuelta a un _commit_ previo   |
