Git merge and Git rebase

What is the bloody difference ?

Git-rebase and Git-merge are two methods for integrating code from two different branches. It is like the inverse of a bifurcation process. It may be called ‘code sexual reproduction’. The genomes of both branches need to combine in a specific way that produces a new commit. We expect that, with continuous integration (CI/CD), these modifications result in a viable entity, that is, software that runs without problems; passed all its test.

These two methods are implemented in the git software as git merge and git rebase. We can , thus, begin to analyse the difference between both by studying their syntax.

What follows my conversation with ChatGPT:

What is the syntax of git merge ?

The syntax for the git merge command in Git is as follows:

git merge [<options>] <branch>

Here’s a breakdown of the syntax components:

  • git merge: This is the base command to perform a merge operation in Git.
  • <options>: Optional flags that modify the behaviour of the merge operation. Some commonly used options include --no-ff to disable fast-forward merging and --squash to merge changes as a single commit.
  • <branch>: The branch you want to merge into the current branch. It can be specified as a branch name, a remote branch reference (e.g., origin/branch-name), or a commit hash.

How does it work?

When you run git merge <branch>, Git attempts to combine the changes from the specified branch into the current branch. It performs a “three-way merge” by comparing the changes between the common ancestor of the two branches (the merge base) and the HEAD commit of the current branch with the latest commit of the branch you’re merging.

During the merge, Git automatically applies the changes from the other branch and creates a new merge commit if there are conflicting changes. If there are no conflicts, Git performs a “fast-forward” merge, which moves the current branch pointer to the latest commit of the other branch.

After running the git merge command, Git may prompt you to resolve any conflicts manually if it couldn’t automatically merge all changes. You can use tools like a text editor or a dedicated merge tool to resolve conflicts. Once conflicts are resolved, you need to stage the changes and create a new commit to finalize the merge.

It’s important to note that the git merge command affects the commit history, so it’s a good practice to review and understand the changes before merging branches to ensure a clean and accurate merge.

What is the role of rebase in this context?

In the context of merging in Git, the git rebase command is an alternative approach to incorporating changes from one branch into another. While git merge combines the changes from different branches, git rebase integrates the commits from one branch onto another branch as if they were made on top of the other branch.

The role of git rebase is to maintain a linear commit history by moving, or “replaying,” the commits from the source branch onto the target branch. This can make the commit history cleaner and easier to follow, especially when dealing with long-running feature branches or branches with frequent commits.

When you perform a rebase, Git identifies the common ancestor commit between the current branch and the branch you want to rebase onto. It then applies the commits from the current branch one by one on top of the target branch, effectively “replaying” the changes. This can result in a linear sequence of commits without the additional merge commits that git merge creates.

Here’s a summary of the steps involved in a typical rebase workflow:

  1. Switch to the target branch: git checkout <target-branch>
  2. Start the rebase: git rebase <source-branch>
  3. Git will identify the common ancestor commit and replay the commits from <source-branch> on top of <target-branch>.
  4. If there are conflicts, Git will pause the rebase process, allowing you to resolve the conflicts manually.
  5. After resolving conflicts, stage the changes: git add <resolved-files>
  6. Resume the rebase: git rebase --continue
  7. Repeat steps 4-6 if there are additional conflicts until the rebase is complete.
  8. Once the rebase finishes successfully, the source branch is effectively incorporated into the target branch.

It’s important to note that git rebase rewrites the commit history, so it should be used with caution, especially when collaborating with others. If the source branch has been shared with others or pushed to a remote repository, you may need to communicate and coordinate the rebase to prevent conflicts for other users.

In summary, the role of git rebase in the context of merging is to integrate commits from one branch onto another while maintaining a linear commit history. It offers an alternative to git merge for incorporating changes and can result in a cleaner commit history.

What is the difference then?

The main difference between git merge and git rebase lies in how they incorporate changes from one branch into another and the resulting commit history.

git merge:

  • Combines the changes from a source branch into a target branch.
  • Creates a new merge commit to represent the merge operation, even if it’s a fast-forward merge.
  • Preserves the individual commits from both the source and target branches in the commit history.
  • Produces a commit graph that shows the branching and merging history of the repository.
  • Is suitable for merging feature branches, hotfixes, or integrating changes from multiple developers.

