Trabajando con GitHub de forma efectiva
Ya me han preguntado varias veces cómo trabajar de forma efectiva con GitHub, así que he decidido dedicarle un post.
Primero contaré algunas cosas básicas, para terminar explicando cómo trabajar con forks.
Recomiendo echar un ojo a mi post sobre el Uso básico de Git antes de embarcarse en esta aventura…
Uso básico de Git y GitHub
Crear un repositorio
Lo primero es crear un repositorio. Para ello nos vamos a nuestra cuenta en GitHub, pulsamos sobre new repository
e indicamos el nombre, descripción y privacidad.
Opcionalmente podemos indicar cierto contenido a añadir, como el archivo README
, .gitignore
o la licencia.
Una vez hecho esto, basta con clonarse el repositorio. GitHub nos ofrece instrucciones sobre cómo hacerlo:
|
|
Sin embargo, hay veces que no tenemos acceso a GitHub o bien que ya tenemos el repositorio en otro sitio. Así que podemos añadir nuevos remotes a nuestra configuración local de git:
|
|
Voy a explicar esto un poco más en detalle: la primera línea le dice a git que añada un remote llamado origin
que apunte a la dirección git@github.com:USER/REPOSITORY.git
.
Cada vez que realicemos una operación remota (fetch
, push
, pull
, …), git necesita un remote para realizarla. Por defecto usará origin
si existe. Es decir, que estas dos órdenes son equivalentes:
|
|
La segunda línea del código de más arriba, el push
, le indica a la copia local de git que quieres que la rama actual se sincronice con la rama master
del remote con mombre origin
. De esta manera, cuando hagamos commit
sobre esta rama git nos permitirá hacer push
directamente sobre esa rama.
Hay que recordar que para git las ramas son sólo referencias, y las referencias locales pueden diferir de las referencias remotas. Es más, distintos remotes pueden tener distintas referencias.
Veremos más de esto al final del post.
Actualizar un repositorio
Lo siguiente es actualizar el repositorio. La mejor manera es usar fetch
, para descargarse los objetos y referencias remotos. Ojo: sólo se los descarga, pero no actualiza nada en local; es decir: el HEAD
seguirá apuntando al mismo sitio y si miramos las branch
no habrán cambiado. Sin embargo, tendremos más commits
, tags
, referencias (show-ref
), … que podremos utilizar.
A continuación podemos realizar distintas acciones locales:
- actualizar el
HEAD
si no hay conflictos (conocido comofast-forward
), haciendo unrebase
o unmerge --ff-only
. - actualizar el
HEAD
a pesar de los conflictos conrebase
. - mergear el
HEAD
con lo descargado, conmerge
.
Y hasta aquí. Esta parte daría para mucho, así que no me voy a extender.
Enviar cambios
Una vez se han hecho cambios locales, tendremos commits
. No voy a entrar aquí en esa parte. El caso es que queremos persistir esos cambios en el repositorio remoto.
Para ello se utiliza push
, indicando qué remote se quiere utilizar. Como ya hemos dicho, origin
será el remote por defecto.
Uso colaborativo de GitHub
Fork
Eventualmente sentiremos la necesidad de arreglar un problema en un repositorio ajeno. Aquí es donde comienza la gracia.
Lo primero que podemos hacer es irnos a GitHub y pulsar sobre el botón fork. Esto realizará una copia del repositorio en nuestra cuenta.
A continuación nos vamos a nuestra cuenta y obtenemos la URL para poder hacer un clone
.
Otra opción es realizar un clone
del repositorio principal y trabajar sobre él, aun a sabiendas de que no podemos hacer push
. Eso no es importante, ya que después podremos reorganizar los remotes.
Actualizar un Fork
Supongamos que hemos hecho un fork
y que nuestro repositorio ha quedado desactualizado, ya que en nuestra cuenta de GitHub tenemos una copia que no es la buena.
En el caso fácil, hicimos un clone
de nuestro fork, podemos actualizar usando directamente la URL:
|
|
Pero claro, nos podemos olvidar, así que es mejor actualizar nuestras referencias locales por si lo necesitamos en el futuro. Para ello, le damos un nombre a la URL (yo suelo utilizar “github”, por razones obvias :D):
|
|
Y a continuación podemos usar el “alias”:
|
|
En el caso de que hubiéramos seguido el camino difícil, es decir, nos clonamos directamente el repositorio principal y no nuestro fork, tampoco es un problema, ya que podemos reorganizar los remotes:
|
|
Y a continuación añadimos nuestro fork, tal y como se indicó un poco más arriba. El resultado será el mismo.
En cualquier momento podéis ver qué remotes tenéis configurados mediante:
|
|
Conclusión
Hace poco que leí el artículo Why I Don’t Hate Git: Hidden Consistency, de Armin Ronacher, en el que decía:
Learning the UI vs the Concept
En mi opinión debería ser al revés: “Aprender el Concepto en lugar de la Interfaz”. No os quedéis sólo con el comando que hace lo que necesitáis: preguntáos cómo hace lo que hace.
En ese mismo artículo dice también algo muy curioso:
The .git/HEAD was still a symlink to the current branch and a documented way to commit was this dance:
1
echo "Commit message" | git-commit-tree $(git-write-tree) > .git/HEAD
Only later an alias for commit was added, and even then the tutorial was still … rough I would say.
Puede parecer exagerado, pero queda claro que no hay magia. En vuestras copias locales de git podéis mirar el contenido de .git/HEAD
. Es un archivo de texto plano. Y contiene una referencia a la rama actual; al changeset actual si estáis detached.