-
Notifications
You must be signed in to change notification settings - Fork 17
/
02-git-github.Rmd
590 lines (418 loc) · 19.8 KB
/
02-git-github.Rmd
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
---
title: "Git/github"
author:
- "Adolfo De Unánue T."
- "Andrea Fernández"
date: "`r format(Sys.time(), '%Y-%m-%d')`"
output:
html_document:
toc: yes
toc_float: yes
---
# Control de versiones con Git
## Introducción
Un controlador de versiones es una herramienta que gestiona los
cambios de un conjunto de archivos. Cada conjunto de cambios genera
una nueva versión de los archivos. El controlador de versiones
permite, además de la gestión de cambios, recuperar una versión vieja
de los archivos o un archivo, así como resolver conflictos entre versiones.
Aunque su principal uso es para agilizar la colaboración en el
desarrollo de proyectos de *software*, también puede utilizarse para
otros fines (como estas notas) e inclusive para trabajar solo (como en
una tesis o proyecto).
Especificamente, un controlador de versiones ofrece lo siguiente:
1. Nada de lo que es *"comiteado"* (_commited_, ahorita vemos que es eso)
se perderá.
2. Lleva un registro de *quién* hizo *qué* cambios y *cuándo* los
hizo.
3. Es *casi* imposible (nota el casi...) sobreescribir los cambios de tu
colaborador. El controlador de versiones notificará que hay un
**conflicto** y pedirá que lo resuelvas antes de continuar.
En esta clase usaremos `git`, aunque debemos de notar que no es el
único controlador de versiones que existe, entre los más populares se
encuentran `bazaar`, `mercurial` y `subversion` (Aunque este último
pertenece a una diferente clase de controladores de versiones).
## Un poco de inspiración
Git no se debe de confundir con github. Sin embargo, github es una de las
razones por las cuáles se ha vuelto tan popular.
[Examinemos](https://github.com/trending) un poco lo que se puede hacer.
Recordemos que Git es un software aparte de Github pero es lo que verdaderamente
hace que todo funcione. Vive en tu computadora y puedes trabajarlo en local si
así lo deseas.
## Instalación
### Windows
Windows no será el sistema operativo que utilizaremos en este taller. Sin
embargo, si lo quieren incorporar fuera de la máquina virtual, deberán instalar
git y el emulador de consola de éste. [En esta liga](http://msysgit.github.io/)
encontrarás el ejecutable para instalar en Windows.
### Linux
####Fedora
```bash
yum install git-core
```
####Debian
```bash
apt-get install git
```
### Mac
Hay dos maneras para usuarios de mac.
1. La fácil es instalando *Xcode Command Line Tools*. Si estás en Mavericks (10.9)
o superior simplemente puedes hacerlo corriendo `git` en la terminal. Si no lo
tienes instalado aún, te prompteará para hacerlo.
2. Si quieres una versión más actualizada, lo puedes instalar vía binarios.Se mantiene
un instalador para git OSX Git y está disponible para su descarga [aquí](http://git-scm.com/download/mac).
## Configurando tu git
Abre una terminal y ve a tu carpeta `home`.
Ahí, teclea lo siguiente, para establecer el usuario, correo
(que usará `Github` para identificarte por ejemplo), si colorea la
salida, y qué editor usará por default para resolver conflictos.
```
git config --global user.name "<Tu Nombre>"
git config --global user.email "<Tu correo-e>"
git config --global color.ui "auto"
git config --global core.editor "emacs" # Recomendado, puede ser otro
```
Para mirar nuestras configuraciones, podemos teclear:
```git
git config --list
```
[Para más opciones de configuración usa esta liga.](http://git-scm.com/book/en/Getting-Started-First-Time-Git-Setup)
## Creando un repositorio
El **repositorio** es la carpeta donde `git` guarda y gestiona todas
las versiones de los archivos.
Crea una carpeta en tu `$HOME` llamada `big-data-test`, ingresa a
ella e inicializa el repositorio con `git init`. ¿Notas algún cambio?
¿Qué comando usarías? Hay una carpeta ahí ¿no la ves? ¿Cómo puedes ver
una carpeta oculta?
La carpeta `.git` es la carpeta donde se guarda todo el historial, si
la borras, toda la historia del repositorio se perderá.
Podemos verificar que todo esté bien, con el comando `status`.
```
git status
> On branch master
> Initial commit
> nothing to commit (create/copy files and use "git add" to track)
```
## Llevando registro de los cambios a archivo
Crea un archivo llamado `hola.txt` de la siguiente manera (ALERTA:
nuevos comandos de **CLI**):
```
touch hola.txt
echo "¡hola mundo!" > hola.txt
git status
```
(Para ver el contenido de `hola.txt` utiliza el comando `cat hola.txt`).
El mensaje de `untracked files` significa que hay archivos en el
repositorio de los cuales `git` no está llevando registro, para que
`git` lo haga, debes de **agregarlos** (`add`):
```
git add hola.txt
git status
```
Ahora `git` sabe que debe de llevar registro de los cambios de
`hola.txt`, pero aún no se *comprometen* los cambios al repositorio
(`Changes to be commited: ...`). Para *comitearlos*:
```
git commit -m "Saludando"
```
Usamos la bandera `-m` para agregar un mensaje que nos ayude a
recordar más tarde que se hizo y por qué. El mensaje es *obligatorio*.
Si ejecutamos
```
git status
```
nos indica que todo está actualizado (`up to date`). Podemos ver la
historia de cambio con `git log`.
Edita `hola.txt` usando emacs, luego, ejecuta `git status`
La parte clave es `no changes added to commit`. Hemos cambiado el
archivo, pero aún no están "comprometidas" o guardadas en el repositorio.
Para ver que ha cambiado usamos lo siguiente
```
git diff
```
Hagamos `commit` de estos cambios.
```
git commit -m 'actualizamos hola.txt'
```
Pero `git` no nos dejará, ya que no lo agregamos antes al índice del
repositorio. Agrégalo y repite el `commit` (¿Recuerdas como hacerlo
con los tips de navegación?).
## El flujo de trabajo
Git maneja este flujo:
Modificando los archivos --> `git add` --> en el área de *staging*
(listos para *commit*) --> `git commit` --> Repositorio (guardados
permanentemente en **tu** computadora.)
Modifica de nuevo `hola.txt`. Observa los cambios y agrégalo. ¿Qué
sucede si vuelves a ejecutar `git diff`?
`Git` dice que no hay nada, ya que para `git` no hay diferencia entre
el área de *staging* y el último *commit* (llamado `HEAD`). Para ver los cambios, ejecuta
```
git diff --staged
```
esto muestra las diferencias entre los últimos cambios *comiteados* y
lo que está en el área de *staging*. Ahora realiza el `commit`, verifica
el estatus y revisa la historia.
## Recapitulando. Los verbos más importantes.
### Agregar (Adding)
Cuando haces cambios o agregas archivos o carpetas, quieres ponerlos
bajo el controlador de versiones.
Para esto, debes hacerle saber a *git* cuáles son los archivos sobre los cuáles
tiene que poner atención (es decir, en lenguaje git, quieres que tracké (**track**)
esos cambios y/o archivos).
**Git add** es la operación que permite que agregues (*add*) esos cambios al
índice (**index**) (la manera en la que git mantiene el registro de todos los
cambios).
Algunos tips para utilizar `git add`
- `git add .` agrega todos los cambios/archivos *nuevos* correspondientes al directorio o subdirectorio en el que estas (¿Recuerdas pwd? Los archivos ahí.)
- `git add -u .` agrega al índice todos los cambios de los archivos que ya estaban en el índice pero que fueron *modificados* en el directorio o subdirectorio en el que estas.
- `git add -A` agrega *todo* [¡tengan cuidado!]
Una vez que agregas unos cambios, se dice que éstos están *staged*. De cualquier
modo, puedes cambiar de opinión acerca de los cambios utilizando `git reset HEAD <file>`.
### Comiteando (commiting)
Puedes commitear (**commit**) los cambios que han sido *staged*. Los commits son
la manera de decirle a git que ese es un checkpoint. Igual que en juegos de
computadora, un commit es un conjunto de cambios que ameritan que git guarde una
versión de el repositorio *hasta ese momento*. Esta es la operación en la que
realmente sucede el *versionamiento*.
Son, básicamente, **snapshots** de todos los archivos que ya stageaste para comitear.
Cada vez que commiteas, debes de proveer de un mensaje acompañante que resuma los
cambios realizados. Al menos, esa es la idea...
![](img/git_commit.png)
*Figura tomada de [XKCD](https://xkcd.com/1296/).*
Sean amables con sus compañeros de equipo y con **su yo futuro**. Los mensajes de
*commit* son útiles en el futuro cuando ya ni recuerdan qué hicieron o por qué.
Lo único que deben hacer es...
```bash
git commit -m "mensaje sencillo, INFORMATIVO y simple aquí"
```
## Explorando el pasado
Podemos ver los cambios entre diferentes **revisiones**, podemos usar
la siguiente notación: `HEAD~1`, `HEAD~2`, etc. como sigue:
```
git diff HEAD~1 hola.txt
git diff HEAD~2 hola.txt
```
También podemos utilizar el identificador único (el número enorme que
aparece en el `git log`), inténtalo.
Modifiquemos de nuevo el archivo `hola.txt`. ¿Qué tal si nos
equivocamos y queremos regresar los cambios? Podemos ejecutar el
comando
```
git checkout HEAD hola.txt
```
(Nota que `git` recomienda un *shortcut* para esta operación: `(use "git checkout -- <file>..." to discard changes in working directory)`)
Obviamente aquí podemos regresarnos las versiones que queramos, por lo
que podemos utilizar el identificador único o `HEAD~2` por ejemplo.
> **Ejercicio**
> Recorre el log con `checkout`, observa como cambia el archivo,
> usando `cat`.
Por último, `git` tiene comandos `mv` y `rm` que deben de ser usados
cuando queremos mover o borrar un archivo del repositorio, i.e. `git
mv` y `git rm`.
> **Ejercicio**
> Crea un archivo `adios.txt`, comitealo, has cambios, comitea y luego
> bórralo. No olvides hacer el último `commit` también.
## Ayuda
Nadie sabe todo. Accesar a la ducumentación siempre es la mejor opción. Poco a
poco te aprenderás los verbos de git.
Para accesar al manual de cada verbo solamente escribe en la terminal:
```git
$ git help <verb>
$ git <verb> --help
$ man git-<verb>
```
donde el <verb> se refiere a cualquier comando en git (y en general, si utilizas
la última forma (Si no conoces el comando, solo pregúntale a Google lo que
quieres hacer y checa las distintas posibilidades para elegir la que más se
acomoda a tu necesidad.)
Antes de continuar con [**Github**](http://github.com) quiero
recomendar que impriman la que mas les guste de estas ayudas visuales
[1](http://jan-krueger.net/wordpress/wp-content/uploads/2007/09/git-cheat-sheet.pdf),
[2](http://www.git-tower.com/blog/git-cheat-sheet-detail/),
[3](https://github.com/mattharrison/Git-Supervisual-Cheatsheet) o [esta](http://ndpsoftware.com/git-cheatsheet.html)
que es interactiva.
El concepto que no alcancé a ver aquí y que es muy poderoso es el de
*stash*, pero pueden deducir su comportamiento de la última ayuda visual.
# Github
## ¿Qué cambia de git a github?
Github es un repositorio central, con una interfaz web bonita, pero
fuera de eso, nada impediría que trabajen ustedes con su computadora y
la de sus amigos usando los comandos que en esta sección vamos a
mostrar, ya que `git` es un sistema distribuito de control de
versiones y **ningún nodo** tiene preferencia sobre los demás, pero
por comodidad, podemos usar **Github** de tal manera.
Los comandos de transporte.
![](img/githuboverview.png)
*Figura tomada del [blog de Oliver Steele](http://blog.osteele.com/posts/2008/05/my-git-workflow/).*
Se introducen los verbos de git `clone`, `pull` y `push`.
## Configuración de credenciales
Github siempre pedirá tu contraseña y tu password. Como están trabajando en sus
computadoras, no queremos que nos pida una y otra vez las credenciales pues
alenta mucho el flujo de trabajo. Nunca dejen sus credenciales en cualquier
computadora.
Si no se configuran las credenciales, cada vez que quieras hacer `clone`,
`pull` o `push` de un repositorio privado, te pedirá tus credenciales. Dado que
el repo del taller es privado, configuremos.
### ssh
La opción preferida y segura es via `ssh`. Solo se deben seguir las instrucciones
para el sistema operativo de su elección [aquí](https://help.github.com/articles/generating-a-new-ssh-key-and-adding-it-to-the-ssh-agent/).
Y nunca tendrás que introducir tus credenciales. Es la manera más segura de
conectar tu versión local de los respositorios con github.
### https
También se puede configurar vía https and guardar las credenciales usando el [credential helper](https://help.github.com/articles/caching-your-github-password-in-git/)
## El repositorio del taller
El repositorio está en:
```
https://github.com/animalito/basic-toolkit
```
Lo primero que hay que hacer es **forkear** este repositorio. La
operación de `fork` creará una copia de repo de la clase en su usuario
de github.
![](img/forkbutton.png)
Para obtener una copia de trabajo en su computadora deberán
de **clonar** su repositorio:
Una vez que tengas configuradas tus credenciales, asegurate de clonar tus repositorios
usando el conector ssh apropiado, es decir, vayan al [repo del taller](https://github.com/animalito/basic-toolkit) y vayan a la sección de
*Clone or download* en la esquina superior derecha. Pueden copiar el link directo de la interfaz como se muestra en la imagen.
![](img/clone_ssh.png)
Noten que, si hubieran configurado sus credenciales con **https** y no con **ssh**
deberán copiar el otro link (que normalmente es `https://github.com/<usuario-u-organizacion/<nombre-del-repositorio>.git`)
Es importante que sepan de la otra manera de configurar pues, en muchos casos,
la conexion por ssh está bloqueada en las empresas y no podrán replicar esa
configuración en sus computadoras de trabajo.
Regresando a nuestro caso, el link que copiaron debe verse `[email protected]:<usuario-u-organizacion/<nombre-del-repositorio>.git`.
Después, se van a la terminal, buscan el directorio en el que quieren tener
su repositorio y lo clonan ahí.
```
git clone https://github.com/<usuario_github>/basic-toolkit.git
```
Esto creará una carpeta `basic-toolkit` en su directorio en el que lo hayan
puesto. Por ahora, supongamos que lo clonaron directo en su `$HOME`.
Ve a la carpeta `alumnos` y crea una carpeta cuyo nombre sea tu nombre
de usuario en github. En esta carpeta realizarás los ejercicios,
proyectos, etc.
Crea dentro de tu carpeta un archivo que se llame `prueba.txt`,
agrégalo, verifica los cambios, has `commit`. El siguiente paso es
**subir** los cambios al repositorio de github. Para hacerlo hacemos
```
git push origin master
```
El verbo `push` es el encargado de la acción de subir los
cambios. `origin` se refiere al repositorio del cual clonamos la copia
local (en nuestra computadora) y `master` se refiere al `branch` (este
es un tema avanzado, por ahora ustedes trabajaran siempre en el branch master, que es el default).
Abre tu repositorio en github y observa que tus cambios ahí
están. Ahora, vamos a simular que alguien está interactuando con tu
repositorio. Desde el sitio web, ve a tu carpeta y has clic en el
símbolo de `+` para agregar un archivo (verifica de nuevo que estés en
tu carpeta). Llamalo `prueba2.txt` y agrega algo de texto. Para
guardar los cambios aprieta el botón `Commit new file`.
En tu computadora, en la carpeta
`basic-toolkit`, para obtener los últimos cambios utiliza:
```
git pull origin master
```
En tu carpeta debería de aparecer el archivo `prueba2.txt`. Ahora
quedan por contestar dos preguntas: (1) ¿Cómo actualizo el repositorio
`tu-usuario/basic-toolkit` con cambios que yo realicé?
y (2) ¿Cómo actualizo mi repositorio con los cambios del repositorio
de `animalito/basic-toolkit`? (para bajar las notas nuevas que se van subiendo)
Para ambas preguntas es necesario aclarar el concepto de los `remote`:
Si ejecutas
```
git remote -v
origin https://github.com/<usuario>/basic-toolkit.git (fetch)
origin https://github.com/<usuario>/basic-toolkit.git (push)
```
Vamos a agregar como `remote` el repositorio
`animalito/basic-toolkit`:
```
git remote add taller https://github.com/animalito/basic-toolkit.git
```
Ejecuta de nuevo `git remote -v`
```
git remote -v
origin https://github.com/animalito/basic-toolkit.git (fetch)
origin https://github.com/animalito/basic-toolkit.git (push)
taller https://github.com/animalito/basic-toolkit.git (fetch)
taller https://github.com/animalito/basic-toolkit.git (push)
```
Entonces, la respuesta a la primera pregunta (¿cómo entrego mis ejercicios)
es una técnica llamada `pull-request` que en
mi conocimiento **solo** se puede realizar desde el navegador. Has
click en `Pull Requests` (como se muestra en la imagen)
y sigue las instrucciones de la pantalla.
![](img/pullrequest.png)
Una vez **autorizado** el `pull-request` es necesario hacer
```
git pull taller master
git push origin master
```
La primera instrucción baja los cambios del repositorio central a su copia **local**
del repositorio, el segundo los sube a su repositorio particular (otra copia pero
la versión que guarda github en su fork particular).
Para responder la segunda pregunta (¿cómo bajo lo que han subido otros al repo central?)
usamos la misma cadena de comandos:
```
git pull taller master
git push origin master
```
Nota que ahora no realizamos un `pull-request`.
## ¿Cuál debería de ser mi *workflow* de trabajo?
En el día a día, se recomienda tener un sano *workflow* de github. Es sencillo
y pronto te será muy natural.
![flujo](img/simple-daily-git-workflow.jpg "workflowdiario")
> Trabajo en equipo usando git
Una posible forma de utilizar un worklow distribuido en equipos es el [Integration Manager Workflow](http://git-scm.com/book/en/Distributed-Git-Distributed-Workflows#Integration-Manager-Workflow). En particular, este es el flujo que utilizaremos en el taller pues
ustedes no tienen permisos de escribir en el repositorio de clase de manera directa, es decir,
siempre deben de pasar por un **pull request** que debe ser autorizado por el
profesor.
> **Ejercicio**
> En esta parte, realizaremos un ejemplo completo del workflow que se espera
> utilicen para entregar sus ejercicios.
Asumiendo que clonaron en su home (sino vayan al lugar donde tienen el folder del repo).
```
cd basic-toolkit
git pull origin master # SIEMPRE empezamos con un pull. ¿Por qué?
```
- trabajas en varios archivos
- trabajas
- editas
- hackeas
Y conforme avances (unas cuantas veces al día o cuando por fin algo te salió y
funciona)
```
git status
git add <archivos modificados o nuevos>
git commit -m "<comentario acerca de que fue lo que se cambió>"
git push origin master
git status
```
Todo estará bien si
- `git status` respondió con:
```
On branch master
Your branch is up-to-date with 'origin/master'.
nothing to commit, working directory clean
```
- En tu repo están tus cambios.
Cuando quieran enviar los ejercicios que realizan el `pull-request`. Y habrán
terminado si en el repositorio `animalito/basic-toolkit`
están sus cambios. No se aceptarán sus cambios si con ellos se rompe el
trabajo de alguien más. Por eso es que estaremos utilizando este workflow.
## .gitignore
`.gitignore` es un archivo específico de texto plano pensado para que
no se suban archivos a los repositorios que, aunque
pueden ser útiles en el ambiente local, si subimos a github pasara una de las
siguientes:
- Github no te lo permitirá pues el archivo es muy grande. Pasa seguido entre los que trabajan con grandes datos.
- Está dentro de los limites de Github pero todos los que comparten repositorio contigo te odiarán pues se tardará siglos en bajar tu actualización.
- Tendras un repositorio muy sucio.
Para eso, está diseñado el archivo `.gitignore` pues, básicamente, permite definir
extensiones que por default nunca te mostrará a la hora de pedir un `git status`.
Para *overridear* el `.gitignore` se debe de agregar el archivo con la bandera `-f`. Piensen
muy bien antes de hacer esto pero a veces es necesario.
El repositorio que compartimos tiene uno en el *home* [del repo](https://github.com/animalito/basic-toolkit/blob/master/.gitignore).
Se pueden poner tantos `.gitignore` como subfolders existan en un repositorio y
aplican de arriba hacia abajo, es decir, aplican para el lugar en donde estén y
para todas las subcarpetas contenidas en ese directorio.