git rebase:

  • Integrates the commits from a source branch onto a target branch, making it appear as if the commits were made on top of the target branch from the beginning.
  • Does not create a merge commit unless there are conflicts that need to be resolved manually.
  • Rewrites the commit history of the source branch, creating new commits with different parent commits.
  • Produces a linear commit history without additional merge commits.
  • Can result in a cleaner and more straightforward commit history but can be disruptive when used on shared or public branches.

In summary, the key differences between git merge and git rebase are:

  • git merge combines branches, creates merge commits, and preserves the commit history of both branches.
  • git rebase integrates branches, rewrites commit history, and produces a linear commit history.

The choice between using git merge or git rebase depends on the specific scenario and your preferences for the commit history. Use git merge when you want to merge branches while preserving the original commits and their context. Use git rebase when you prefer a linear commit history and want to incorporate changes from one branch onto another as if they were made on top of the target branch.

[ GIT ] Inconsistencias en archivos remotos y locales

Cuando utilizamos git pull origin master internamente se ejecutan dos comandos: `git fetch` y git merge.

El primer comando git fetch origin master descarga el contenido de la rama (branch) master del repositorio origin Mientras, el comando git merge junta los archivos descargados con la rama master local. Es muy frequente que tengamos algunos archivos differentes a los del repositorio remoto y a la hora de hacer el mergese presenten inconsistencias entre el repositorio remoto y el local.

La forma más común de corregir esto es editando el archivo con problemas (usar git statussobre la raíz del repositorio) y seleccionar la versión que necesitemos, es decir, entre la version remota y la local. Git automaticamente añade las dos versiones en el archivo aludido concatenado las líneas de texto difentes entre las dos versiones. Estas diferencias son fácilmente visibles por que git añade adicionalmente las líneas >>>>[hash commit remoto] para las diferencias provenientes del repositorio remoto, y >>>HEAD para la version local. Ambas versiones están separadas por los símbolos =======. Recuerda, estas modificaciones son automáticamente añadidas en el archivo que presenta el problema.

Una vez que hemos borrado la versión que no queremos proseguimos a salvar el archivo, añadirlo al Stage de git (con git add [archivo problematico]) y luego hacemos un commit (git commit -m "alguna mensaje").

Arreglar inconsitencias en archivos grandes

Algunas veces editar manualmente cada archivo problemático puede ser engorroso o simplemente ya sabemos que alguna versión es mejor que la otra. Por ejemplo la versión local (nuestra versión) puede estar más actualizada o la versión remota (la del ellos) puede ser más estable.

En versiones git > 1.6.1 podemos utilizar la opción --ours (nuestra versión) o --theirs (la de ellos) para seleccionar si queremos mantener la versión local o la versión remota (respectivamente). Esta opción sólo es válida para el comando git checkout [archivo problemático] . De esta manera podemos hacer:

git checkout --ours [archivo problemático]

Para quedarnos con nuestra versión.

git checkout --theirs [archivo problemático]

Para quedarnos con la versión remota.

Filtrar una mega lista de objetos

Sabemos que filtrar una lista en Python puede hacerse con la función filter, que recibe una función booleana y un iterable, por ejemplo una lista.

La historia es esta. Tengo una lista de 455, 864 objetos Occurrence (llamada omega_tree.occurrences) , y quiero filtrar de aquí (remover) 16,380 (de una lista llamada ocs_of_interest). Originalmente pensé en simplemente hacer un filter:

ocs_complements = filter(lambda occurrence : occurrence not in ocs_of_interest , omega_tree.occurrences)

Estaba cansado y decidí dejar la compu corriendo. Cuando regresé a trabajar (12 horas después) el proceso seguía corriendo…

Pensé que tal vez se estaba lo que ocasionaba la demora era el método __hash__ y __eq__ que se utiliza para decidir si un elemento es igual al otro por lo que extraje solo el índice (un mapeo de los objectos Occurrence a Int). Esto hizo, efectivamente, más eficiente el filtrado pero igual, haciendo unas estimaciones a bote pronto me dijeron que posiblemente tardaría unas 10 horas… Rubish!

Me puse a buscar y encontré que la clase Set no solo es útil para remover elementos repetidos dentro de listas pero también hace muy eficiente la busqueda y, en mi caso, filtrado de objectos grandes.

Hice un cast (conversión) a lista para obtener un set. Los resultados fueron sorprendentes!!

%time ofi = set(map(lambda o : o.pk, ocs_of_interest))
%time oo = set(map(lambda o : o.pk ,omega_tree.occurrences))
%time ocs_complements = filter(lambda occurrence : occurrence not in ofi , oo)

