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. Puedeexpand_date
nombre a este archivoexpand_date
y ponerlo en su camino. Ahora, debe configurar un filtro en Git (llámalodater
) y dígale que use su filtroexpand_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.
Tristemente no.
Lea su documentación, enlace adjunto: Expansión de palabras clave