Kitabı oku: «Raspberry Pi® a fondo para desarrolladores», sayfa 10

Yazı tipi:

Procesos de Linux

Un proceso es una instancia de un programa que se está ejecutando en el SO. Debemos ser capaces de gestionar los procesos en ejecución en nuestro RPi, comprender los procesos de primer y de segundo plano y cerrar inmediatamente (kill, matar en inglés, pero también es el nombre literal de un comando Unix y Linux) cualquier proceso que se cuelgue.

Cómo controlar los procesos en Linux

El comando ps lista los procesos en ejecución en cada momento en el RPi. Tras escribir ps, vemos que el siguiente RPi está ejecutando dos procesos de usuario, el intérprete de comandos bash, con PID (Process ID, identificador de proceso) 912, y el propio comando ps, con PID 25481. El PID de ps será diferente siempre que lo ejecutemos porque se cierra cada vez que da los resultados:

pi@erpi ~ $ ps

PID TTY TIME CMD

912 pts/0 00:00:05 bash

25481 pts/0 00:00:00 ps

Para ver todos los procesos en ejecución, escribimos ps ax. En el ejemplo siguiente se aplica un filtro con los caracteres "ntp" para descubrir información acerca de los procesos ntp en ejecución en el RPi.

pi@erpi ~ $ ps ax | grep ntp

1069 ? Ss 0:00 /usr/sbin/ntpd -p /var/run/ntpd.pid -g -u 107:112

1077 ? S 0:00 /usr/sbin/ntpd -p /var/run/ntpd.pid -g -u 107:112

1132 ttyAMA0 S+ 0:00 grep --color=auto ntp

Está claro que se ejecutan tres procesos diferentes para el servicio, lo que le permite manejar múltiples conexiones simultáneas. En este ejemplo, todos los hilos están a la espera de que se complete un evento (S), PID 1069 es el líder de la sesión (Ss), 1077 es su clon (S) y el proceso grep, PID 1132, está en el grupo de primer plano (S+). Como vimos anteriormente, una llamada a systemctl status ntp proporciona información sobre los servicios en ejecución en el RPi, es decir, si ejecutamos la llamada veremos que los PID de los procesos se corresponden con los que muestra el comando ps.

Procesos en primer y en segundo plano

Linux es un sistema operativo multitarea que nos permite ejecutar múltiples procesos en segundo plano (background) mientras usamos un programa que se ejecuta en primer plano (foreground). Este concepto es muy similar al comportamiento que presenta una interfaz gráfica basada en ventanas, como las de Windows, Mac OS X, etc. Por ejemplo, el reloj del escritorio continúa actualizando la hora al mismo tiempo que navegamos por Internet.

Lo mismo es válido para aplicaciones que se ejecuten en una ventana de terminal. Para demostrar esto, veamos un pequeño fragmento de código fuente en C que muestra la frase "Hello World!" cada cinco segundos en una ventana de terminal de Linux. El funcionamiento preciso del código se verá en el capítulo 5, pero por el momento basta con que el lector lo escriba literalmente en un archivo, que llamará HelloRPiSleep.c, mediante el editor nano trabajando en la cuenta de usuario pi; para ello:

pi@erpi ~ $ cd ~/

pi@erpi ~ $ nano HelloRPiSleep.c

pi@erpi ~ $ more HelloRPiSleep.c

#include<unistd.h>

#include<stdio.h>

int main(){

int x=0;

do{

printf("Hello Raspberry Pi!\n");

sleep(5);

}while(x++<50);

return 0;

}

El programa consiste en un bucle que realiza 50 iteraciones, en cada una de las cuales muestra un mensaje y espera 5 segundos. Después de guardar el archivo como HelloRPiSleep.c, lo compilaremos como un ejecutable mediante el comando siguiente (-o especifica el nombre del archivo ejecutable):

pi@erpi ~ $ gcc HelloRPiSleep.c -o helloRPiSleep

pi@erpi ~ $ ls -l helloRPiSleep

-rwxr-xr-x 1 pi pi 5864 Jun 20 16:40 helloRPiSleep

Si todo ha funcionado, tendremos tanto el archivo de código fuente como el ejecutable llamado helloRPiSleep. Observe cómo este muestra la marca, x, de archivo ejecutable. Podemos, ahora, ejecutarlo sin más:

pi@erpi ~ $ ./helloRPiSleep

Hello Raspberry Pi!