CPU times: user 116 ms, sys: 0 ns, total: 116 ms
Wall time: 114 ms
CPU times: user 3.24 s, sys: 8 ms, total: 3.25 s
Wall time: 3.26 s
CPU times: user 136 ms, sys: 0 ns, total: 136 ms
Wall time: 133 ms

Conclusión

Para filtrar una lista grande de objetos conviene convertir la lista a conjunto (Set). El aumento de rendimiento es increiblemente grande!

Bacalao a la Vizcaína Mexicana

Ingredientes

  • 1 Kg de Bacalao
  • 1.3 Kg de Jitomate
  • 400g de cebolla
  • 200g de ajo
  • 1 manojo de perejil
  • 2 pimientos pelados (rojos) (puede ser lata)
  • 200g de aceitunas sin hueso
  • 150g de alcaparras
  • 1/2 taza de almendras
  • 2 tazas de papa cortada o chiquita
  • 1/2 taza aceite de oliva
  • 3 Rebanadas de pan
  • chiles gueros

Elaboración

Preprocesamiento

Cocer el bacalo, si es fresco. Hacer un caldito tarda poco. Una vez frío se desmenuza en lajitas.

Pelar el jitomate con el método del chef. Cortas los jitomates separas el endospermo (parte gelatinosa) con semillas y se pica el jitomate sin semillas. Las cáscaras y el endospermo se muele y se cuela. A esto se le llama purecito.

Se echan en una olla con agua hirviendo por un minuto y luego se sacan y echan al agua fria. Asi se pelan muy rápido.

El método del Chef

Se pica toda la cebolla en pequeños cubitos.

Se asan los pimientos para pelarlos con el método del sudado de chiles (trapo húmedo). Se parten en rajas.

Las aceitunas y alcaparras se ponen enteras, sin la salmuera.

Se pica o raya el ajo. El perejil también se pic finamente.

Las almendras se pelan con agua caliente y así se pelan fácilmente. Apachurrándolas suavemente. Se cortan en rebanaditas.

Dependiendo del tamaño de las papas se pueden cocer previamente si son grandes y ponerlas en el guisado en el último hervor.

Procedimiento del guisado

En una olla grande pones una parte de aceite, un poco, y se pone a freir unos dos dientes de ajo enteros con las rebanas de pan. Esto para que espese la salsa y quede rico. Retiras el pan dorado, sin dejar quemar junto con los ajos.

Una vez separado el pan y el ajo se muelen con un poco de purecito para formar una pastita.

Poner la cebolla y los ajos a freír. Una vez ya están sofritos se añade el jitomate, las papas y el perejil y se deja sazonar. Se le añade el purecito y la pastita de panajo. Si el jitomate está agrio se le puede pone una pizaca de azúcar.

En caso de usar bacalao seco (previo tratamiento) se añade en ese momento y se deja hervir al menos una hora. En caso de ser fresco no se necesita esto y se añade después.

Se añaden las aceitunas, alcaparras.

Se añaden los pimientos.

Se deja cocinar a fuego bajo hasta que el aceite suba y “haga ojos”. Se le pone sal al gusto y se le va añadiendo el caldito de bacalao mientras se esta cocinando la salsa.

Los “ojitos” del bacalao

En caso de usar bacalao fresco, se ponen las lajitas se pone en ese momento.

Se sirve con pan y con los chiles güeros.

Regresión logística jerarquizada con STAN

Estoy sorprendido por la capacidad y flexibilidad para expresar modelos estadísticos complejos con STAN. Como sabrán, STAN es un lenguage declarativo de programación probabilístico. Los modelos estadísticos son descritos con una sintaxis sencilla para especificar de una forma muy similar a lo que hacemos en el pizarrón o en papel. STAN está basado en principios bayesianos y utiliza varios métodos para muestrear distribuciones posteriores, entre los más conocidos están Hamiltonian Monte Carlo, Non U Turn y Metrópolis-Hastings (no voy a meterme a detalle en esto ahora, en internet hay montón de referencias al respecto).

En este post veremos como definir un modelo logistico jerárquico. Supongamos que para toda observación binaria \(y_i \in \{0,1\} \) existe un nivel associado \(j_i \in \{1,2,…,J\}\) y un vector de covariables (predictores) \(x_i \in \mathbb{R}^K\). Supondremos pues que las observaciones son realizaciones de un proceso bernoulli independendiente cuando se condiciona con un proceso normal jerarquizado. Esto es:

\([Y | S] \sim Bernoulli(S)\)

