supervivencia en python usando xml con namespaces

En python hay dos librerías que se usan extensamente xml que viene en el core de python y lxml una librería externa que provee de algunas cosas que xml no.

Vamos a manejar tres clases o conceptons ElementTree, Element y ElemenPath y vamos a jugar siempre con que nuestro xml tiene namespaces ya que tooooodo el uso actual de xml de servicios soap se hace con namespaces, excepto los ficheros de configuración de java

texto

Elment, es un tag, y tiene nombre ( tag, tagname o como quieras llamarlo ), attributos y texto

En estos ejemplos se realiza una acción y se dumpea la salida para comprobar lo que estamos haciendo

import xml.etree.ElementTree as ET

# crear nodos
>>> root = ET.Element('root')
>>> body = ET.SubElement(a, 'body')
>>> ET.dump(root)

# asignar atributos a un tag
#
>>> root = ET.Element('root')
>>> body = ET.SubElement(root, 'body', {'env':'devel'})
>>> ET.dump(body)

# otras formas de manejar los attributos
>>> body.attrib['env']
'devel'
>>> body.attrib['env'] = 'foo'
>>> body.attrib['env']
'foo'

# texto dentro de un Element
>>> body.text = 'this is the text'
>>> ET.dump(body)
this is the text

# importar de fichero
>>> import xml.etree.ElementTree as ET
>>> tree = ET.parse('country_data.xml')
>>> root = tree.getroot()

# importar de string
>>> xml_string = ""
>>> root = ET.fromstring(xml_string)
>>> ET.dump(root)

# namespaces

source = """


irrelevant_request_id
0



"""

>>> xml = ET.fromstring(source)
>>> xml

Dos cosas a tener en cuenta, NO puede haber un salto de linea de en el “””

source = """



irrelevant_request_id
0



"""

>>> import xml.etree.ElementTree as ET
>>> xml = ET.fromstring(source)
>>> xml = ET.fromstring(source)
Traceback (most recent call last):
File “”, line 1, in
File “/usr/lib/python2.7/xml/etree/ElementTree.py”, line 1311, in XML
parser.feed(text)
File “/usr/lib/python2.7/xml/etree/ElementTree.py”, line 1653, in feed
self._raiseerror(v)
File “/usr/lib/python2.7/xml/etree/ElementTree.py”, line 1517, in _raiseerror
raise err
xml.etree.ElementTree.ParseError: XML or text declaration not at start of entity: line 2, column 0
#Usando namespaces los tags se nombran así
{url}TagName

Con lo que las busquedas xpath se hace buscando por {url}TagName. Para buscar lo tendremos que hacer de la siguiente manera, pero antes hay que registar las urls

Podemos usar find o findall para buscar uno o todos los nodos que cumplan un pattern xpath

source = """


irrelevant_request_id
0



"""

>>> xml = ET.fromstring(source)
# como tenemos namespaces esta consulta no funcionará
>>> xml.find('ID')
# esta debería funcionar, pero tampoco funciona por que find busca desde la raiz y no desde cualquier nodo
>>> xml.find('{urn:dslforum-org:cwmp-1-2}ID')
# buscamos con find desde cualquier nodo con una busqueda al estilo xpath
>>> xml.findall('.//{urn:dslforum-org:cwmp-1-2}ID')

# es posible usar etiquetas para los namespaces
>>> ns = {'cwmp': 'urn:dslforum-org:cwmp-1-2',
'soap': 'http://schemas.xmlsoap.org/soap/envelope/'}
>>> xml.find('.//{urn:dslforum-org:cwmp-1-2}ID', ns)

# findall devolerá una lista con los resultados, o una lista vacía si no hay resultado
>>> xml.findall('.//{urn:dslforum-org:cwmp-1-2}ID', ns)
[]

# pip install lxml
# from lxml import etree

# crear nodos
>>> root = etree.Element('root')
>>> root.append(etree.Element('body'))
>>> etree.tostring(root)
''
>>> etree.tostring(root, pretty_print=True)
'\n \n\n'

# asignar atributos a un tag

>>> root = etree.Element('root')
>>> root.append(etree.Element('body', env='devel'))
>>> etree.tostring(root)
''
>>> etree.tostring(root, pretty_print=True)
'\n \n \n\n'

