miércoles, 7 de diciembre de 2022

2.- Django - Contenido dinámico e Introducción de Parámetros en URL.

 ¿Te pierdes entre tantos temas? 📚✨ Descubre todo lo que ofrece este blog en un solo vistazo [👉 Ver índice completo]

En la primera página que mostramos en el post anterior, correspondiente al "Hola Mundo", se mostraba un contenido estático. Aunque cargaras la página web varias veces siempre se mostraba lo mismo. 

Vamos a diseñar ahora una página que nos muestre la hora y fecha del servidor, con lo que cada vez que actualices la página se mostrará una información diferente - Dinámico -. Además, podemos pasar esta información formateada, usando como parámetro del método HttpResponse con código HTML, en vez de un string.

Y ¿Cómo hacemos esto?

Pues partimos del ejemplo del capitulo anterior. En el archivo views.py,  creamos una vista más de la siguiente forma:

views.py

from django.http import HttpResponse
import datetime

# Vistas
...
# Nueva vista que mostrará la hora actual.
def fecha_actual(request):

    date = datetime.datetime.now()

    # Estructura de un documento tipo html5
    documento = f"""
    <!DOCTYPE html>
    <html lang="es">
    <head>
        <meta charset="UTF-8">
        <meta http-equiv="X-UA-Compatible" content="IE=edge">
        <meta name="viewport" content="width=device-width, initial-scale=1.0">
        <title>Fecha Servidor</title>
    </head>
    <body>
        <h2>
            Fecha y hora Actuales: {date}
        </h2>    
    </body>
    </html>
    """
    return HttpResponse(documento)
Para empezar importamos la biblioteca datatime ya que es la que utilizaremos para mostrar la fecha y hora actuales. 

Creamos la variable date que almacenará esa fecha y hora.

Creamos la nueva vista. La Función de esta vista la he llamado "fecha_actual". Para darle formato a la salida utilizamos la variable documento que recoge la estructura básica de un documento html5. Al final no es más que un string con lo que podemos introducir información, como lo haríamos normalmente en Python - f"texto {variable}" -

El siguiente paso es registrar esa vista en el archivo que guarda las urls, urls.py.

urls.py

from django.contrib import admin
from django.urls import path
from Proyecto1.views import saludo, fecha_actual

urlpatterns = [
    path('admin/', admin.site.urls),
    path('saludo/', saludo),
    path("time_server/", fecha_actual),
]
Importamos la función fecha_actual al principio. Luego para acceder a la vista hay que usar el nombre "time_server" que hace referencia a la vista o función "fecha_Actual". Como comentamos en el post anterior el nombre para acceder a la vista "time_server" no tiene que ser necesariamente el nombre de la función "fecha_actual" aunque es lo más recomendable.

Vamos a ver si funciona. Ejecutamos el servidor de pruebas con:

$ python manage.py runserver

Salida:

muestra fecha servidor en pantalla


Puedes ver como va cambiando refrescando el navegador con F5.


Paso de Parámetros a través de la URL.


Para ver como se hace, vamos a ver un ejemplo, en el que pasando dos números a través de una vista nos muestre su suma.

Como en los casos anteriores lo primero es crear la función de la vista.

IMPORTANTE: Por defecto los parámetros que se pasan a través de una URL son de tipo string. Por eso si necesitamos, como en este caso, que sean numéricos hay que ponerlos con este formato:

/<int: parámetro>

Comentar que aparte de <int:loquesea> también se pueden utilizar los siguientes comandos para modificar el tipo de parámetros que introducimos en la Url:

  • string: Acepta cualquier texto sin barras (por defecto). Si no ponemos nada en el parámetro como ya dijimos lo considera como un string, una cadena de texto.
  • int: para convertirlo en enteros
  • float: para  valores reales, con decimales.
  • path: Acepta cadena de caracteres con barras


Otra opción es sabiendo que al pasárselos a la función, estos datos que son de tipo string, los convirtamos luego dentro de la función al tipo de datos que necesitemos usando Python. (por ejemplo int(parametro) )

Dicho lo cual la forma general de pasar los parámetros es:

def nombre_vista(request, parametro1, parametro2,...,parametro_n):
        -----
        -----
        -----
        return HttpResponse(documento)


Creamos la función de la nueva vista.

views.py

# Suma dos números pasados como parámetros en la Url
def suma_numeros(request, numero_1, numero_2):
    documento = documento = f"""
    <!DOCTYPE html>
    <html lang="es">
    <head>
        <meta charset="UTF-8">
        <meta http-equiv="X-UA-Compatible" content="IE=edge">
        <meta name="viewport" content="width=device-width, initial-scale=1.0">
        <title>Fecha Servidor</title>
    </head>
    <body>
        <h3>
            La suma de {numero_1} más {numero_2} = {numero_1 + numero_2}
            <hr/>
        </h3>    
    </body>
    </html>
    """
    return HttpResponse(documento)

Para registrar la URL la forma general es:

path("Nombre_Url/<parametro_1>/<parametro_2>/..../<parametro_n>/", nombre_vista)

en nuestro ejemplo, como necesitamos que los parámetros se pasen como enteros para sumarlos:

urls.py

from django.contrib import admin
from django.urls import path
from Proyecto1.views import saludo, fecha_actual, suma_numeros

urlpatterns = [
    path('admin/', admin.site.urls),
    path('saludo/', saludo),
    path("time_server/", fecha_actual),
    path("suma_numeros/<int:numero_1>/<int:numero_2>/", suma_numeros),
]

Como siempre, importamos la función y luego registramos la URL.

Salida:

paso de parametros a través de url
Plantillas - Son cadenas de texto que pueden tener código Html o ser texto plano simplemente. Sirven para separar la parte lógica de la parte visual del proyecto. Aunque hay muchas formas de utilizar las plantillas la más habitual es guardar todo el código HTML en un documento aparte y en otra carpeta distinta y luego la cargarla en nuestra vista.

Para crear una plantilla, básicamente seguimos tres pasos:

1.) Creación de un objeto tipo Template.
2.) Creación de un contexto (Contenido dinámico, variables, funciones etc)
3.) Renderizado del template.

Vamos a pasar todo esto a código con el proyecto que estamos usando desde el post inicial. En el proyecto que estamos usando ya teníamos una función en views.py llamada "saludo" que nos devolvía un texto plano. Vamos a hacer que nos devuelva el mismo texto pero usando una plantilla para que nos sirva de ejemplo.

Vamos a crear un nuevo archivo que será la plantilla que vamos a crear y la guardaremos también en una carpeta nueva, separada que por ejemplo podemos llamar "plantillas", aunque normalmente se suele llamar "templates".