Ahora, \(S\) puede ser descrita de la siguiente forma:

\(S_{i,j} = \beta^t_j x_i + \epsilon\)

Y se lee de la siguiente forma. La variable S en la observación i del nivel j es igual a \(\beta^t_j x_{i} + \epsilon \). Es decir, el vector \(\beta\) son los coeficientes associados a la respuesta \(S_{i}\) en el nivel j.

En STAN esto es equivalente al siguiente código:

hierarquical_log_model = u"""
data {
  int<lower=0> N; // num obs. 
  int<lower=0> J; // number of levels
  int<lower=1> K;                // num covariates
  matrix[N, K] x;                // design matrix
  int<lower=1,upper=J> level[N];  // type of level (spec)
  int<lower=0,upper=1> y[N];              // observations, in this case is binary.
  
} 
parameters {
  real mu[K];
  vector[K] beta[J];
  real<lower=0,upper=100> sigma; // same sigma

}

model {
    for (k in 1:K) {
        mu[k] ~ normal(0,100);
        for (j in 1:J)
            beta[j,k] ~ normal(mu[k], sigma);
    }
    for (i in 1:N)
        y[i] ~ bernoulli_logit(x[i] * beta[level[i]]);
  
}"""

Para correr el modelo en Python usando PyStan hacer esto.

varying_intercept_model = pystan.StanModel(model_code=hierarquical_log_model)
multilevel_linear_data = {'N': X.shape[0],
                          'J': 2,
                          'K': X.shape[1],
                          'level': data.codes.values, # niveles
                          'x' : X.values,
                          'y': data.obs.values}
%time fit = varying_intercept_model.sampling(data=multilevel_linear_data, iter=1000,chains=1)
sample = fit.extract(permuted=True)

En este caso mis datos están definidos en un Pandas Dataframe llamado X, separado de las observaciones. Para eso use patsy. La muestra de la distribución posterior estará guardada en el objeto ‘sample’

Envolver líneas (text wrap) en VIM

Text wrap es el proceso de insertar saltos de línea automágicamente para poder visualizar líneas de texto mas grandes que la ventana del editor de texto (IDE).

Muchos IDEs hacen esto y VIM no es la excepción.

Para activarlo usar:


:set tw='n'

Donde ‘n’ es el número de caracteres por línea.

Para detener el proceso de wrap (envolver) hay que usar ‘n’=0

Modificar margen antes de aplicar wrap

Para modificar este valor usar:

:set wm=k

Donde ‘k’ es el numero de caracteres por tolerar antes de aplicar el wrap (cuando se haya sobrepasado el límite tw)

Soft wrap

Se no se quiere insertar símbolos EOL y únicamente se quiere visualizar saltos de línea úsese:

:set wrap linebreak nolist

Mas información

[N] VIM Shortcuts

My lista de los atajos (shortcuts) más usados en [N]VIM

Substituir texto entre dos marcadores

Ya sabemos que con la teclas [m] + [a-z] creamos un marcador dentro del archivo.

Podemos entonces substituir texto entre cualesquiera par de marcadores utilizando el siguiente comando (en modo Normal).

Supongamos pues que queremos cambiar la palabra ‘Político Priísta’ por ‘Rata’. Dentro del texto:

a

“El poder no lo debe tener y nunca debió haber regresado a Los Pinos ese poder del presidente con el PRI”, manifestó el político priista, quien el domingo a la noche no acompañó a José Antonio Meade Kuribreña en su noche triste..

b


El comando sería el siguiente:

:’a , ‘bs/político priista/rata/gc

Las opciones g y c significan: global (cambiará todas las occurrencias encontradas en cada línea) y confirmation (preguntará por confirmación para sustituir).

Hay más información aquí: https://vim.fandom.com/wiki/Search_and_replace


¿ Cómo crear paquetes de R ?

Objetivos

Queremos hacer un paquete (i.e. un conjunto de funciones, datos y documentación de R). El paquete debe ser accesible desde internet de la manera más eficiente posible. Se deben seguir las mejores prácticas de la comunidad, incluir los datos a utilizar, ejemplos , etc

Crear un repositorio Git

Lo primero que tenemos que hacer es crear un repositorio GIT. Hay muchos tutoriales ahí afuera para hacer repositorios. Usa el google.