Hello Raspberry Pi! ...

Continuará mostrando este mensaje cada 5 segundos. Podemos terminar su ejecución con Control+C. Sin embargo, para ejecutarlo en segundo plano tenemos dos opciones.

Primero podemos, en lugar de pulsar Control+C para terminar el proceso, pulsar Control+Z y, luego, en el símbolo del sistema, escribir el comando bg (por background, como ya hemos visto).

pi@erpi ~ $ ./helloRPiSleep

Hello Raspberry Pi!

^Z

[1]+ Stopped ./helloRPiSleep

pi@erpi ~ $ bg

[1]+ ./helloRPiSleep &

pi@erpi ~ $ Hello Raspberry Pi!

Hello Raspberry Pi!

Hello Raspberry Pi!

Cuando pulsamos Control+Z, ^Z aparece en la salida. Cuando escribimos bg, el proceso se sitúa en segundo plano, donde continúa su ejecución. De hecho, podemos continuar usando el terminal, pero resultará frustrante porque cada cinco segundos aparecerá el mensaje "Hello Raspberry Pi!" El comando fg nos permite devolver este proceso al primer plano.

pi@erpi ~ $ fg

./helloRPiSleep

Hello Raspberry Pi!

^C

pi@erpi:~$

Cuando pulsamos Control+C, que aparece como ^C, la aplicación se detiene.

La otra manera de poner la aplicación en segundo plano consiste en añadir el símbolo ampersand, &, al final de su nombre:

pi@erpi ~ $ ./helloRPiSleep &

[1] 30965

pi@erpi ~ $ Hello Raspberry Pi!

Hello Raspberry Pi!

El proceso se ha situado en segundo plano y su PID es 30965, en este caso. Para detener el proceso, usamos ps para encontrar el PID:

pi@erpi ~ $ ps aux|grep hello

pi 30965 0.0 0.0 1612 304 pts/0 S 20:14 0:00 ./helloRPiSleep

pi 30978 0.0 0.1 4208 1828 pts/0 S+ 20:15 0:00 grep hello

Para terminar el proceso, use el comando kill:

pi@erpi ~ $ kill 30965

[1]+ Terminated ./helloRPiSleep

Podemos confirmar la terminación del proceso usando ps de nuevo. Si el proceso no termina de inmediato, usaremos el argumento -9 para asegurarnos de que lo haga. Por ejemplo: kill -9 30965. Un comando diferente, pkill, termina un proceso a partir de su nombre. Así, en este caso:

pi@erpi ~ $ pkill helloRPiSleep

Otro comando que merece la pena mencionar es watch. Este ejecuta un comando a intervalos regulares y muestra el resultado en terminal a pantalla completa. Por ejemplo, para ver el log de mensajes del núcleo, escribimos:

pi@erpi ~ $ watch dmesg

Podemos concretar la duración del intervalo entre ejecuciones mediante -n seguido del número de segundos. Una buena manera de comprender el funcionamiento de watch consiste en ejecutarlo del siguiente modo:

pi@erpi ~ $ watch -n 1 ps a

Every 1.0s: ps a Sat Jun 20 20:22:39 2015

PID TTY STAT TIME COMMAND

912 pts/0 Ss 0:06 -bash

31184 pts/0 S+ 0:01 watch -n 1 ps a

31257 pts/0 S+ 0:00 watch -n 1 ps a

31258 pts/0 S+ 0:00 sh -c ps a

31259 pts/0 R+ 0:00 ps a

Veremos que el PID de ps, sh y watch cambia cada (1) segundo, lo que deja claro que watch está realmente ejecutando el comando (ps) al pasarlo a un nuevo intérprete de comandos mediante sh -c. La razón por la que watch aparece dos veces en la lista es que se reproduce a sí mismo temporalmente en el momento exacto en el que ejecuta ps a.

Otros temas de Linux

En este punto del libro, el lector ha podido revisar los principales comandos para trabajar con Linux en el RPi. Sin embargo, el tema de la gestión de sistemas Linux da mucho más de sí. Por ejemplo: ¿cómo configurar un adaptador WiFi? ¿Cómo usar cron para planificar (schedule) trabajos con el RPi? Estos temas se analizarán en los capítulos restantes del libro. Sin ir más lejos: la programación de trabajos con cron se trata en el capítulo 12, en el contexto de los dispositivos IoT.

Cómo utilizar Git para el control de versiones

