tag remove practices crear commits best git svn version-control version-control-keywords

remove - ¿Sustitución de palabras clave de Git como las de Subversion?



git tag commits (3)

Solía ​​trabajar con Subversion / SVN y estaba usando al instante una función agradable llamada sustitución de palabras clave. Simplemente agregando archivos fuente como:

/* * $Author: ivanovpv $ * $Rev: 42 $ * $LastChangedDate: 2012-05-25 21:47:42 +0200 (Fri, 25 May 2012) $ */

Y cada vez que Subversion sustituía las palabras clave (Author, Rev, LastChangedDate) por palabras reales.

Hace algún tiempo me obligaron a mudarme a Git y me preguntaba si hay algo similar a la sustitución de palabras clave de Subversion en Git?


Solución

Bueno, podrías implementar fácilmente esa función tú mismo.

Básicamente incrustó el comando commit en un script de shell. Este script primero sustituirá las macros deseadas y luego confirmará los cambios. El proyecto consiste en dos archivos:

¿Contenido?

keysub , un script de shell bash y keysub.awk un script awk para reemplazar palabras clave en un archivo específico. Un tercer archivo es un archivo de configuración que contiene los valores que se deben sustituir (además de cosas variables como el recuento de compromisos y la marca de tiempo).

¿Como lo usas?

Llama a keysub lugar de commit con las mismas opciones. La opción -m o -a debe aparecer antes que cualquier otra opción de confirmación. Una nueva opción (que siempre debe ser lo primero) es -f que toma un archivo de configuración como un valor. Ejemplo:

$ git add ''someJavaFile.java'' $ keysub -m ''fixed concurrent thread issue'' $ git push

o

$ git -f .myfile.cnf -m ''enhanced javadoc entries''

KeySub

#!/bin/bash # 0 -- functions/methods ######################### # <Function description> function get_timestamp () { date # change this to get a custom timestamp } # 1 -- Variable declarations ############################# # input file for mapping file=".keysub.cnf" timestamp=$(get_timestamp) # 2 -- Argument parsing and flag checks ######################################## # Parsing flag-list while getopts ":f:m:a" opt; do case $opt in f) file=${OPTARG} ;; a) echo ''Warning, keyword substitution will be incomplete when invoked'' echo ''with the -a flag. The commit message will not be substituted into'' echo ''source files. Use -m "message" for full substitutions.'' echo -e ''Would you like to continue [y/n]? /c'' read answer [[ ${answer} =~ [Yy] ]] || exit 3 unset answer type="commit_a" break ;; m) type="commit_m" commitmsg=${OPTARG} break ;; /?) break ;; esac done shift $(($OPTIND - 1)) # check file for typing if [[ ! -f ${file} ]] then echo ''No valid config file found.'' exit 1 fi # check if commit type was supplied if [[ -z ${type} ]] then echo ''No commit parameters/flags supplied...'' exit 2 fi # 3 -- write config file ######################### sed " /timestamp:/ { s//(timestamp:/).*//1${timestamp}/ } /commitmsg:/ { s//(commitmsg:/).*//1${commitmsg:-default commit message}/ } " ${file} > tmp mv tmp ${file} # 4 -- get remaining tags ########################## author=$(grep ''author'' ${file} | cut -f1 -d'':'' --complement) # 5 -- get files ready to commit ################################# git status -s | grep ''^[MARCU]'' | cut -c1-3 --complement > tmplist # 6 -- invoke awk and perform substitution ########################################### # beware to change path to your location of the awk script for item in $(cat tmplist) do echo ${item} awk -v "commitmsg=${commitmsg}" -v "author=${author}" / -v "timestamp=${timestamp}" -f "${HOME}/lib/awk/keysub.awk" ${item} / > tmpfile mv tmpfile ${item} done rm tmplist # 5 -- invoke git commit ######################### case ${type} in "commit_m") git commit -m "${commitmsg}" "$@" ;; "commit_a") git commit -a "$@" ;; esac # exit using success code exit 0

keysub.awk