directorio para plantillas


plantilla.html (guardada en directorio "plantillas")

<!DOCTYPE html>
<html lang="es">
<head>
     <meta charset="UTF-8">
     <meta http-equiv="X-UA-Compatible" content="IE=edge">
     <meta name="viewport" content="width=device-width, initial-scale=1.0">
     <title>Fecha Servidor</title>
</head>
<body>
      <h3>
         ¡Hola Mundo! He sido cargada desde una plantilla.
      </h3>    
</body>
</html>

Ahora volvemos a el archivo views.py y modificamos la función saludo para que cargue la plantilla. Aunque posteriormente lo haremos con cargadores vamos a empezar poco a poco y en este ejemplo lo haremos manualmente.

Lo primero que haremos es importar al comienzo del programa la clase Template y Context

views.py

from django.http import HttpResponse
import datetime
from django.template import Template, Context

# Vistas
def saludo(request):
    doc_externo = open("/home/chema/Cursos/DJANGO/Proyecto1/plantillas/plantilla.html")
    plantilla = Template(doc_externo.read())
    doc_externo.close()
    # Aunque no hay contenido dinámico, hay que crear el contexto.
    contexto = Context()
    # Renderizamos el contenido
    documento = plantilla.render(contexto)
    return HttpResponse(documento)

...
Si vamos al archivo de vistas, views.py, en vez de trabajar con texto incrustado lo vamos a hacer con una plantilla ya creada, para cargarla y renderizarla. 

Empezamos creando una variable, doc_externo, que utiliza el método open para cargar la plantilla. Tenemos que especificar la ruta donde encontrar el documento. (Ojo que para especificar la ruta hay que usar esta barra "/" sobretodo si estás en windows)

Una vez hecho esto creamos el objeto de tipo Template que asignare a una variable que puedes llamar como prefieras, plantilla en mi caso. Utilizamos .read() para leerla. Ya tenemos cargado el documento.

Y como lo tenemos cargado voy a cerrar el fichero para que no ocupe memoria con doc_externo.close().

Como el ejemplo es muy sencillo y no lleva contenido dinámico, ni información adicional la variable contexto es igual a la clase Context pero sin contenido. 

Para finalizar renderizamos el contenido.

Si ejecutamos el servidor y lo probamos con localhost/saludo/ nos debería funcionar.

Todo lo anterior es para tener la idea global de como funciona la carga de plantillas, ya que como veremos luego existen métodos más eficientes y sencillos de hacerlo, como veremos en el próximo post.

Próximo. Post 3.- Plantillas, variables y propiedades en la plantilla.

sábado, 19 de noviembre de 2022

1.- Django - Instalación y Primera Página.


 ¿Te pierdes entre tantos temas? 📚✨ Descubre todo lo que ofrece este blog en un solo vistazo [👉 Ver índice completo]

¿Que es Django?

De forma muy resumida podemos decir que es un "framework" de Python para crear entornos web. 


1) Instalación.

Se puede instalar en local o también, que suele ser lo normal, en un entorno virtual. Todos los ejemplos que siguen están realizados en un entorno virtual.

Para instalarlo vamos a su página y buscamos la sección de descargas. Ni que decir tiene que tienes que tener Python instalado en tu ordenador para poder ejecutar Django. Personalmente como estoy en Linux, lo voy a instalar con: 

$ sudo pip3 install Django

o también,  a fecha en la que he escrito esta entrada, la última versión con:

pip install Django==4.1.3

Para ver si esta correctamente instalado, entramos en la consola de Python y tecleamos:

(miEntorno) chema@lenovo:~/Cursos/DJANGO$ python
Python 3.10.6 (main, Nov  2 2022, 18:53:38) [GCC 11.3.0] on linux
Type "help", "copyright", "credits" or "license" for more information.
>>> import django
>>> django.VERSION
(4, 1, 3, 'final', 0)


2) Creación de un proyecto.

Un Proyecto se organiza como un grupo de aplicaciones individuales que trabajan juntas para que el proyecto funcione como un todo.

Empezaremos creando una carpeta donde guardar el proyecto (DJANGO en mi caso). Entramos en ella y desde el terminal, podemos hacerlo de dos formas:

a) $ django-admin startproject Nombre_Proyecto

(como nombre de proyecto escogí Proyecto1)

Se creará una carpeta con el nombre que le hayamos puesto al proyecto y si entramos en ella veremos el siguiente esquema de directorio:

Proyecto1



o

b) $ django-admin startproject Nombre_Proyecto .

Importante el punto final. La diferencia está en que de esta forma se nos crea el proyecto con forma de directorio para que sea más fácil desplegarlo. Quedaría así:

Proyecto1


Cuestión de gustos o funcionalidad el elegir una y otra. (el directorio miEntorno es el entorno virtual que he creado, no se instala con Django).

El archivo manage.py es muy importante porque nos permite interactuar con los proyectos Django de varias formas. Si vamos a la consulta y ejecutamos:

$ ./manage.py help o bien python manage.py help

Nos ofrece una salida con todas las instrucciones y comandos que puede ejecutar. (entre ellos el parámetro startproject ya visto)

(miEntorno) chema@lenovo:~/Cursos/DJANGO$ ./manage.py help

Type 'manage.py help <subcommand>' for help on a specific subcommand.

Available subcommands:

[auth]
    changepassword
    createsuperuser

[contenttypes]
    remove_stale_contenttypes

[django]
    check
    compilemessages
    createcachetable
    dbshell
    diffsettings
    dumpdata
    flush
    inspectdb
    loaddata
    makemessages
    makemigrations
    migrate
    optimizemigration
    sendtestemail
    shell
    showmigrations
    sqlflush
    sqlmigrate
    sqlsequencereset
    squashmigrations
    startapp
    startproject
    test
    testserver

[sessions]
    clearsessions

[staticfiles]
    collectstatic
    findstatic
    runserver


Dentro de la carpeta del proyecto creada tenemos otros archivos que son:

__init__.py 

Es un archivo necesario para que Python trate el directorio del proyecto - Proyecto1 en el ejemplo - como un paquete.

settings.py 

Contiene, como te puedes imaginar por el nombre, todas las configuraciones de nuestro proyecto de Django.

urls.py

Es donde se almacenan las urls o direcciones de nuestro proyecto.

wsgi.py

Es el servidor web que vamos a utilizat en el proyecto de Django.


3) Creación de la Base de Datos del Proyecto.