De manera sencilla podemos decir que Git es un sistema que nos permite registrar cualquier cambio que se introduzca en el contenido de un proyecto de software a medida que avanza su desarrollo. Git, diseñado también por Linus Torvalds, se emplea hoy en la línea principal de desarrollo del núcleo de Linux. Git es un sistema increíblemente útil, que debemos entender bien por dos motivos principales: podemos utilizar Git en el desarrollo de nuestro propio software y además nos permite aprender a trabajar con distribuciones de código fuente del núcleo de Linux.

Git es un sistema distribuido de control de versiones, o DVCS (Distributed Version Contol System) que facilita el control del código fuente de un proyecto. Un sistema de control de versiones, VCS, registra y gestiona cualquier cambio introducido en documentos de cualquier tipo. Normalmente, los documentos que cambiemos se destacarán con números de revisión y marcas de tiempo. Se pueden comparar revisiones y hasta regresar a versiones antiguas de los documentos. Hay dos tipos de sistemas VCS:

❏Centralizados (CVCS): estos sistemas, como Apache Subversion (SVN), funcionan con la premisa de que existe una copia "maestra" única del proyecto. El flujo de trabajo es simple y directo: bajamos los cambios desde un servidor central, introducimos los nuestros propios y los volvemos a subir como definitivos a la copia maestra (esta subida definitiva de los cambios se denomina "commit", término típico también de las bases de datos; en español su uso como sustantivo ("hacer commit") es abrumadoramente mayoritario en el entorno informático, y es el que usaremos aquí).

❏Distribuidos (DVCS): usando estos sistemas, por ejemplo Git y Selenic Mercurial, no bajamos cambios, sino que clonamos el repositorio completo, incluido todo el histórico de cambios. El clonado del repositorio produce una copia tan exacta como una copia maestra, que hasta puede llegar a actuar como tal si fuera preciso. Por fortuna, los estándares actuales hacen que los documentos de texto plano y los archivos de código fuente no ocupen mucho espacio en disco. Una precisión importante: el modelo DVCS no excluye el uso de un repositorio maestro central para todos los usuarios. Véase, por ejemplo, git.kernel.org.

La ventaja principal de un DVCS frente a un CVCS es la posibilidad de hacer

commit rápidamente y probar las modificaciones localmente, en nuestro propio sistema, sin tener que subirlas antes a ninguna copia maestra. Esto permite la flexibilidad de poder subir los cambios solo cuando alcancen un nivel apropiado de calidad. La única desventaja significativa es el espacio en disco que exige el almacenamiento de todo el proyecto con su histórico de cambios, que va creciendo con el paso del tiempo.

Git es un DVCS centrado en el control y gestión de código fuente. Nos permite crear desarrollos paralelos que no afecten al original. Podemos regresar a una versión anterior de alguno de los archivos de código fuente, o bien a una de todo el proyecto. El proyecto, con sus archivos asociados e histórico de cambios, se denomina "repositorio" (repository). Esta capacidad resulta particularmente útil en proyectos de programación a gran escala, en los que es posible optar por una dirección para el desarrollo que, finalmente, acabe por resultar infructuosa. También es importante la facilidad para el desarrollo en paralelo cuando se tiene a varias personas trabajando en el mismo proyecto.

Git está escrito en C y, aunque se creó para cubrir la necesidad de control de versiones en el desarrollo del núcleo de Linux, se utiliza ampliamente en otros proyectos de código abierto como Eclipse o Android.

La manera más fácil de entender el manejo de Git es usarlo. Por tanto, hemos estructurado la sección siguiente en forma de guía paso a paso. Si todavía no lo tiene, Git se instala con facilidad mediante el comando sudo apt install git, así que no debería tener problemas para seguir los pasos directamente en el terminal. Este libro emplea GitHub como repositorio remoto de los ejemplos de código fuente. Salvo realizar commit de código fuente en el servidor, el lector podrá hacer todo lo expuesto en esta guía sin crear una cuenta en GitHub. No obstante, GitHub permite crear cuentas de repositorio públicas de forma gratuita, pero si queremos un repositorio privado, por ejemplo para desarrollos que deban salvaguardar derechos de propiedad intelectual, tendremos que pagar una cuota.