# 0 BEGIN ########## BEGIN { FS=":" OFS=": " } # 1 parse source files ######################## # update author $0 ~ /.*/$Author.*/$.*/ { $2=author " $" } # update timestamp $0 ~ /.*/$LastChangedDate.*/$.*/ { $0=$1 $2=timestamp " $" } # update commit message $0 ~ /.*/$LastChangeMessage.*/$.*/ { $2=commitmsg " $" } # update commit counts $0 ~ /.*/$Rev.*/$.*/ { ++$2 $2=$2 " $" } # print line { print }

Archivo de configuración

author:ubunut-420 timestamp:Fri Jun 21 20:42:54 CEST 2013 commitmsg:default commit message

Observaciones

Intenté documentar lo suficiente para que pueda implementarlo fácilmente y modificarlo según sus necesidades personales. Tenga en cuenta que puede asignar a las macros cualquier nombre que desee, siempre que lo modifique en el código fuente. También intenté mantener relativamente fácil la extensión del script; debería poder agregar nuevas macros con bastante facilidad. Si está interesado en extender o modificar el guión, es posible que desee echar un vistazo al directorio .git también, debe haber mucha información allí que puede ayudar a mejorar el guión, debido a la falta de tiempo que no hice investigar la carpeta sin embargo.


Git no incluye esta funcionalidad lista para usar. Sin embargo, hay un capítulo en el Libro de Git sobre Customizing Git y uno de los ejemplos es cómo usar los atributos de git para implementar un resultado similar.

Resulta que puedes escribir tus propios filtros para hacer sustituciones en los archivos en commit / checkout. Estos se llaman filtros "limpios" y "difuminados". En el archivo .gitattributes , puede establecer un filtro para determinadas rutas y luego configurar las secuencias de comandos que procesarán los archivos justo antes de que se comprueben ("borrón") y justo antes de que se organicen ("limpiar"). Estos filtros se pueden configurar para hacer todo tipo de cosas divertidas.

Incluso hay un ejemplo para $LastChangedDate: $ :

Otro ejemplo interesante obtiene la expansión $Date$ keyword $Date$ keyword, estilo RCS. Para hacer esto correctamente, necesita un pequeño script que tome un nombre de archivo, descubra la fecha del último compromiso para este proyecto e inserte la fecha en el archivo. Aquí hay un pequeño script de Ruby que hace eso:

#! /usr/bin/env ruby data = STDIN.read last_date = `git log --pretty=format:"%ad" -1` puts data.gsub(''$Date$'', ''$Date: '' + last_date.to_s + ''$'')

Todo lo que hace el script es obtener la fecha de compromiso más reciente del comando git log , pegarlo en cualquier $Date$ strings que vea en stdin, e imprimir los resultados; debe ser fácil de hacer en el idioma en el que se sienta más cómodo. Puede expand_date nombre a este archivo expand_date y ponerlo en su camino. Ahora, debe configurar un filtro en Git (llámalo dater ) y dígale que use su filtro expand_date para difuminar los archivos en el proceso de pago. Usarás una expresión Perl para limpiar eso en commit:

$ git config filter.dater.smudge expand_date $ git config filter.dater.clean ''perl -pe "s////$Date[^///$]*///$////$Date///$/"''

Este fragmento de Perl elimina todo lo que ve en una cadena $Date$ , para volver al lugar donde comenzó. Ahora que su filtro está listo, puede probarlo configurando un atributo de Git para ese archivo que active el nuevo filtro y cree un archivo con su palabra clave $Date$ :

date*.txt filter=dater $ echo ''# $Date$'' > date_test.txt If you commit

esos cambios y revisa el archivo nuevamente, ve la palabra clave correctamente sustituida:

$ git add date_test.txt .gitattributes $ git commit -m "Testing date expansion in Git" $ rm date_test.txt $ git checkout date_test.txt $ cat date_test.txt # $Date: Tue Apr 21 07:26:52 2009 -0700$

Puede ver cuán poderosa puede ser esta técnica para aplicaciones personalizadas. Sin embargo, debe tener cuidado, ya que el archivo .gitattributes se compromete y se transmite con el proyecto, pero el controlador (en este caso, dater ) no lo está, por lo que no funcionará en todas partes. Cuando diseñe estos filtros, deberían poder fallar con elegancia y que el proyecto aún funcione correctamente.