Para que el proyecto se ponga en funcionamiento tenemos que crear una base de datos. Por defecto Django utiliza Sqlite3, aunque como veremos más tarde también soporta oficialmente PostgreSql, MySql o Oracle. Con desarrollos de terceros también es posible utilizar Sql server, Sap Sql, db2, Firebird etc.

Para empezar vamos a crear la que se utiliza por defecto Sqlite3, con el siguiente comando:

$ python manage.py migrate

>>> (miEntorno) chema@lenovo:~/Cursos/DJANGO$ python manage.py migrate
Operations to perform:
  Apply all migrations: admin, auth, contenttypes, sessions
Running migrations:
  Applying contenttypes.0001_initial... OK
  Applying auth.0001_initial... OK
  Applying admin.0001_initial... OK
  Applying admin.0002_logentry_remove_auto_add... OK
  Applying admin.0003_logentry_add_action_flag_choices... OK
  Applying contenttypes.0002_remove_content_type_name... OK
  Applying auth.0002_alter_permission_name_max_length... OK
  Applying auth.0003_alter_user_email_max_length... OK
  Applying auth.0004_alter_user_username_opts... OK
  Applying auth.0005_alter_user_last_login_null... OK
  Applying auth.0006_require_contenttypes_0002... OK
  Applying auth.0007_alter_validators_add_error_messages... OK
  Applying auth.0008_alter_user_username_max_length... OK
  Applying auth.0009_alter_user_last_name_max_length... OK
  Applying auth.0010_alter_group_name_max_length... OK
  Applying auth.0011_update_proxy_permissions... OK
  Applying auth.0012_alter_user_first_name_max_length... OK
  Applying sessions.0001_initial... OK


Dentro de la carpeta Principal se habrá generado un archivo db.sqlite3.

base de datos sqlite3


El proyecto ya está listo para funcionar. Para ver que todo va bien tenemos que ejecutar un servidor web y usar el navegador para ver la página de bienvenida de Django. El servidor web que viene con Django es útil para probar nuestro proyecto pero NO para ponerlo en producción, sirve para ver si nuestros proyectos funcionan y se ven.


$ python manage.py runserver


>>> (miEntorno) chema@lenovo:~/Cursos/DJANGO$ python manage.py runserver
Watching for file changes with StatReloader
Performing system checks...

System check identified no issues (0 silenced).
November 09, 2022 - 17:13:08
Django version 4.1.3, using settings 'proyecto1.settings'
Starting development server at http://127.0.0.1:8000/
Quit the server with CONTROL-C.

Ahora si abres el navegador web que utilices y vas a la dirección:


http://127.0.0.1:8000/

o

http://localhost:8000/

podrás ver, si esta todo instalado correctamente la página de bienvenida de Django:

Pagina de instalación correcta de Django

Vamos a personalizar algunos elementos de Django como son la hora local y el idioma. Por defecto la aplicación utiliza por defecto el idioma ingles y como hora local UTC (Coordinated Universal Time) que en verano es dos horas menos que la nuestra. (si estás en España)

Para cambiarlo busca el archivo settings.py y busca los siguientes valores:

...
# Internationalization
# https://docs.djangoproject.com/en/4.2/topics/i18n/

LANGUAGE_CODE = 'en-us'

TIME_ZONE = 'UTC'

USE_I18N = True

USE_TZ = True
...

Puedes usar el idioma y tu hora local, pero si quieres usar el Castellano y poner la hora de España cambia los siguientes valores:

LANGUAGE_CODE = 'es-es'

TIME_ZONE = 'Europe/Madrid'

4) Creación de una página web sencilla "Hola Mundo".

Lo primero que tenemos que hacer es crear un archivo nuevo que va a almacenar las diferentes vistas que vayamos almacenando. Este archivo, por convención, se suele llamar views.py. Estará dentro de la carpeta que contiene los demás, donde está el __init__.py.

Lo primero que tenemos que hacer es importar:

views.py

# Importar el módulo
from django.http import HttpResponse

# El nombre de la primera vista será Saludo
def saludo(request):
    return HttpResponse("Hola Mundo")

A cada función que creemos dentro de views.py se le denomina vista.

Ahora debemos decirle a Python cual es la Url que debemos introducir en el navegador para que nos de esta vista.

Esto se lo decimos en el archivo urls.py. En el mismo, al abrirlo, ya vienen las instrucciones de como construirla. Tiene que tener la siguiente estructura:

path("nombreurl/", nombre_de_la_vista)

nombreurl/ -> podemos poner el que nosotros queramos, pero por coherencia debería coincidir con el nombre de la función. (Hay que poner la barra al final).

nombre de la vista -> el mismo que pusimos en el archivo views.py

y como la función está en un archivo diferente al que nos encontramos hay que importarla:

from nombre_proyecto.views import nombre_de_la_vista

nombre_proyecto será el nombre de la carpeta que lo contiene:

En mi ejemplo: (en negrita está lo que se ha añadido de nuevo al archivo)

from django.contrib import admin
from django.urls import path
from Proyecto1.views import saludo

urlpatterns = [
    path('admin/', admin.site.urls),
    path('saludo/', saludo),
]

Si ejecutamos de nuevo el servidor de Django:

$ python manage.py runserver

y vamos a la siguiente Url: localhost:8000/saludo/

debemos ver lo siguiente:

hola mundo en Django

Próximo Post. 2.- Contenido dinámico e introducción de parámetros en url.

lunes, 7 de noviembre de 2022

Creación de Ejecutables de una aplicación en Python.

El ejecutable tomará la forma del sistema operativo con el que estemos trabajando. Si lo estas haciendo en Windows será un archivo con terminación .exe, si estas en Linux un archivo ejecutable sin terminación o con terminación .tar.gz y .dmg si estás en Mac.

Para crear el ejecutable voy a utilizar el siguiente código:

https://github.com/chema-hg/SISTEMA_SOLAR

Es una simulación del sistema solar que utiliza la biblioteca Pygame para funcionar, con lo que si no la tienes instalada deberías instalarla previamente. Yo creare un directorio, crearé en el un entorno virtual. Después copiaré aquí el programa, activaré el entorno virtual e instalaré en el la librería Pygame.

Vamos a utilizar para crear el ejecutable la biblioteca Pyinstaller.  Por tanto hay que instalarlo. Existen otros programas similares como, Py2exe, cx_Freeze. Para Mac también está py2app.

Lo primero comentar que si quieres crear un ejecutable para Windows tienes que instalarlo y usarlo en Windows y lo mismo para Linux o Mac, ya que este programa en concreto no compila la versión para otra plataforma. Yo estoy trabajando en Linux así que crearé un ejecutable para Linux.