NOTA Si el lector planea embarcarse en el desarrollo de un proyecto grande y prefiere que no esté públicamente disponible en www.github.com ni pagar cuota de suscripción alguna, es posible hospedar repositorios privados de pequeña escala en sitios como bitbucket.org y gitlab.com. Con un poco más de trabajo, hasta es posible configurar GitLab en nuestro propio servidor, ya que existe una versión de código abierto de la plataforma.

Una introducción práctica

Para esta guía, hemos creado un repositorio llamado "test" en GitHub. En principio solo contiene un archivo, README.md, con una descripción breve del proyecto "test".

Como podemos ver en la figura 3-4, casi todas las operaciones son locales. Git realiza una suma de verificación en cada archivo antes de almacenarlo. Suma que garantiza que Git detecte cualquier modificación realizada fuera del propio repositorio Git, incluidas las que pudieran derivarse de la corrupción del sistema. Git emplea códigos hash de 40 caracteres para las sumas de verificación. De este modo, es capaz de registrar los cambios entre repositorios locales y remotos, lo que, a su vez, hace posible toda la funcionalidad de operaciones locales.


Figura 3-4: El flujo de trabajo básico de Git.

Cómo clonar un repositorio (git clone)

Clonar un repositorio supone realizar una copia de todos los archivos que contenga el proyecto, junto con el histórico de cambios completo, y guardarla en nuestro disco duro. Haremos esta operación una sola vez. Para clonar el repositorio envíe el comando git clone seguido del nombre completo del repositorio:

pi@erpi / $ cd ~/

pi@erpi ~ $ git clone https://github.com/derekmolloy/test.git

Cloning into 'test'...

remote: Counting objects: 14, done.

remote: Compressing objects: 100% (5/5), done.

remote: Total 14 (delta 1), reused 0 (delta 0), pack-reused 9

Unpacking objects: 100% (14/14), done.

Checking connectivity... done.

Ahora tenemos una copia completa del repositorio "test" en el directorio /test. Nuestro repositorio es igual de completo que la versión en el servidor de GitHub. Si fuera necesario, este repositorio podría quedar disponible a través de una red, en un sistema de archivos o en otra cuenta de GitHub y serviría perfectamente como versión principal del repositorio. Aunque no sea necesario contar con un servidor central, generalmente lo hay, ya que de este modo múltiples usuarios pueden insertar (check in) código fuente en un repositorio maestro conocido. El repositorio se crea en el directorio /test y en este momento contiene lo siguiente:

pi@erpi ~/test $ ls -al

total 20

drwxr-xr-x 3 pi pi 4096 Jun 20 22:00 .

drwxr-xr-x 6 pi pi 4096 Jun 20 22:00 ..

drwxr-xr-x 8 pi pi 4096 Jun 20 22:00 .git

-rw-r--r-- 1 pi pi 59 Jun 20 22:00 README.md

Podemos ver el archivo README.md que se creó cuando el proyecto se inicializó en GitHub. Podemos usar more para ver el contenido del mismo. El directorio contiene un subdirectorio .git oculto, con los siguientes archivos y directorios:

pi@erpi ~/test/.git $ ls

branches description hooks info objects refs

config HEAD index logs packed-refs

El directorio oculto .git contiene toda la información acerca del repositorio, como mensajes de commit, archivos de log y los objetos de datos. Por ejemplo, la ubicación del repositorio remoto se encuentra en el archivo config.

pi@erpi ~/test/.git $ more config | grep url

url = https://github.com/derekmolloy/test.git

La sección "Otras lecturas", al final del capítulo, incluye una referencia a un magnífico libro sobre Git que está disponible en la red de forma gratuita. En él se describe con detalle la estructura del directorio .git. Por fortuna, ahora no debemos introducir ningún cambio en el directorio .git, puesto que tenemos comandos Git que lo harán por nosotros.

NOTA Esta guía paso a paso utiliza el propio repositorio "test" del autor. No obstante, no le resultará difícil al lector crear su propio repositorio en GitHub. Después de configurar una cuenta gratuita en GitHub, diríjase a "Create New" (crear nuevo) y, luego, "New repository" (nuevo repositorio). Dé un nombre y una descripción al repositorio y hágalo disponible públicamente, seleccione la opción para inicializarlo con un README y, luego, seleccione "Create Repository" (crear repositorio). A partir de aquí podrá seguir estas instrucciones con el repositorio de su propia cuenta, y, en consecuencia, podrá comunicarse desde su RPi con su propio repositorio en GitHub.

Cómo obtener información de estado (git status)