# manejar attributes de forma comoda
>>> root = etree.Element('root')
>>> root.append(etree.Element('body', my_attribute='my_value'))
>>> attributes = root[0].attrib
>>> attributes['new_attr'] = '12345'
>>> etree.tostring(root)
''

# manejar texto
>>> from lxml import etree
>>> root = etree.Element('root')
>>> root.append(etree.Element('body', my_attribute='my_value'))
>>> root.text = 'this is the text'
>>> etree.tostring(root)
'this is the text'

# importar de fichero

>>> from lxml import etree
>>> tree = ET.parse('country_data.xml')
>>> root = tree.getroot()

# importar de string
>>> xml_string = ""
>>> root = ET.fromstring(xml_string)
>>> ET.dump(root)

# namespaces

>>> source = """


irrelevant_request_id
0



"""
>>> root = ET.fromstring(source)

#Buscando nodos, como el xml hay que poner {

# nótese que el {namespace} debe ser exacto al encabezado o no funcionará la búsqueda
>>> print(root.findall('{http://schemas.xmlsoap.org/soap/envelope}Header'))
[]
>>> print(root.findall('{http://schemas.xmlsoap.org/soap/envelope/}Header'))
[]

# para poder obtener los nsmap de un xml debemos usar objectify, hay dos Element

http://lxml.de/api/xml.etree.ElementTree.Element-class.html
http://lxml.de/api/lxml.etree.ElementBase-class.html

>>> root = objectify.fromstring(source)
>>> root.nsmap
{'cwmp': 'urn:dslforum-org:cwmp-1-2', 'soap-enc': 'http://schemas.xmlsoap.org/soap/encoding/', 'xsi': 'http://www.w3.org/2001/XMLSchema-instance', 'soap': 'http://schemas.xmlsoap.org/soap/envelope/', 'xsd': 'http://www.w3.org/2001/XMLSchema'}

# printea con cabecera xml usando xml_declaration=True
root = etree.Element('root')
etree.tostring(root, encoding="utf-8" , xml_declaration=True)
"\n"

# Se pueden crear a mano elmentos de namespaces con ElementMarker pero el trabajo es muy extenso y el código no es muy legible, mi recomendación es usar templates de string importarlos y usarlos en vez de generarlos a mano.