>>> mkdir Ejecutable
>>> cd Ejecutable/ # Aquí, copia dentro de este directorio la aplicación.
>>> python3 -m venv Mientorno
>>> source ./Mientorno/bin/activate
(Mientorno) >>> pip install pygame
Collecting pygame
  Using cached pygame-2.1.2-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl (21.9 MB)
Installing collected packages: pygame
Successfully installed pygame-2.1.2

(Mientorno) >>> pip install pyinstaller
Collecting pyinstaller
  Downloading pyinstaller-5.6.2-py3-none-manylinux2014_x86_64.whl (594 kB)
     ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ 594.9/594.9 KB 3.5 MB/s eta 0:00:00
Collecting pyinstaller-hooks-contrib>=2021.4
  Downloading pyinstaller_hooks_contrib-2022.12-py2.py3-none-any.whl (250 kB)
     ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ 250.0/250.0 KB 25.5 MB/s eta 0:00:00
Collecting altgraph
  Downloading altgraph-0.17.3-py2.py3-none-any.whl (21 kB)
Requirement already satisfied: setuptools in ./Mientorno/lib/python3.10/site-packages (from pyinstaller) (59.6.0)
Installing collected packages: altgraph, pyinstaller-hooks-contrib, pyinstaller
Successfully installed altgraph-0.17.3 pyinstaller-5.6.2 pyinstaller-hooks-contrib-2022.12

Una vez instalado lo primero que tenemos que hacer es ir al directorio donde tenemos la aplicación, que en este caso es el mismo, puesto que hemos copiado la aplicación app.py aquí.


 pyinstaller aplicación.py --onefile --windowed --icon=./logo.ico



La estructura del comando es la anterior, pero en este ejemplo no voy a usar icono.

(Mientorno) >>> pyinstaller app.py --onefile --windowed

app.py es el nombre del archivo que quieres convertir en un ejecutable.


Opciones:

--windowed es para que no aparezca la consola al ejecutar el programa. En mi caso no aparecerá la ventana de la consola (si el programa no tiene salida por terminal) y solamente el gui gráfico.

--onefile Para que se cree un solo archivo compilado con todo lo que la aplicación necesita. Se podrá ejecutar incluso en un ordenador que no tenga Python instalado. Si no lo incluyes te aparecerá un montón de archivos con todo lo necesario para que la aplicación funcione. Si lo haces solo aparecerá un archivo.

--icon. Más que nada en windows para que el ejecutable aparezca con el icono que le pongas. Eso si, tiene que ser un archivo ico.

Después de unas cuantas operaciones, al final el programa te dirá si se ha podido crear el ejecutable con éxito. El archivo o archivos del ejecutable ya compilado lo puedes encontrar en la carpeta "dist" que habrá creado el programa. Y solo queda ejecutarlo para ver que funcione.




miércoles, 19 de octubre de 2022

GIT - 6 - Cosas Varias.

Mejores prácticas para el trabajo en equipo.

  1. Sincronizar las ramas siempre antes de comenzar a trabajar (git pull)
  2. Evitar tener cambios muy grandes que modifiquen muchas cosas diferentes.
  3. Cuando trabajamos en un gran cambio tiene sentido tener una rama con esas características separadas.
  4. Para facilitar la fusión final del proyecto, combina regularmente los cambios realizados en la rama principal.
  5. Es recomendable tener la última versión del proyecto en la rama main y la versión estable en otra rama separada.
  6. No debes usar rebase para los cambios que se han enviado a repositorios remotos.
  7. Poner buenos mensajes en las confirmaciones. 

Bajar solamente un subdirectorio de un proyecto de Github.


En Github hay veces en que no nos interesa clonar todo el repositorio, si no solamente una carpeta del mismo que es donde está el código que queremos. Los métodos que hemos visto hasta ahora nos descargarían todo el contenido, pero no un subdirectorio en concreto.

Considera por ejemeplo este repositorio:  https://github.com/chema-hg/CURSO-DE-FLASK

Verás que está dividido en carpetas, las cuales corresponden cada una a una lección.
Si quisiéramos clonar solamente una de ellas, la subcarpeta 10, por decir algo, haríamos los siguiente:

1.- Creamos una carpeta en nuestro ordenador donde guardar el contenido, entramos en ella e iniciamos el proyecto.

$ mkdir proyecto
$ cd proyecto/
$ git init
Initialized empty Git repository in /home/chema/Desktop/proyecto/.git/
2.- Indicamos a git donde está el repositorio remoto del proyecto.

$ git remote add origin https://github.com/chema-hg/CURSO-DE-FLASK

3.-  Para cambiar el directorio desde donde clonar la subcapeta que nos interesa:

$ git config core.sparsecheckout true


4.- Le indicamos a git cual es la subcarpeta a clonar. Hay que escribir tal cual el nombre de la subcarpeta. Como yo quiero clonar la número 10: 

$ echo '/POST 10/'>>.git/info/sparse-checkout

5.- Clonamos la subcarpeta. (se utiliza master o main dependiendo de como este llamada remotamente la rama pricipal.)

$ git pull --depth=1 origin master

SALIDA.

remote: Enumerating objects: 196, done.
remote: Counting objects: 100% (196/196), done.
remote: Compressing objects: 100% (143/143), done.
remote: Total 196 (delta 39), reused 136 (delta 24), pack-reused 0
Receiving objects: 100% (196/196), 106.76 KiB | 2.27 MiB/s, done.
Resolving deltas: 100% (39/39), done.
From https://github.com/chema-hg/CURSO-DE-FLASK
 * branch            master     -> FETCH_HEAD
 * [new branch]      master     -> origin/master
chema@lenovo:~/Desktop/proyecto$ ls
'POST 10'
chema@lenovo:~/Desktop/proyecto$ cd POST\ 10/
chema@lenovo:~/Desktop/proyecto/POST 10$ ls
inicio.py  static  templates

Y ya tenemos clonada solamente esa carpeta.


¿Que son las PULL REQUEST de Github?


pull request

Normalmente tu puedes clonar los proyectos pero no puedes modificarlos. Pero lo que si puedes hacer es ayudar al desarrollador realizando mejoras en el programa y enviándoselas al propietario para que las revise y si lo considera oportuno las incorpore. Esto se hace a través de esta opción de github "PULL REQUEST". Solo hay que seguir las instrucciones.


¿Qué es botón fork de Github?


opcion fork


Un fork es una copia del repositorio que se guarda en tu cuenta personal de Github. Te permite libremente experimentar con el proyecto, realizando cambios pero sin afectar al proyecto original. 


lunes, 17 de octubre de 2022

GIT - 5 - Conflictos entre archivos. Git merge Vs Git rebase