Ahora que contamos con nuestro repositorio, el paso siguiente es añadir un nuevo archivo de texto al directorio de trabajo, donde estará en estado untracked (sin seguimiento). Cuando ejecutamos el comando git status, observamos un mensaje que indica que hay untracked files, es decir, archivos sin seguimiento:

pi@erpi ~/test $ echo "Just some text" > newfile.txt

pi@erpi ~/test $ git status

On branch master

Your branch is up-to-date with 'origin/master'.

Untracked files:

(use "git add <file>..." to include in what will be committed)

newfile.txt

nothing to commit, untracked files present (use "git add" to track)

El paso siguiente consiste en añadir cualquier archivo sin seguimiento (untracked) al área de preparación (staging area). No obstante, si no desea añadir un conjunto de archivos, también puede crear uno llamado gitignore para obviarlos. Por ejemplo, esto resultaría útil si en un proyecto C/C++ decidimos que no queremos archivos objeto, .o, intermedios. He aquí un ejemplo de cómo crear un archivo .gitignore destinado a ignorar archivos objeto, .o, de C/C++:

pi@erpi ~/test $ echo "*.o" > .gitignore

pi@erpi ~/test $ more .gitignore

*.o

pi@erpi ~/test $ touch testobject.o

pi@erpi ~/test $ git status

On branch master

Your branch is up-to-date with 'origin/master'.

Untracked files:

(use "git add <file>..." to include in what will be committed)

.gitignore

newfile.txt

nothing to commit, untracked files present (use "git add" to track)

En este caso, hay dos archivos sin seguimiento, pero no existe mención al archivo testobject.o, lo que indica que se está ignorando tal como queríamos. Observe que el archivo .gitignore forma parte también del repositorio y que se conservará en cualquier clonación del mismo, junto con su histórico de cambios, etc.

Cómo añadir archivos al área de preparación (git add)

Los archivos del directorio de trabajo se pueden añadir ahora al área de preparación con el comando git add . (comando que incluye todos los archivos en el directorio de trabajo, con la excepción de los archivos ignorados). En este ejemplo, dos archivos se agregan desde el directorio de trabajo al área de preparación. Luego, podemos mostrar el estado del repositorio del siguiente modo:

pi@erpi ~/test $ git add .

pi@erpi ~/test $ git status

On branch master

Your branch is up-to-date with 'origin/master'.

Changes to be committed:

(use "git reset HEAD <file>..." to unstage)

new file: .gitignore

new file: newfile.txt

Para eliminar (remove) un archivo del área de preparación, usamos git rm somefile.ext.

Cómo hacer commit en el repositorio local (git commit)

Después de añadir archivos al área de preparación, podemos hacer commit y convertir en definitivos los cambios desde aquella en el repositorio Git. Primero, podríamos querer añadir nuestro nombre y dirección de correo electrónico para indicar quién realiza el commit con los cambios.

pi@erpi ~/test $ git config --global user.name "Derek Molloy"

pi@erpi ~/test $ git config --global user.email derek@my.email.com

Estos valores se configuran a partir de los de nuestra cuenta de usuario Linux, de manera que persisten en el siguiente inicio de sesión. Para verlos, podemos escribir more ~/.gitconfig.

El commit permanente de los cambios de los archivos en el repositorio Git local se hace con el comando git commit:

pi@erpi ~/test $ git commit -m "Testing the repository"

[master 3eea9a2] Testing the repository

2 files changed, 2 insertions(+)

create mode 100644 .gitignore

create mode 100644 newfile.txt

Los cambios se marcan con el nombre de usuario, pero también requieren la inclusión de un mensaje. Si queremos detallar el mensaje en la línea, usamos -m para establecerlo.

NOTA El atajo git commit -a realiza un commit de los archivos modificados directamente en el repositorio local, sin necesidad de invocar add. No añade archivos nuevos. Observe la figura 3-4 en este mismo capítulo.

Envío al repositorio remoto (git push)

Para realizar este paso, debemos poseer una cuenta propia en GitHub. El comando git push envía cualquier cambio en el código al repositorio remoto. Para que tales cambios se apliquen, debemos estar registrados como usuarios que pueden, en efecto, realizar modificaciones. En Git 2.0 se ha implementado un nuevo método llamado simple, más conservador, para enviar a repositorios remotos. Está seleccionado de forma predeterminada, pero puede suprimir algún mensaje de advertencia, y el envío se puede realizar del siguiente modo (sustituya los detalles de usuario y repositorio por los suyos propios):

