referencia git

Staging area git

Unlike the other systems, Git has something called the «staging area» or «index». This is an intermediate area where commits can be formatted and reviewed before completing the commit.

One thing that sets Git apart from other tools is that it’s possible to quickly stage some of your files and commit them without committing all of the other modified files in your working directory or having to list them on the command line during the commit.

This allows you to stage only portions of a modified file. Gone are the days of making two logically unrelated modifications to a file before you realized that you forgot to commit one of them. Now you can just stage the change you need for the current commit and stage the other change for the next commit. This feature scales up to as many different changes to your file as needed.

## agregar ficheros al staging
git add file

## agregar ficheros al staging
git commit -m"title" -m"description"

## agregar cambios al ultimo commit
git commit --amend -m"title" -m"description"

## deshacer commit, hash es el hash del commit al que quieres volver
git reset hash

# origins
# agregando un origen remoto, con convención ‘origin’ y ‘upstream’
git remote add origin http://rutaproject/project

# ver configuracion remota del origin
git remote show origin

#pull tirar, se trae cambios, push empuja sube cambios
#antes de hacer un push, hacer un pull
#para actualizar el contenido de mi rama
git pull origin master
o
git merge origin master
# con rebase intenta reordenar los commits de forma que no se pierda la historia
git merge --rebase origin master

#ahora ya podemos intercambiar codigo con otras ramas, voy a subir mi rama feature/new-feature
git push origin feature/new-feature

# stash, el cajón
# guardamos lo que hay en el staging pendiente de commitear en un cajón
git stats

# guardar notas para un stash
git stats save "explanation about this stash"

# ver los stash que hay
git stats list

# ver quét tiene un stash, ver stash #3
git stats show stash@{3}

## por defecto el reset, es –soft, te deja los cambios realizados en working directoy
git reset hash

## El modo –hard, elimia todo
git reset --hard hash

## deshacer el ultimo cambio, genera un commit nuevo con nombre «Revert: nombre del commit anterior», una nueva entrada en la historia, aplicando los cambios necesarios para dejar el contenido tal y como estaba antes
git revert
## si no queremos que se genere un commit, podemos usar –no-commit y nos dejará los cambios en el staging
git revert --no-commit
## este commando requiere finarlo, y generará un nuevo commit
git revert --continue

## también se puede hace referencia a HEAD, y HEAD~1, HEAD~2 para indicar los pasos previos a HEAD

git reset HEAD
git reset HEAD~1
# Recuerda que si haces un reset HEAD, el HEAD se moverá al siguiente elemento, y los desplazamientos de ~1 o ~2 serán en base a ese estado
git reset HEAD~2

# comparar ficheros de diferentes ramas, compara somebranch con la rama actual
git diff somebranch path/to/your/file

# configurar herramienta para hacer diffing
git config diff.tool xxdiff

## rama actual
git branch

## crear rama desde la rama actual, todo tiene un origen
git checkout -b'feature/nombre'

## borrar rama
git -D branch

## renombrar rama
git -m branch newbranchname

# fusionar ramas
# debes posicionarte en la rama que va a recibir los cambios, con merge te traes los cambios a la rama actual
git merge feature/somethiing-new
# mezcla de ramas puede ser con fast forward que lo que hace es directamente cambiar el puntero HEAD a la rama que nos estamos trayendo, siempre que sea posible

«The –no-ff flag prevents git merge from executing a «fast-forward» if it detects that your current HEAD is an ancestor of the commit you’re trying to merge. A fast-forward is when, instead of constructing a merge commit, git just moves your branch pointer to point at the incoming commit. This commonly occurs when doing a git pull without any local changes.

However, occasionally you want to prevent this behavior from happening, typically because you want to maintain a specific branch topology (e.g. you’re merging in a topic branch and you want to ensure it looks that way when reading history). In order to do that, you can pass the –no-ff flag and git merge will always construct a merge instead of fast-forwarding.»

http://stackoverflow.com/questions/9069061/what-is-the-difference-between-git-merge-and-git-merge-no-ff/9069127#9069127

# etiquetas, tag
# nombra a un commit con un nombre para humanos
# para etiquetado ver http://semver.org/
# tagea el ultimo commit como v.1.0.1
git tag v1.0.1
# tagea un commit concreto
git tag v1.0.2 433fc3

# listar todos los tags
git tag

# eliminar tag
git tag -d tagname

## etiquetas anotadas
# etiquetas con mayor contenido de información agregado
# exigue que le indiques texto como si fuera un commit
git tag -a tagname

# puedes ver info del tag con git show, descripción y diffing
git show tagname

# otras ramas
## ver un fichero de la rama somebranch
git show somebranch path/to/your/file

# traerte un fichero de otra rama
git checkout somebranch path/to/your/file

# buscar a que branch pertenece un hash
git branch --contains ce1637f
# tambien se puede hacer con el reflog
git reflog show --all | grep ce1637f

# historial de cambios, muestra la historia verdadera de lo que ha pasado
git reflog

# ver las referencias de ramas remotas, en este caso busco un tag en concreto
git ls-remote origin --tags v1.5.0
a56956fc089c84482f0f457d1fa299142f8d6e42 refs/heads/release/v1.5.0

# ver ramas remotas con informacion extendida
git remote show origin

# http://stackoverflow.com/a/9074343
# git lg para mostrar un arbol con color de ramas y etiquetas
# ~./gitconfig