Normalmente los conflictos de fusión se producirán cuando dos personas han cambiado las mismas líneas en un archivo o si una de ellas ha borrado un archivo que otra está desarrollando. En estos casos Git no sabe como solventar la situación y generará un conflicto que tendremos que resolver.

Tipos de conflictos de fusión.

- Git no inicia la fusión.

Una fusión no se iniciará si Git detecta que hay cambios en el directorio de trabajo actual, no confirmados que puedan ser sobrescritos en la fusión. Vamos a crear un ejemplo de fusión que cree un error de este tipo:

chema@mcbook:~/Prueba$ git init
Initialized empty Git repository in /home/chema/Prueba/.git/
chema@mcbook:~/Prueba$ > main.py
chema@mcbook:~/Prueba$ git add .
chema@mcbook:~/Prueba$ git commit -m "Primer commit en rama main."
[main (root-commit) b19e412] Primer commit en rama main.
 1 file changed, 0 insertions(+), 0 deletions(-)
 create mode 100644 main.py
 
chema@mcbook:~/Prueba$ git branch auxiliar
chema@mcbook:~/Prueba$ git switch auxiliar 
Switched to branch 'auxiliar'
chema@mcbook:~/Prueba$ echo "# Un comentario." > main.py
chema@mcbook:~/Prueba$ git add .
chema@mcbook:~/Prueba$ git commit -m "Añadida linea en archivo. Rama 
auxiliar."
[auxiliar e195481] Añadida linea en archivo. Rama auxiliar.
 1 file changed, 1 insertion(+)
 
chema@mcbook:~/Prueba$ git switch main 
Switched to branch 'main'
chema@mcbook:~/Prueba$ echo "segunda linea" > main.py
chema@mcbook:~/Prueba$ git merge auxiliar
Updating b19e412..e195481
error: Your local changes to the following files would be overwritten
     by merge:
	main.py
Please commit your changes or stash them before you merge.
Aborting


- Git falla durante la fusión.

Un fallo durante la fusión indica un conflicto entre la rama local actual y la rama que se está fusionando. Git hará lo posible para fusionar los archivos, pero te dejará cosas a solventar en los archivos con conflictos. 

Vamos a verlo con un ejemplo.

chema@mcbook:~/Prueba$ git init
Initialized empty Git repository in /home/chema/Prueba/.git/
chema@mcbook:~/Prueba$ echo "Esto es el texto inicial." > merge.txt
chema@mcbook:~/Prueba$ git add .
chema@mcbook:~/Prueba$ git commit -m "Confirmamos el contenido inicial."
[main (root-commit) e951c03] Confirmamos el contenido inicial.
 1 file changed, 1 insertion(+)
 create mode 100644 merge.txt

Ahora tenemos un repositorio con una única rama main y un poco de texto en el archivo merge.txt. A continuación creamos una nueva rama y la utilizaremos para crear una fusión conflictiva.

chema@macbook:~/Prueba$ git checkout -b nueva_rama_para_mezclar_luego
Switched to a new branch 'nueva_rama_para_mezclar_luego'
chema@macbook:~/Prueba$ echo "Contenido diferente para mezclar luego." > merge.txt
chema@macbook:~/Prueba$ git add .
chema@macbook:~/Prueba$ git commit -m "Editado el contenido del archivo merge.txt para crear un conflicto."
[nueva_rama_para_mezclar_luego 9a77225] Editado el contenido del archivo merge.txt para crear un conflicto.
 1 file changed, 1 insertion(+), 1 deletion(-)

Con esta nueva rama, hemos creado una confirmación que sobrescribe el contenido de merge.txt

chema@mcbook:~/Prueba$ git switch main
Switched to branch 'main'
chema@mcbook:~/Prueba$ echo "Contenido para añadir." >> merge.txt
chema@mcbook:~/Prueba$ git add .
chema@mcbook:~/Prueba$ git commit -m "añadido contenido a merge.txt"
[main 4f820aa] añadido contenido a merge.txt
 1 file changed, 1 insertion(+)

Esto ahora pone nuestro repositorio de ejemplo en un estado en el que tenemos dos nuevas confirmaciones. Una está en la rama main y la otra en la rama 'nueva_rama_para_mezclar_luego'. En este momento vamos a fusionarlas a ver que pasa.

chema@mcbook:~/Prueba$ git branch
* main
  nueva_rama_para_mezclar_luego
chema@mcbook:~/Prueba$ git merge nueva_rama_para_mezclar_luego 
Auto-merging merge.txt
CONFLICT (content): Merge conflict in merge.txt
Automatic merge failed; fix conflicts and then commit the result.

Como no podía ser de otra forma Git nos indica que existe un conflicto puesto que las dos ramas intentan escribir en la misma línea del archivo merge.txt.


Como identificar conflictos de fusión.


Tal como hemos visto anteriormente Git al intentar la fusión nos avisa de que existe un conflicto. 
Podemos ver más detalles usando el siguiente comando:

chema@macbook:~/Prueba$ git status
On branch main
You have unmerged paths.
  (fix conflicts and run "git commit")
  (use "git merge --abort" to abort the merge)

Unmerged paths:
  (use "git add <file>..." to mark resolution)
	both modified:   merge.txt

no changes added to commit (use "git add" and/or "git commit -a")

El resultado de "git status" nos indica que existen ramas a fusionar a causa de un conflicto. El archivo merge.txt aparece ahora como modificado. Vamos a ver el archivo para ver que es lo que se ha modificado. 

chema@macbook:~/Prueba$ cat merge.txt
<<<<<<< HEAD
Esto es el texto inicial.
Contenido para añadir.
=======
Contenido diferente para mezclar luego.
>>>>>>> nueva_rama_para_mezclar_luego

Se nos muestra lo que aporta cada rama  <<<<<<< HEAD y >>>>>> nueva_rama_para_mezclar_luegoseparado por los signos ==========. 


Como resolver conflictos de fusión mediante la línea de comandos.


La forma de resolver en nuestro caso el archivo es editar el archivo merge.txt. Como las líneas que intentamos fusionar no son excluyentes, quitamos los signos añadidos por Git y lo dejamos como está.
El contenido del archivo merge.txt tendría el siguiente aspecto:

Esto es el texto inicial.
Contenido para añadir.
Contenido diferente para mezclar luego.

Cuando hayas editado el archivo, utiliza git add merge.txt para prepararlo para la fusión. Finalmente terminamos la fusión con una nueva confirmación:

chema@macbook:~/Prueba$ git add merge.txt
chema@macbook:~/Prueba$ git commit -m "fusionados y resueltos los conflictos de merge.txt"
[main d1d0197] fusionados y resueltos los conflictos de merge.txt