from lxml import etree
from lxml.builder import ElementMaker
soap = ElementMaker(namespace=”http://schemas.xmlsoap.org/soap/envelope/”, nsmap={‘soap’ : “http://schemas.xmlsoap.org/soap/envelope/”})

# Extras : xmlwitch
xmlwitch sólo lee y no escribe, pero lo hace de manera muy cómodo

entornos virtuales en python

Las aplicaciones cada vez son más complejas y por suerte más estructuradas, por ello los pequeños bloques de código reutilizable se extraen y se paquetizan, con uno u otro nombre dependiendo de cada lenguaje. El siguiente paso necesario es una herramienta que gestione los paquetes, instalar, listar, eliminar, instalar desde una fuente remota, etc… Bien pues aquí es donde llega la necesidad de usar un entorno virutal. ¿Por qué? Por varios motivos, uno es que cada aplicación puede requerir una serie de paquetes con versiones concretas que no son necesarias con otras aplicaciones o que incluso que sean incopatibles entre sí.
Usando un entorno virtual podemos instalar estas dependencias en una ruta exclusiva para nuestra aplicación y no tenemos que instalarlas en el sistema. Esto es genial ya que no necesitaremos permisos elevados para instalar los paquetes ni tendremos que andar instalando o desinstalando paquetes para poder desarrollar o instalar una aplicación. Además podemos deshacernos fácilmente de estos paquetes eliminando la ruta donde se almacenan y volver a instalarlos para probar el despliegue o simplemente por si sospechamos que hay ‘algo’ que no está correcto en nuestras dependencias.

En el caso de python hay dos entornos virtuales que se usan extensivamente: virtualenvwrapper y virtuaenv.

La primera vez que empecé a leer sobre esto me resultó muy confuso por que parecía que se hablaba de un sólo software para crear el entorno virutal y no de dos. El uso de estos dos nombres muy parecidos favorece la confusión, pero son dos proyectos que al fin y al cabo hacen lo mismo: proveernos de un entorno virtual.

A grandes rasgos las características principales de virtualenvwrapper vs virtualenv en Debian son:
* virtualenvwrapper sólo soporta python2.x ( ojo, en paquete Debian, ver READE.debian) y virutalenv soporta 2.x y 3.x
* virtualenvwrapper centraliza el almacenamiento de dependencias en $WORKON_HOME Y virutalenv no, debes especificar el directorio cada vez que creas el entorno.

Ahora, como comenzar a usar un entorno virtual en python:

Virtualenvwrapper


sudo apt-get install virtualenvwrapper
mkvirtualenv my_project
workon my_project
...
deactivate

Se crea por defecto en `~/.virtualenvs`

 Virtualenv

Puedes preparar el entorno para la version de python que quieras siempre que la tengas instalada en el systema ( -p )

sudo apt-get install python-virtualenv
virtualenv -p /usr/bin/python2 venv
source venv/bin/activate
...
deactivate

instalar dependencias: pip

El gestor de dependencias por defecto en python es pip, y con el puedes instalar, desintalar, instalar desde remoto, etc…
Con estos entornos ya puedes instalar tus ficheros requirements.txt o requirements-dev.txt de pip sin tener que usar poderes de supervaca. La manera ‘standard’ para instalar las dependencias de un proyecto:


pip install pip --upgrade
pip install -r acs/requirements-dev.txt --upgrade
pip install -r acs/requirements.txt --upgrade

Finalmente podrías configurar cada paquete que disponga de setup.py

for package in $(ls -d */); do pushd $package; if [ -e setup.py ]; then python setup.py develop; fi; popd; done

Extraer imagen jffs2

Cuando accedemos a un dispositivo embebido una de las cosas que solemos hacer es echar un vistazo a /proc/mtd para ver los montajes de los bloques mtd y suele haber un bloque que es el contiene la imagen del sistema embedibo.

Uno de los formatos de ficheros con el que habitualmente nos encontramos es jffs2 [1]

Para extraer el contenido tenemos varias herramientas que podemos usar:

vía script

Podemos copiar el contenido a un dispositivo mtd local y montarlo como jffs de la siguiente manera. ( Estoy usando image.jffs2)


modprobe mtdram
modprobe jffs2
modprobe mtdchar
modprobe mtdblock
dd if=image.jffs2 of=/dev/mtd0
mkdir -p jffs-root
mount -t jffs2 /dev/mtdblock0 jffs-root/

unjffs2 de firmware mod kit

Es básicamente el mismo script pero mejorado, ya que puede darse que tengamos una image ‘big endian’ este script puede convertir la imagen para su correcta extracción. Firmware mod kit[2] es un conjunto de herramientas empaquetadas para todo este tipo de tareas. Requiere el paquete mtd-utils que provee jffs2dump y debe ejecutarse como root ya que jffs2dump sólo es ejecutable por el usuario root.

apt-get install mtd-utils
git clone https://github.com/mirror/firmware-mod-kit
sudo src/jffs2/unjffs2 image.jffs2 jffs-root

jefferson

Es una herramienta de extracción de jffs2 hecha en python

git clone https://github.com/sviehb/jefferson
sudo python setup.py install
sudo pip install cstruct
sudo apt-get install python-lzma

Extraemos la imagen así
jefferson image.jffs2 -d jffs-root

Personalmente el mejor resultado ha sido con el script de firmware mod kit, aquí dejo algunos enlaces de interés que pueden ayudarte si ninguna de estas herramientas ha funcionado [3] [4]


[1] https://es.wikipedia.org/wiki/JFFS2
[2] https://github.com/mirror/firmware-mod-kit
[3] https://www.owasp.org/index.php/IoT_Firmware_Analysis
[4] http://wiki.securityweekly.com/wiki/index.php/Reverse_Engineering_Firmware_Primer

vim soporte de portapapeles en entornos X

Por defecto en Debian, el paquete vim no soporta copiar y pegar texto de forma que se use el portapapeles para el entorno gráfico. Esto es debido a que vim puede ser compilado con una gran cantidad de opciones distintas, y para ello disponemos de muchos paquetes que actualizarán el binario con más o menos opciones activadas.

En este caso, necesitamos activar ‘clipboard’, pero… ¿ cómo podemos ver las opciones activas de nuestro vim ? con vim --version

$ vim --version
VIM - Vi IMproved 7.4 (2013 Aug 10, compiled Nov 17 2016 06:26:47)
Included patches: 1-488, 576
Extra patches: 8.0.0056
Modified by pkg-vim-maintainers@lists.alioth.debian.org
Compiled by jamessan@debian.org
Huge version with GTK2 GUI. Features included (+) or not (-):
+acl +farsi +mouse_netterm +syntax
+arabic +file_in_path +mouse_sgr +tag_binary
+autocmd +find_in_path -mouse_sysmouse +tag_old_static
+balloon_eval +float +mouse_urxvt -tag_any_white
+browse +folding +mouse_xterm +tcl
++builtin_terms -footer +multi_byte +terminfo
+byte_offset +fork() +multi_lang +termresponse
+cindent +gettext -mzscheme +textobjects
+clientserver -hangul_input +netbeans_intg +title
+clipboard +iconv +path_extra +toolbar
+cmdline_compl +insert_expand +perl +user_commands
+cmdline_hist +jumplist +persistent_undo +vertsplit
+cmdline_info +keymap +postscript +virtualedit
+comments +langmap +printer +visual
+conceal +libcall +profile +visualextra
+cryptv +linebreak +python +viminfo
+cscope +lispindent -python3 +vreplace
+cursorbind +listcmds +quickfix +wildignore
+cursorshape +localmap +reltime +wildmenu
+dialog_con_gui +lua +rightleft +windows
+diff +menu +ruby +writebackup
+digraphs +mksession +scrollbind +X11
+dnd +modify_fname +signs -xfontset
-ebcdic +mouse +smartindent +xim
+emacs_tags +mouseshape -sniff +xsmp_interact
+eval +mouse_dec +startuptime +xterm_clipboard
+ex_extra +mouse_gpm +statusline -xterm_save
+extra_search -mouse_jsbterm -sun_workshop +xpm
system vimrc file: "$VIM/vimrc"
user vimrc file: "$HOME/.vimrc"
2nd user vimrc file: "~/.vim/vimrc"
user exrc file: "$HOME/.exrc"
system gvimrc file: "$VIM/gvimrc"
user gvimrc file: "$HOME/.gvimrc"
2nd user gvimrc file: "~/.vim/gvimrc"
system menu file: "$VIMRUNTIME/menu.vim"
fall-back for $VIM: "/usr/share/vim"
Compilation: gcc -c -I. -Iproto -DHAVE_CONFIG_H -DFEAT_GUI_GTK -pthread -I/usr/include/gtk-2.0 -I/usr/lib/x86_64-linux-gnu/gtk-2.0/include -I/usr/include/gio-unix-2.0/ -I/usr/include/cairo -I/usr/include/pango-1.0 -I/usr/include/atk-1.0 -I/usr/include/cairo -I/usr/include/pixman-1 -I/usr/include/libpng12 -I/usr/include/gdk-pixbuf-2.0 -I/usr/include/libpng12 -I/usr/include/pango-1.0 -I/usr/include/harfbuzz -I/usr/include/pango-1.0 -I/usr/include/glib-2.0 -I/usr/lib/x86_64-linux-gnu/glib-2.0/include -I/usr/include/freetype2 -g -O2 -fPIE -fstack-protector-strong -Wformat -Werror=format-security -U_FORTIFY_SOURCE -D_FORTIFY_SOURCE=1 -I/usr/include/tcl8.6 -D_REENTRANT=1 -D_THREAD_SAFE=1 -D_LARGEFILE64_SOURCE=1
Linking: gcc -L. -Wl,-z,relro -L/home/pere/src/debian/ruby/ruby2.1/debian/lib -fstack-protector -rdynamic -Wl,-export-dynamic -Wl,-E -fPIE -pie -Wl,-z,relro -Wl,-z,now -Wl,--as-needed -o vim -lgtk-x11-2.0 -lgdk-x11-2.0 -lpangocairo-1.0 -latk-1.0 -lcairo -lgdk_pixbuf-2.0 -lgio-2.0 -lpangoft2-1.0 -lpango-1.0 -lgobject-2.0 -lglib-2.0 -lfontconfig -lfreetype -lSM -lICE -lXpm -lXt -lX11 -lXdmcp -lSM -lICE -lm -ltinfo -lnsl -lselinux -lacl -lattr -lgpm -ldl -L/usr/lib -llua5.2 -Wl,-E -fstack-protector -L/usr/local/lib -L/usr/lib/x86_64-linux-gnu/perl/5.20/CORE -lperl -ldl -lm -lpthread -lcrypt -L/usr/lib/python2.7/config-x86_64-linux-gnu -lpython2.7 -lpthread -ldl -lutil -lm -Xlinker -export-dynamic -Wl,-O1 -Wl,-Bsymbolic-functions -L/usr/lib/x86_64-linux-gnu -ltcl8.6 -ldl -lz -lpthread -lieee -lm -lruby-2.1 -lpthread -lgmp -ldl -lcrypt -lm

Para afinar un poco más :

$ vim --version | grep clipboard
+clipboard +iconv +path_extra +toolbar
+eval +mouse_dec +startuptime +xterm_clipboard

En este caso vemos ‘+clipboard‘ por lo que tengo la opción activada. Si no es así podemos instalar el paquete gtk para activar el soporte
apt-get install vim-gtk

Ahora ya podemos entrar a vim, escribir algo y probar a seleccionar texto y utilizar las combinaciones típicas de copiar y pegar entre vim y otra aplicación. Si no es posible copiar el texto, podemos mapear la combinación de teclas ‘control+shift+c’ en vim de la siguiente manera:

vmap <C-S-C> "y+<CR>"

… y ya podemos hacer copy+paste de vim a cualquier otro sitio. Recuerda que puedes hacer el mapping persistente en tu ~/.vimrc

Usando tftpd para extraer ficheros de un router

Cuando consigues acceso a un sistema embedido lo más práctico es poder sacar ficheros, o el sistema de ficheros completo fuera del router para poder analizarlo detenidamente.
No siempre hay herramientas como ssh, telnet o un puerto usb donde volcar los datos, pero casi siempre está disponible el comando tftp, un servicio de transferencia de ficheros sin autenticación.

Por lo que nuestro objetivo será conectar desde la consola (busybox) de nuestro router a un host externo que tenga un servidor tftpd y dejar ahí nuestro botín.

Tras algunas pruebas me he decantado por atftpd

sudo apt-get install atfpd

Preparamos la ruta que alberga el contenido

mkdir /srv/tftp/
chonw nobody.nogroup -R /srv/tftp

Desde mi consola tengo este cliente tftp que puede ser o no el tenga tu firmware


# tftp
BusyBox v1.15.3 () multi-call binary

Usage: tftp [OPTIONS] HOST [PORT]

Transfer a file from/to tftp server

Options:
-l FILE Local FILE
-r FILE Remote FILE
-g Get file
-p Put file

 

Un ejemplo para volcar un fichero de bloques mtd a mi host es este
tftp -p -l /dev/mtd6 -r mtd6 192.168.0.155

Y algo un poco más chulo para volcar casitodo el sistema de ficheros sería esto:
for file in `find /bin/ /etc/ lib/ mnt/ opt/ root/ sbin/ shares/ srv/ tmp/ usr/ var/ vmlinux.lz nocomprlist `; do tftp -p -l "$file" -r "$file"
192.168.0.155; done ;

excluyo los directorios /dev /sys /proc por que tienen ficheros en uso, ficheros de bloques, etc… por que no se pueden copiar de la manera habitual

Como nota, revisar /var/syslog para ver si la subida de ficheros no se está realizando correctamete y por qué. Por defecto el directorio es /srv/tftp el usuario nobdoy y el group nogroup. Recuerda revisar los permisos.

ftp mirroring con lftp

He necesitado hacer un mirror de unos directorios que sólo estaban disponibles por ftp y necesito lanzar sincronizaciones periódicas de forma sencilla y cómoda, para ello he usado lftp una vieja herramienta que tenía ya enterrada.

Instalar lftp

apt-get install lftp

Lo más útil de lftp es la capacidad de copiar directorios de forma recursiva ya que por defecto el cliente ftp de toda la vida de las distrubicones de linux no lo soporta.

Como puedo hacer un mirroring:

lftp -u usuario,password ftp.midominio.tld
mirror /ruta/ftp/origen /ruta/local/b

 

ls: Fatal error: Certificate verification: Not trusted

Este error aparece cuando nuestro lftp no es capaz de verificar que el certificado remoto sea válido por lo que no nos permite continuar realizando operaciones en la máquina remota. Esto está bien, si el certificado es correcto, pero habitualmente nos encontraremos con certificados incorrectos o caducados, por lo que podremos desactivarlo, ya que no nos ofrece ningún nivel de seguridad, si el certificado no está correctamente instalado.

Para desactivarlo, yo he usado esta opción con éxito ( aunque hay varias variantes buscando en google ):

set ftp:ssl-allow no;

A lo que tengo que añadir que después de ejecutar este comando con el debug activo:

set debug 10

me ha sido imposible retornar el listado de directorios, y parece ser un bug. Este caso se observa al lanzar el comando `ls` y ver infinitamente el texto: Delaying before reconnect.

Desactivado el debug, funciona correctamente

set debug 0

Mirroring sites using ftp

Aquí os dejo un pequeño script para hacer migración de sitios usando ftp de una forma bastante rápida:

FTP_USER="tu usuario"
FTP_PASSWORD="tu password"
FTP_HOST=ftp.dominio.ltd
SOURCE=/ruta/remota/origen
DEST=/ruta/remota/destino
lftp -u"${FTP_USER},${FTP_PASSWORD}" -e "set ftp:ssl-allow no; mirror ${SOURCE} ${DEST} --only-newer --verbose --use-pget-n=10; quit" ${FTP_HOST}

A tener en cuenta:

  • -u”usuario,password” Es necesario usar las comillas ya que de esa forma escapamos los caracteres especiales que pueda tener el password
  • -e“ejecuta comandos una vez que abre la conexión”
  • set ftp:ssl-allow no No valida el certificado ssl del servidor ftp
  • –only-newer Sólo ficheros nuevos
  • –use-pget n=10 Usa 10 conexiones concurrentes

Configura wordpress con SSL

La seguridad en las comunicaciones es necesaria, y más vale tarde que nunca. Ahora podemos usar SSL de forma gratuíta gracias a Let’s Encrypt.

Let’s Encrypt es un proyecto de la Linux Foundation con el que colaboran grandes empresas como Cisco y organizaciones como Electronic Frontier Foundation que tiene como objetivo proveer de manera gratuíta certificados de seguridad para todos. Hasta ahora y aún sigue siendo así los certificados cuestan entre 60 y 300 euros dependiendo del tipo de certificado, seguro, etc… con Let’s Encrypt podremos usar un certificado sin tener que gastarnos dinero, el único incoveniente es que caduca a los 90 días y hay que renovarlo. Aunque esto no quiere decir que lo tengas que hacer manualmente, ¡ que trabaje el CRON !

He instalado este certificado para mi dominio, de manera muy sencilla por que uso Plesk y existe un plugin[2] y he cambiado la configuración de wordpress en Ajustes / Generales / Dirección de WordPress (URL) y Dirección del sitio (URL) a https://www.senin.org

Te animo a que tambien uses SSL y muevas tu blog a ssl

[1]https://letsencrypt.org/getting-started/
[2]https://devblog.plesk.com/2015/12/lets-encrypt-plesk/

Hostingaldescubierto.com ha muerto

En septiempbre de 2007 creamos hostingaldescubierto.com un sitio donde poder colgar nuestras recetas para solucionar problemas relacionados con hosting y software de gestión de hosting: Plesk, que luego pasó a llamarse Parallels y ahora es conocido como Odin.
Son muchos años en los que fuimos dejando chuletas, parches, noticias, así como artículos de opinión de compañías del mundo del hosting.
Hostingaldescubierto, no fué muy relevante, pero seguíamos publicando información por puro placer divulgativo. Hoy ya es un site muerto, como tantos otros, la falta de tiempo, el cambio de trabajo, etc… ha concluído en el cierre de hostingaldescubierto, ya no tenía sentido mantener un site en que no se publicaba desde hacía tiempo y que apenas tenía visitas.
Para no perder muchas de las ‘recetas’ he importado los artículos a mi blog, para que al menos estén vivas en algún sitio.
Espero que sea útil para alguien, al igual que cuando comenzamos.

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

quitar link preview de wordpress

Pues ahora wordpress te hace un bonito preview de los links que interpreta en el texto de tu post, queda muy bonito, pero a mí no me convence y para desactivarlo hay que instalar un pluguin 🙁 https://wordpress.org/plugins/disable-embeds/