[alias]
lg1 = log --graph --abbrev-commit --decorate --format=format:'%C(bold blue)%h%C(reset) - %C(bold green)(%ar)%C(reset) %C(white)%s%C(reset) %C(dim white)- %an%C(reset)%C(bold yellow)%d%C(reset)' --all
lg2 = log --graph --abbrev-commit --decorate --format=format:'%C(bold blue)%h%C(reset) - %C(bold cyan)%aD%C(reset) %C(bold green)(%ar)%C(reset)%C(bold yellow)%d%C(reset)%n'' %C(white)%s%C(reset) %C(dim white)- %an%C(reset)' --all
lg = !"git lg1"
[core]
excludesfile = /home/jorge/.gitignore_global

Prompt para bash para mostrar el branch actual

PS1='${debian_chroot:+($debian_chroot)}\[\033[01;32m\]\u@\h\[\033[00m\]:\[\033[01;34m\]\w\[\033[00m\]$(__git_ps1)\$ '

#git find file alias script
git config --global alias.find-file '!for branch in $(git for-each-ref --format="%(refname)" refs/heads); do if git ls-tree -r --name-only $branch | grep "$1" > /dev/null; then echo "${branch}:"; git ls-tree -r --name-only $branch | nl -bn -w3 | grep "$1"; fi; done; :'

#git grep through branches with no pagger
for branch in `git for-each-ref –format=»%(refname)» refs/heads`; do echo «[+] $branch :» ; GIT_PAGER=cat git grep ‘OfferType’ $branch; done

git hooks
https://github.com/brigade/overcommit#installation

# git avanzada
http://learngitbranching.js.org/?demo

la he liado parda con el git: como borrar cosas que ya he comiteado

¿ Quien no ha hecho un commit de una cosa que no quería ? seguramente todos hemos comiteado algo que luego nos hemos dado cuenta que no tenía que ir y no lo hemos metido en .gitignore. A veces da un poco igual, depende de lo estrictos que seamos en nuestro equipo o nosotros mismos o bien por que estemos publicando el repositorio de forma pública. Con eliminar el fichero, volver a comitear y pushear… aquí no ha pasado nada :D… pero y si quiero borrar algo que no quiero… ¿ qué hago ?

En mi caso he metido un directorio con una compilacion de node via nodeenv[1] que son unos 200MB que no pintan nada en el repo y que además pesa, el objetivo es eliminar ese contenido de una forma limpia. Para ilustrarlo y que no se me olvide voy a documentar un ejemplo ilustrativo 😉

 

# creamos un repositorio nuevo de git llamado foo
git init project
cd project

# primer commit
echo "Hola mundo" > readme.txt
git add .
git commit -m"add readme file"

# segundo commit, aquí es donde nos colamos metiendo contenido
mkdir pictures
echo "vacaciones" > pictures/readme.txt
git add .
git commit -m"add new feature"

# hacemos como que no nos hemos dado cuenta y seguimos comiteando
echo "Nuevas caracteristicas" > CHANGES
git add . 
git commit -m"add changefile"

En este punto la hemos liado por que se nos ha colado el directorio de vacaciones en el proyecto y hacemos un facepalm, por que hemos metido la carpeta de pictures con cosas de las vacaciones en el proyecto y eso no lo queremos 😀

¿Ahora como solucionamos esta situación?

Lo que necesitamos es conservar el último cambio pero eliminar el directorio pictures del proyecto de forma que no quede almacenado en git. Para ello y siguiendo la documentación de git checkout[2] vamos a hacer lo siguiente:

  • volver al paso 2 dejando los cambios de 3 en el stage area
  • Crear una rama con los cambios de stage
  • mover el head del master al paso 1
  • mergear el master con la nueva rama

Explicamos los pasos:

Necesitamos trabajar con los ficheros de forma que no modifiquemos la rama master y nos creamos una rama para reparar que se llamará ‘fix-mess-up’ y la dejamos en el punto anterior a cuando la hemos liado, es decir hace dos commits.

# creamos una rama en la que trabajar la reparacion
git checkout -b fix-mess-up
# volvemos dos commits atrás y dejamos los cambios en el stage, de forma que podemos manejarlos, quitar, añadir, etc...
git reset --soft HEAD~2
# vemos lo que hay en el stash, pendiente de comitear
git status
# quitamos del stash la carpeta de pictures
git reset HEAD pictures/
# ahora tenemos el directorio pictures que tenemos que eliminarlo o meterlo en .gitignore
rm -fr pictures
# aplicamos los cambios en nuestra rama, esto debería ser el contenido correcto
git commit -m"fixed mess up"

Ahora que ya tenemos una rama buena, vamos a eliminar el contenido no deseado de master y echunfarle nuestra rama con la reparación.

# cambiamos a la rama master
git checkout master
# volvemos dos commits atrás y nos cargamos lo que haya con el hard!
git reset --hard HEAD~2
# mezclamos lo que tenemos en la rama fix-mess-up en el master
git merge fix-mess-up

Y en este momento ya lo tenemos reparado, solo falta borrar la rama de fix-mess-up que ya no la necesitamos.

#borrar la rama de la reparación que ya no es necesaria
git branch -d fix-mess-up

 

Nota:

Para que no se me olvide, en el momento en que se hacen checkouts o resets, se entra en modo deatached, con lo que el puntero de HEAD no está en el último commit y cada modificación que se haga a partir de ahí se mete en un branch virtual. Para no perder estos cambios hay que hacer o bien un branch o un tag tal y como se indica en la documentación de git checkout[2]

It is important to realize that at this point nothing refers to commit f. Eventually commit f (and by extension commit e) will be deleted by the routine Git garbage collection process, unless we create a reference before that happens. If we have not yet moved away from commit f, any of these will create a reference to it:

$ git checkout -b foo   (1)
$ git branch foo        (2)
$ git tag foo           (3)

 

[1] http://ekalinin.github.io/nodeenv/

[2] https://git-scm.com/docs/git-checkout#_detached_head