pi@erpi ~/test $ git config --global push.default simple

pi@erpi ~/test $ git push

Username for 'https://github.com': derekmolloy

Password for 'https://derekmolloy@github.com': mySuperSecretPassword

Counting objects: 4, done.

Delta compression using up to 4 threads.

Compressing objects: 100% (2/2), done.

Writing objects: 100% (4/4), 350 bytes | 0 bytes/s, done.

Total 4 (delta 0), reused 0 (delta 0)

To https://github.com/derekmolloy/test.git

f5c45f4..3eea9a2 master -> master

Después de que el código haya sido enviado (push) al repositorio remoto, podemos traer (pull) los cambios al repositorio local de cualquier máquina gracias al comando git pull desde el interior del directorio del repositorio local:

pi@erpi ~/test $ git pull

Already up-to-date.

En este caso, todo está actualizado.

Ramas de desarrollo de Git

Git contempla el concepto de ramas de desarrollo (branching), lo que nos permite trabajar en múltiples versiones diferentes del conjunto de archivos de nuestro proyecto. Por ejemplo, para desarrollar una nueva característica en nuestro proyecto (versión 2) pero conservar el código de la versión actual (versión 1), crearíamos una nueva rama (versión 2). Ninguna de las nuevas características o cambios introducidos en la versión 2 afectará al código de la versión 1. Después podremos pasar de una rama a otra con facilidad.

Cómo crear una rama de desarrollo (git branch)

Suponga, por ejemplo, que desea crear una nueva rama llamada mybranch (acción denominada "ramificar"). Puede hacerlo con el comando git branch mybranch y, luego, pasar a trabajar con ella usando git checkout mybranch del siguiente modo:

pi@erpi ~/test $ git branch mybranch

pi@erpi ~/test $ git checkout mybranch

Switched to branch 'mybranch'

Ahora, para demostrar el funcionamiento de todo esto, suponga que un archivo temporal llamado testmybranch.txt se añade al repositorio. Este podría ser un nuevo archivo de código para nuestro proyecto. Puede observar que el estado de la rama de desarrollo deja claro que el directorio de trabajo contiene un archivo sin seguimiento:

pi@erpi ~/test $ touch testmybranch.txt

pi@erpi ~/test $ ls

newfile.txt README.md testmybranch.txt testobject.o

pi@erpi ~/test $ git status

On branch mybranch

Untracked files:

(use "git add <file>..." to include in what will be committed)

testmybranch.txt

nothing to commit, untracked files present (use "git add" to track)

Puede añadir entonces este nuevo archivo al área de preparación de la rama usando los mismos comandos:

pi@erpi ~/test $ git add .

pi@erpi ~/test $ git status

On branch mybranch

Changes to be committed:

(use "git reset HEAD <file>..." to unstage)

new file: testmybranch.txt

Podemos hacer commit de este cambio en la rama mybranch del repositorio local. Este cambio afectará a la rama mybranch, pero no tendrá efecto sobre la rama maestra:

pi@erpi ~/test $ git commit -m "Test commit to mybranch"

[mybranch d4cabf3] Test commit to mybranch

1 file changed, 0 insertions(+), 0 deletions(-)

create mode 100644 testmybranch.txt

pi@erpi ~/test $ git status

On branch mybranch

nothing to commit, working directory clean

pi@erpi ~/test $ ls

newfile.txt README.md testmybranch.txt testobject.o

De la salida anterior puede apreciar que el archivo testmybranch.txt se encuentra en el repositorio local y podemos verlo en el directorio.

Si ahora pasa de la rama mybranch a la rama maestra mediante git checkout master, observará algo interesante al solicitar un listado del directorio:

pi@erpi ~/test $ git checkout master

Switched to branch 'master'

Your branch is up-to-date with 'origin/master'.

pi@erpi ~/test $ ls

newfile.txt README.md testobject.o

Así es, el archivo testmybranch.txt ha desaparecido del directorio. Aún existe, obviamente, pero se encuentra en forma de objeto blob (de BLOB, Binary Large OBject, objeto binario grande), dentro del directorio git/objects. Si regresa a la rama y lista el directorio, verá esto:

pi@erpi ~/test $ git checkout mybranch

Switched to branch 'mybranch'

pi@erpi ~/test $ ls