Supongamos pues, que tenemos uno ya hecho. En mi caso, hice un fork de CARBayes (Duncan Lee) y lo puse en mi repositorio público en Github (https://github.com/molgor/CARBayeSDM.git )

Fijensé como esta la estructura de los archivos.

Paquetes necesarios

install.packages("devtools")
library("devtools")
install.packages("roxygen2")
library("roxygen2")

 

Devtools permite instalar paquetes desde repositorios GIT además de otras utilidades para desarrolladores. Roxygen es una librería crear documentación en R. Su nombre viene de la popular applicación Doxygen para crear documentación.

Inicializar la estructura

Podemos utilizar la función ‘create_package(Nombre_de_paquete) ‘ para crear una estructura de directorios.

setwd('ruta del repositorio')
create_package('mi_paquete')

La estructura quedará de la siguiente manera :

  • R (Carpeta donde se guardará el código de R)
  • man (Donde se guardará la documentación)
  • DESCRIPTION (archivo Readme que contiene la descripción del paquete)
  • NAMESPACE (configuración de las funciones definidas por el paquete)

 

Escribir función con documentación

Vamos a escribir las funciones dentro de la carpeta R. Aquí definiremos las funciones pero primero pondremos la documentación (descripción de cada función al comienzo del archivo). Ve el siguiente ejemplo. El archivo se llama: *MyTestingFunction.R* [ Disculpa por escribirla en inglés, ya quedará en ustedes traducirla] .

#' An example for writing a function in R using Roxygen (e.g. a variant of Doxygen for
#' R) 
#' Well, this function is for writing stuff, I suppose that I need to write here the
#' pourpose of the function.
#' @param something Something to put
#' @keywords Tests, examples, many
#' @export
#' @examples
#' test_function()

test_function  <- function(something=TRUE) {
  if(something==TRUE) {
   c = 'Something is True'
  return(c)
  }
  else {
    c = 'Something is different from TRUE'
    return(c)
  }
}

Compilar documentación e instalar

Para compilar la documentación basta con ejecutar:

document()

 

Para instalar todo:

setwd("..")
install("mi_paquete")

Usando repositorio en Github

Si se opta por esta opción se puede instalar directamente usando la función:

install_github('mi_paquete','usuario_de_github')

Listo! A desarrollar

Ahora podemos desarrollar paquetes de R, subirlos a github y compartirlos con todos nuestros colegas.

Colabora y no seas culer@!
Este post está basado en el ejemplo de Hillary Parker .

Solucionar: IO Error ‘[Errno 28] No space left on device’

Este error es frecuente al utilizar librerías de Python de multiprocesamiento ‘joblib’ con una cantidad considerable de datos.

Diagnostico

El problema es que la memoria compartida ‘/dev/shm’(usualmente menor que la memoria RAM) se satura.

Para corregirlo tendremos que cambiar la variable de entorno: JOBLIB_TEMP_FOLDER a un directorio que con mayor capacidad. (e.g. /tmp)

Esto puede hacerse directamente en iPython o Jupyter con:

%env JOBLIB_TEMP_FOLDER=/tmp

O agregandola en el shell con:

$ export JOBLIB_TEMP_FOLDER=/tmp

[Tutorial R] Modelos CAR generalizados

En este post veremos como ajustar *Conditional Autoregressive Models* (Una variante de Gaussian Markov Random Fields) a un conjunto de datos generados por Biospytial.

Para cargar los datos vaya a https://ecomorphisms.holobio.me/2019/01/28/tutorial-para-analisis-de-datos-espaciales-en-r/ 

Requisitos

Instalar paquete CarBayes

install.packages(‘CARBayes’)

The conditional autologistic model (Besag, et. al 1991) has the following specification (Lee, 2013).

$$k \in {1…K}$$ Neighbours

$$ Y_k \sim Binomial(n_k,\theta_k) $$

$$ ln\left(\frac{\theta_k}{1-\theta_k}\right)= x_k^t \beta + O_k + \psi_k$$

$$\beta \sim N(\mu_\beta,\Sigma_\beta)$$

$$ \psi_k = \phi_k + \theta_k $$

$$ \phi_k | \phi_{-k}, \mathbb{W},\tau^2 \sim N \left( \frac{\sum_{i=1}^{K} w_{ki} \phi_i}{\sum_{i=1}^{K}w_{ki}}, \frac{\tau^2}{\sum_{i=1}^{K}w_{ki}}\right) $$

$$\theta_k \sim N\left(0, \sigma^2\right)$$

$$\tau^2, \sigma^2 \sim^{iid} Inv.Gamma(a,b) $$

Referencias