¿Sustitución de palabras key de Git como las de Subversion?

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

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

Y cada vez Subversion estaba sustituyendo palabras key (Author, Rev, LastChangedDate) por palabras reales.

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

Solución

Bueno, podrías implementar fácilmente esa function tú mismo.

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

¿Contenido?

keysub , un script de shell bash y keysub.awk un script awk para replace palabras key en un file específico. Un tercer file es un file de configuration que contiene los valores que se deben sustituir (además de cosas variables como el recuento de compromisos y la timestamp).

¿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 file de configuration 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 configuration

 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 count 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 también desee examinar el directory .git, debería haber mucha información allí que pueda ayudar a mejorar el guión, debido a la falta de time que no tuve. investigar la carpeta sin embargo.

Git no incluye esta funcionalidad list 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 attributes de git para implementar un resultado similar.

Resulta que puedes escribir tus propios filters para hacer sustituciones en los files en commit / checkout. Estos se llaman filters "limpios" y "difuminados". En el file .gitattributes , puede establecer un filter para determinadas routes y luego configurar las secuencias de commands que procesarán los files justo antes de que se comprueben ("borrón") y justo antes de que se organicen ("limpiar"). Estos filters 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 file, descubra la date del último compromiso para este proyecto e inserte la date en el file. 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 get la date de compromiso más reciente del command 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 file expand_date y ponerlo en su path. Ahora, debe configurar un filter en Git (llámalo dater ) y dígale que use su filter expand_date para difuminar los files en el process 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 fragment de Perl elimina todo lo que ve en una cadena $Date$ , para volver al punto donde comenzó. Ahora que su filter está listo, puede probarlo configurando un atributo de Git para ese file que active el nuevo filter y cree un file con su palabra key $Date$ :

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

esos cambios y revisa el file nuevamente, ve la palabra key 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 file .gitattributes se compromete y se transmite con el proyecto, pero el controller (en este caso, dater ) no lo está, por lo que no funcionará en todas partes. Cuando diseñe estos filters, deberían poder fallar con elegancia y que el proyecto aún funcione correctamente.

Tristemente no.

Lea su documentation, enlace adjunto: Expansión de palabras key