newfile.txt README.md testmybranch.txt testobject.o

Es decir, el archivo vuelve a aparecer. Por lo tanto, puede observar lo bien integrado que está el sistema de ramas de desarrollo. En este punto puede regresar a la rama maestra e introducir cambios en el código original y ver que los cambios introducidos en la rama mybranch no afectan al código maestro. Aun si cambiamos el código en el mismo archivo, carecerá de efectos sobre el código original de la rama maestra.

Cómo fusionar ramas de desarrollo (git merge)

¿Qué ocurre si deseamos aplicar los cambios introducidos en la rama de desarrollo mybranch a la versión maestra del proyecto? Es decir, ¿cómo fusionamos las dos ramas? Pues utilizaremos el comando git merge.

pi@erpi ~/test $ git checkout master

Switched to branch 'master'

Your branch is up-to-date with 'origin/master'.

pi@erpi ~/test $ git merge mybranch

Updating 3eea9a2..d4cabf3

Fast-forward

testmybranch.txt | 0

1 file changed, 0 insertions(+), 0 deletions(-)

create mode 100644 testmybranch.txt

pi@erpi ~/test $ git status

On branch master

Your branch is ahead of 'origin/master' by 1 commit.

(use "git push" to publish your local commits)

nothing to commit, working directory clean

pi@erpi ~/test $ ls

newfile.txt README.md testmybranch.txt testobject.o

Ahora el archivo testmybranch.txt está en la rama maestra y también se han aplicado el resto de cambios introducidos en cualquier otro documento de la misma. El repositorio local va ahora un commit por delante del remoto, y podemos utilizar git push para actualizar este último.

Cómo borrar una rama de desarrollo (git branch -d)

Para borrar una rama de desarrollo, use el comando git branch -d mybranch:

pi@erpi ~/test $ git branch -d mybranch

Deleted branch mybranch (was d4cabf3).

pi@erpi ~/test $ ls

newfile.txt README.md testmybranch.txt testobject.o

En este caso, la rama testmybranch.txt sigue presente en el proyecto maestro, como por otro lado deber ser, puesto que se ha fusionado con él. Si la rama se hubiera borrado antes de realizar la fusión, se habría perdido el archivo.

Comandos habituales de Git

La table 3-8 ofrece un resumen de los principales comandos de Git. Llegados a este punto, ya hemos visto el uso básico de Git. Cuando se desarrolla código directamente en el RPi, Git puede resultar muy útil, puesto que nos permite subir fácilmente nuestros desarrollos a un repositorio remoto. Esta funcionalidad sirve muy bien para realizar copias de respaldo de nuestro código, así como para volver a desplegar el proyecto en múltiples RPi.

Table 3-8: Resumen de los principales comandos Git.


OperaciónDescripciónOperaciónDescripción
git cloneRealiza la clonación desde el repositorio remoto.git rmElimina un archivo o directorio del área de preparación.
git initCrea un repositorio completamente nuevo.git mvMueve o renombra un archivo o directorio en el área de preparación.
git pullFusiona cambios desde un repositorio maestro.git logMuestra un log (registro) con los commits. El histórico del proyecto.
git fetchEncuentra los cambios en el repositorio maestro sin realizar la fusión.git tagDa nombre a un commit (por ejemplo: versión 2).
git statusMuestra el estado del proyecto.git merge [name]Fusiona la rama.
git addAñade un nuevo archivo o edita un archivo existente.git showObtiene detalles sobre el commit actual o sobre cualquier otro.
git diff Muestra las diferencias que pasarán al repositorio cuando se haga el commit.git branch [name]Crea una nueva rama de desarrollo. (Use el parámetro -d para borrar (delete)).
git commitRealiza commit en el reposi-torio.git checkout [name]Cambia a otra rama de desarrollo.
git pushEnvía los cambios desde un repositorio local a uno remoto.

Cómo utilizar escritorios virtuales

El RPi es perfectamente capaz de actuar como plataforma de computación general, pero si planeamos compilar un núcleo de Linux o realizar desarrollo multiplataforma cruzado (véase el capítulo 7) lo más recomendable es utilizar un ordenador personal con Linux. Es posible utilizar un ordenador con un gestor de arranque que nos permita un sistema dual. Sin embargo, si mayoritariamente utilizamos un PC o un Mac, podríamos decantarnos por utilizar escritorios o máquinas virtuales.