Git merge Vs Git rebase.

Lo primero que hay que comentar sobre estos dos comandos es que ambos están diseñados para la misma función. Integrar las modificaciones o cambios que se hayan hecho en una rama con los de otra. En lo que varían es que lo hacen de forma diferente.

Imaginemos que tenemos un repositorio con dos ramas. Una llamada "main" y otra llamada "nuevas_caracteristicas". En la rama main un miembro del equipo ha hecho modificaciones y ha agregado varios commits. Por nuestra parte en la rama "nuevas_caracteristicas" nosotros hemos hecho algunas aportaciones con sus correspondientes confirmaciones. Este escenario da lugar a un historial bifurcado típico de git, tal como este:


escenario log gits
Digamos que ahora las nuevas confirmaciones en la rama main son relevantes para nuestro rama y queremos utilizarlas. Tenemos para ello dos opciones:


1) GIT MERGE

$ git switch nuevas_caracteristicas
o
$ git checkout nuevas_caracteristicas
(Para cambiar de rama.)

$ git merge main

Esta instrucción crea una nueva confirmación de mezcla en la rama nuevas_caracteristicas que une o fusiona las historias de ambas ramas, lo que hace que quede una estructura como esta:


git merge


Usar "git merge" hace que no cambien las ramas de ninguna forma y evita los problemas que puede causar la otra opción como veremos luego.

Por otro lado esto también significa, que la rama "nuevas_características" tendrá una confirmación de commits extraña cada vez que se necesiten incorporar cambios ascendentes. Si la rama main es muy activa esto puede contaminar bastante el historial de la rama "nueva_caracteristicas" al extremo de dificultar la compresión del proyecto.

2) GIT REBASE

Como alternativa a la fusión, podemos rebasar la rama "nuevas_caracteristicas" en la rama "main" usando el siguiente comando:

$ git checkout nuevas_caracteristicas
o
$ git switch nuevas_caracteristicas
(Para cambiar de rama.)

$ git rebase main

Esto mueve toda la rama nuevas_caracteristicas para que comience en la punta de la rama main, incorporando efectivamente todas las nuevas confirmaciones de main. Pero en lugar de utilizar una confirmación de fusión, la reorganización vuelve a escribir el historial del proyecto mediante la creación de nuevas confirmaciones para cada confirmación de la rama main.


git rebase

El mayor beneficio es que se obtiene un historial del proyecto mucho más limpio. Primero, se eliminan todas las confirmaciones de combinación innecesarias requeridas por "git merge". En segundo lugar, como se puede ver en el diagrama anterior, da como resultado un historial del proyecto perfectamente lineal. Puedes seguir el proyecto desde la punta hasta el inicio sin ninguna bifurcación. Esto facilita la navegación por el proyecto.

Pero también hay dos desventajas. La primera es que volver a escribir el historial del proyecto puede ser catastrófico para el flujo de trabajo cuando se esta trabajando en equipo, ya que se unifican las ramas perdiendo el historial de los commits. Además monta los commits de una rama en otra sin importar la cronología. Y aunque menos importante, la reorganización pierde el contexto proporcionado por una confirmación de combinación: no se puede ver cuando se incorporaron los cambios anteriores a la función.


Debido a esto es SUPERIMPORTANTE:

Nunca usar si este comando si se esta trabajando en un repositorio público en el que se colabora con más personas y donde las confirmaciones y su historial son muy importantes.


lunes, 10 de octubre de 2022

GIT - 4 - Trabajando con repositorios remotos.

Lo normal es que cuando tenemos un repositorio remoto, bien sea en GitHub o en otro servidor distinto, trabajaremos con el varias personas por lo que es normal que se introduzcan cambios. Vamos una serie de comandos que nos facilitarán la tarea.

$ git remote -v 

Nos muestra las URLS asociadas con el control remoto-origen del repositorio. Normalmente suelen apuntar a la misma dirección pero no tiene porque ser así.

txema@macbook:~/Prueba$ git remote -v
origin	git@github.com:usuario/Prueba.git (fetch)
origin	git@github.com:usuario/Prueba.git (push)

$ git remote show origin

Nos muestra aun más información que el comando anterior. 

txema@macbook:~/Prueba$ git remote show origin
* remote origin
  Fetch URL: git@github.com:usuario/Prueba.git
  Push  URL: git@github.com:usuario/Prueba.git
  HEAD branch: main
  Remote branch:
    main tracked
  Local branch configured for 'git pull':
    main merges with remote main
  Local ref configured for 'git push':
    main pushes to main (up to date)

Ahora, imagina que un compañero ha realizado y subido cambios al servidor, si volvemos a ejecutar el comando.

txema@macbook:~/Prueba$ git remote show origin
* remote origin
  Fetch URL: git@github.com:usuario/Prueba.git
  Push  URL: git@github.com:usuario/Prueba.git
  HEAD branch: main
  Remote branch:
    main tracked
  Local branch configured for 'git pull':
    main merges with remote main
  Local ref configured for 'git push':
    main pushes to main (local out of date)

Puedes ver como el comando, en la última línea nos dice "local out of date" o "desactualizado local". Esto es que ha habido cambios desde la última vez que actualizamos nuestro repositorio con los datos del servidor.


$ git branch -r

Muestra las ramas remotas del repositorio.


$ git fetch 

Si este comando muestra alguna salida es porque le está diciendo al repositorio local que ha habido cambios en el repositorio remoto pero sin traer esos cambios al repositorio local. En otras palabras si lo ejecutas y te sale una respuesta es porque algo se ha modificado en el repositorio remoto pero no te modifica el repositorio local con el que estas trabajando.

Sin cambios en el repositorio remoto. (El comando no muestra ninguna salida)

txema@macbook:~/Prueba$ git fetch

Ahora modificaré el archivo readme.md del repositorio remoto y esto es lo que ocurre:

txema@macbook:~/Prueba$ git fetch
remote: Enumerating objects: 5, done.
remote: Counting objects: 100% (5/5), done.
remote: Compressing objects: 100% (3/3), done.
Unpacking objects: 100% (3/3), 708 bytes | 708.00 KiB/s, done.
remote: Total 3 (delta 0), reused 0 (delta 0), pack-reused 0
From github.com:usuario/Prueba
   f2612e6..7eb5580  main       -> origin/main

En cambio:

$ git pull

Trae los cambios de ese repositorio remoto al local, pero solo de la rama en la que estamos.

txema@macbook:~/Prueba$ git pull
Updating f2612e6..7eb5580
Fast-forward
 README.md | 1 +
 1 file changed, 1 insertion(+)

Lo mismo que con el comando "git push" podemos lograr haciendo:

1) git fetch  
2) git merge origin/main

txema@macbook:~/Prueba$ git fetch
remote: Enumerating objects: 5, done.
remote: Counting objects: 100% (5/5), done.
remote: Compressing objects: 100% (3/3), done.
Unpacking objects: 100% (3/3), 750 bytes | 750.00 KiB/s, done.
remote: Total 3 (delta 0), reused 0 (delta 0), pack-reused 0
From github.com:usuario/Prueba
   7eb5580..d660c34  main       -> origin/main

txema@macbook:~/Prueba$ git merge origin/main
Updating 7eb5580..d660c34
Fast-forward
 README.md | 1 +
 1 file changed, 1 insertion(+)


Podemos ver los cambios que ha habido usando:


$ git log -p -1

txema@macbook:~/Prueba$ git log -p -1
commit d660c34793c59a229a6ba3f2492ed97d3522eeda (HEAD -> main, origin/main, origin/HEAD)
Author: usuario <usuario@users.noreply.github.com>
Date:   Mon Oct 10 11:10:55 2022 +0200

    Update README.md

diff --git a/README.md b/README.md
index 6c611a5..3ad79b4 100644
--- a/README.md
+++ b/README.md
@@ -1,2 +1,3 @@
 # Aquí Irán las instrucciones.
 Añadida una nueva rama
+ahora probare git fetch y git merge origin/main


Nueva Rama en Repositorio Remoto.

Vamos a suponer que un compañero ha creado en el repositorio remoto una rama llamada "auxiliar" para realizar pruebas del programa. Ahora mismo en nuestro repositorio local solamente tenemos la rama main. Si quisiéramos traerla al local lo haríamos con:

$ git checkout <nueva_rama_remota>

en nuestro caso

txema@macbook:~/Prueba$ git checkout auxiliar
Branch 'auxiliar' set up to track remote branch 'auxiliar' from 'origin'.
Switched to a new branch 'auxiliar'

y luego haríamos un "git pull" para actualizarla.

txema@macbook:~/Prueba$ git pull
remote: Enumerating objects: 4, done.
remote: Counting objects: 100% (4/4), done.
remote: Compressing objects: 100% (2/2), done.
remote: Total 3 (delta 0), reused 0 (delta 0), pack-reused 0
Unpacking objects: 100% (3/3), 694 bytes | 694.00 KiB/s, done.
From github.com:usuario/Prueba
   f2612e6..e442da5  auxiliar   -> origin/auxiliar
Already up to date.

Si queremos obtener el contenido de las ramas remotas pero sin fusionar automáticamente cualquier contenido que haya podemos usar:

$ git remote update

Esto obtendrá el contenido de todas las ramas remotas, para que podamos hacer un checkout o fusionarlas según sea necesario, peor no lo hace automáticamente.


Subir una nueva rama que hayamos creado localmente al repositorio remoto.

# Creamos la nueva rama local
txema@macbook:~/Prueba$ git checkout -b datos
Switched to a new branch 'datos'

# Creamos algo de contenido y hacemos una confirmación.
txema@macbook:~/Prueba$ echo '# Nueva rama' > datos.dat
txema@macbook:~/Prueba$ git add .
txema@macbook:~/Prueba$ git commit -m 'nuevo archivo en rama datos'
[datos 6746957] nuevo archivo en rama datos
 1 file changed, 1 insertion(+)
 create mode 100644 datos.dat

# Subimos la nueva rama al repositorio remoto con:
# git push -u origin [nueva_rama_local]
txema@macbook:~/Prueba$ git push -u origin datos
Enumerating objects: 4, done.
Counting objects: 100% (4/4), done.
Delta compression using up to 2 threads
Compressing objects: 100% (2/2), done.
Writing objects: 100% (3/3), 359 bytes | 359.00 KiB/s, done.
Total 3 (delta 0), reused 0 (delta 0), pack-reused 0
remote: 
remote: Create a pull request for 'datos' on GitHub by visiting:
remote:      https://github.com/usuario/Prueba/pull/new/datos
remote: 
To github.com:usuario/Prueba.git
 * [new branch]      datos -> datos
Branch 'datos' set up to track remote branch 'datos' from 'origin'.

Eliminar una Rama remota.


$ git push --delete origin <rama_a_borrar>







domingo, 9 de octubre de 2022

GIT - 3 - GITHUB - Clonar/Subir repositorio - Gestión de Credenciales.

 ¿Que es Github?


Es un portal creado para poder alojar el código de las aplicaciones de cualquier desarrollador. Utiliza el código de control de versiones Git que estamos viendo, que fue creado por Linus Torvalds.

No es el único que existe, ya que existen servicios similares como Bitbucket y GitLab.

Lógicamente antes de empezar a usarlo tenemos que darnos de alta en el servicio

Una vez registrado puedes hacer multitud de cosas, como por ejemplo crear tu propio repositorio, escribir el código en un navegador web, muy similar a  Visual Studio Code o trabajar en local desde el ordenador. 

Para ver como funciona vamos a crear un repositorio ficticio nuestro, lo clonaremos, trabajaremos con el en local y finalmente lo volveremos a subir a Github. Existen también infinidad de repositorios creados por la comunidad que puedes utilizar de la misma forma, es decir, buscas el que necesites y lo clonas a tu ordenador como vamos a ver a continuación.


Crear un repositorio y subirlo a Github



Si lo que quieres es clonar un repositorio que ya existe en Github o en cualquier otro servidor, para trabajar con él en local.

Por ejemplo este programa para resolver sudokus:

$ git clone https://github.com/kying18/sudoku.git
Copiará el contenido del repositorio dentro del directorio donde hayas lanzado 
el comando.
Si lo que quieres es crear tu propio repositorio y subirlo a Github.

Lo primero es abrir el navegador, ir a Github y logearnos.

Luego se pueden utilizar varias opciones:

a) Con una cuenta en esta plataforma, cuyo registro es gratuito, puedes subir archivos a GitHub. Para ello primero crearemos un repositorio en Github de la siguiente manera:

1.- Aunque existen varias formas, una de ellas es la siguiente. Utiliza el menú desplegable de la esquina superior derecha, y seleccionas tus repositorio. 



Luego le das al botón "New"  o  "Nuevo" según tengas configurado el idioma.



Se abrirá la pantalla donde podremos seleccionar varias opciones. La más importante es el nombre del repositorio. En este caso le he llamado "Prueba" y lo he dejado como Público para que cualquiera en la web pueda verlo y trabajar con él. También podemos añadir una descripción. En la parte inferior le damos al botón "Crear Repositorio".




En la siguiente pantalla nos darán información útil de como crear un repositorio nuevo o subir uno que ya tengamos a través de la línea de comandos a este proyecto. Lo que nos importa en este caso es apuntar el enlace al repositorio ya que nos será útil posteriormente.




Aunque lo puedes hacer antes de crear el proyecto, en este ejemplo vamos a crear el archivo README junto con la creación del repositorio (En este archivo puedes usar el lenguaje markdown para darle formato).  Ya un terminal de nuestro ordenador ponemos el repositorio en marcha.

Creamos el archivo readme.md que contendrá instrucciones de como funciona
el programa y como ponerlo en marcha.
$ echo "# Aquí Irán las instrucciones." > README.md

Ahora iniciamos el repositorio.
$ git init 

Creamos un archivo más para añadir al repositorio, para ver como funciona
el ejemplo.
$ touch main.py

Lo añadimos todo al árbol de trabajo y al stage.
$ git add .

Realizamos una confirmación.
$ git commit -m "Primer y único commit"

Como una de las cosas que recomienda Github es cambiar el nombre de la 
rama master a main, vamos a hacerlo. Ya ha habíamos visto una opción 
que era usar justo después del git init, el comando git checkout -b main.
Ahora haremos lo mismo pero ya al final con el siguiente comando:
$ git branch -M main

Ahora viene lo importante. Le decimos a git que añada el repositorio local,
el que tenemos en el ordenador, a github, que es el repositorio remoto. 
Aquí es donde tenemos que tener la ruta o enlace al repositorio remoto que 
apuntamos en un paso anterior.
$ git remote add origin https://github.com/Usuario/Prueba.git

* Usuario es tu nombre de usuario en Github

Para finalizar ejecutamos los cambios con el siguiente comando:
$ git push -u origin main
nos pedirá nuestro nombre de usuario y luego la contraseña de github.
Sin embargo cuando le das la Intro.

.....SORPREEEEEEEESAAAAAAA !!!!!
Support for password authentication was removed on August 13, 2021.


La autenticación basada en contraseña para Git se quitó en favor de métodos de autenticación más seguros, así que tendremos que usar uno de ellos para identificarnos ante el servidor y poder enviar el repositorio a Github.

Vamos a verlos:

1.- Creación de un Token de acceso personal.

Para entendernos, un Token es un código de seguridad que nos permite autenticarnos en Github cuando usamos la línea de comandos en el terminal. Como obtenerlo está muy bien explicado en el enlace a la página de documentación de Githubno me detendré a comentar como hacerlo.  Eso si en cuanto la página lo genere guárdalo en algún sitio, porque tal como dice el aviso no te lo volverán a mostrar de nuevo.

Una vez que lo tengamos ya podemos subir el repositorio, proseguimos donde lo dejamos:

$ git push -u origin main
Username: tu nombre de usuario
Password: tu token de acceso 
El problema de los tokens de seguridad es que, al igual que la contraseña hay que introducirlo cada vez que necesitemos conectarnos al servidor de github a través de la línea de comandos, bien sea porque queramos clonar un repositorio o subir el nuestro propio.  

Una forma de mitigar esto es usar un ayudante de credenciales que se almacena en la cache del ordenador para un determinado tiempo, de forma estándar 15 minutos. 

    $ git config --global credential.helper cache

Si quieres establecer un determinado periodo de tiempo, por ejemplo 2 horas hay que usar el parámetro  --timeout. (el tiempo en segundos)

    $ git config --global credential.helper cache --timeout=120

Puedes obtener más información en "Caching your Github credentials in Git".




Seguimos los siguientes pasos:

a) generar la llave privada y pública.
$ ssh-keygen -t ed25519 -C "your_email@example.com"
Dentro de las comillas ponemos nuestra dirección de correo, la que usamos al registrarnos en Github.

b) Añadir la llave ssh al agente ssh

- Nos aseguramos de que el agente está activo:
# start the ssh-agent in the background
$ eval "$(ssh-agent -s)"
> Agent pid 59566
- Agregamos nuestra llave ssh privada al agente para poder usarla. Si has creado tu clave con un nombre diferente o si estas agregando una clave existente que tenga un nombre diferente, reemplaza id_ed25519 en el comando con el nombre de tu archivo de clave privada.
Si has puesto contraseña a la clave cuando la generamos, el sistema de la pedirá en este momento.

    $ ssh-add ~/.ssh/id_ed25519


a) Abrimos la clave pública con cualquier editor de texto y la copiamos. Si no le has cambiado el nombre es el archivo id_ed25519.pub

b) En la esquina superior derecha de cualquier página, haz clic en la foto del perfil y, luego, en Settings (Configuración).

settings git

A la izquierda, en la sección que pone "Acess", haz click en "SSH and GPG KEYS"

c) Hacemos click en "New SSH Key" o en "Add SSH Key"

d) En el campo "Título", agrega una etiqueta descriptiva para la nueva clave. Por ejemplo, si estás utilizando una computadora portátil personal, puedes poner "Laptop personal".

e) Seleccionamos el tipo de clave "Autenticación" o "Firma". Si no sabes cual usar déjala en autenticación. Puedes encontrar más información aquí

f) Pega tu llave pública en el campo donde pone "Key"

key field



g)  Para finalizar haz click en "Add SSH Key"

botón añadir llave

Si se te solicita, confirma tu contraseña en GitHub

Para comprobar si todo ha ido correcto probáremos la conexión ssh con github siguiendo las instrucciones de este enlace tal como indica la documentación de github.

IMPORTANTE:

Recuerda cuando clones tus repositorio tomar la opción de copiar la url por SSH y no por HTTP, sino, no estarás usando la llave ssh que hemos creado.

Por ejemplo, para clonar el repositorio del sudoku que puse al principio utilizando la conexión SSH seria:

    $ git clone git@github.com:kying18/sudoku.git


Si volvemos al repositorio que dejamos preparado para subir a Github, ya vimos como subirlo usando un token de seguridad, ahora usando SSH el proceso se hace directamente (aunque tendrás que poner la contraseña de la llave la primera vez que lo utilices seguramente). El comando sigue siendo el mismo, solo que ahora va automáticamente:

    $ git push -u origin main



3) Si trabajas con Visual Studio Code el tema es sencillo también. Puedes crear el repositorio como hemos antes y una vez que tengas el proyecto finalizado le das al icono de Git o haces que se muestre yendo al menú view --> Source Control y ejecutas la opción de push y sigues las instrucciones.