Uso un par de packages de software (como gitlab) que instalas clonando de su git repo. Por lo general, vienen con algún config.example
(bajo control de versión), que copy en su propio file de config
(no bajo control de versión o incluso ignorado en .gitignore
) y se adapta a sus necesidades.
Cuando el package original se actualiza y, por ejemplo, cambia las opciones del file de configuration que, obviamente, solo se reflejarán en config.example
.
¿Hay una cadena de commands git que me falta que me pueden ayudar a comparar los cambios de config.example
con el nuevo en upstream/HEAD
y tal vez incluso combinarlos de forma interactiva en mi file de config
local?
Sería increíble si pudiera get algo como el modo de parche interactivo en git add/commit --interactive
.
git checkout --patch
selecciona diff hunks, lo más simple aquí podría ser poner tu contenido en la ruta de subida, hacer eso y limpiar después de:
cp config config.example git checkout -p upstream config.example mv config.example config git checkout @ config.example
eso te dará la selección de git add --patch
dos diferencias de git add --patch
.
vim
como una herramienta de combinación con vimdiff
. Emacs
puede hacer esto también con ediff-mode
. Probablemente puedas acercarte a esto de muchas maneras. Podría pensar en dos: git-merge-file
y un buen patch
viejo. El método git-merge-file
ofrece algo de interactividad, mientras que el método patch
no ofrece ninguno.
git-merge-file
config.example
que tiene un file original config.example
que utiliza para crear un file local sin versión, config.local
. Ahora, cuando se actualizan las actualizaciones de config.example
, puede seguir algo así como los siguientes pasos para fusionar cualquier cambio nuevo.
$ git fetch $ git show master:config.example > config.example.base $ git show origin/master:config.example > config.example.latest $ git merge-file config.local config.example.base config.example.latest
Esto actualizará config.local
con los marcadores de conflicto habituales, que luego tendrá que resolver con su herramienta de combinación favorita ( ediff
en Emacs es agradable, estoy seguro de que hay modos similares para Vim). Por ejemplo, los siguientes tres files,
config.example.base :
Original: some config
config.example.latest :
Original: some config Upstream: new upstream config
config.local :
Original: some config My changes: some other config
se fusionará así:
Original: some config <<<<<<< config.local My changes: some other config ======= Upstream: new upstream config >>>>>>> config.example.latest
Probablemente podrías escribir esto sin mucho esfuerzo. Por cierto, git-merge-file
puede operar en 3 files, no necesitan ser controlados por versión bajo git
. ¡Eso significa que uno podría usarlo para combinar tres files!
patch
: Suponiendo los mismos nombres de file, config.local
y config.example
, lo siguiente debería funcionar.
$ git fetch $ git diff master..origin/master -- config.example | sed -e 's%\(^[-+]\{3\}\) .\+%\1 config.local%g' > /tmp/mypatch $ patch < /tmp/mypatch
Si desea la combinación completa de git, puede hacer que git lo haga con contenido arbitrario configurando una input de índice como lo hace git read-tree
y luego invocando el controller de combinación normal de git en esa input. Git se refiere a las diferentes versiones de contenido como "etapas"; son 1: el original, 2: tuyo, 3: el suyo. La fusión compara los cambios de 1 a 2 y de 1 a 3 y hace su trabajo. Para configurarlo, use git update-index
:
orig_example= # fill in the commit with the config.example you based yours on new_upstream= # fill in the name of the upstream branch ( while read; do printf "%s %s %s\t%s\n" $REPLY; done \ | git update-index --index-info ) <<EOD 100644 $(git rev-parse $orig_example:config.example) 1 config 100644 $(git hash-object -w config) 2 config 100644 $(git rev-parse $new_upstream:config.example) 3 config EOD
y ha organizado una combinación de contenido personalizado para esa ruta. Ahora hazlo:
git merge-index git-merge-one-file -- config
y automatizará o abandonará los excrementos habituales del conflicto, lo arreglará como lo desee y se git rm --cached --ignore-unmatch
(o mantendrá) la input del índice si lo desea.
La ruta que pones en el índice (la "configuration" en las tres inputs aquí), por cierto, no tiene que existir ni tener nada que ver con nada. Puedes ponerle el nombre "wip" o "deleteme" o cualquier cosa que desees. La fusión es del contenido id'd en la input del índice.
Creo que eso hará lo que quieras aquí. Si realmente quieres escoger y elegir entre los cambios en sentido ascendente, puedes poner tu propio contenido en config.example y hacer git checkout -p upstream -- config.example
, que hace el inverso de git add -p
, luego volver a poner las cosas como estaban.
Para diferenciar solo config.example
en su repository local con el file correspondiente en el config.example
upstream/HEAD
, puede ejecutar:
git diff upstream/HEAD config.example
Desafortunadamente, no conozco una manera de hacer que git aplique directamente los cambios a un file que git no rastrea.
Hay una herramienta llamada sdiff que puede hacer lo que quieras.
Invocarlo (en su caso) con sdiff -o config config.example config
Lo siguiente debería funcionar:
git diff <some-args> | perl -pe 's/path\/to\/changes\/file/path\/other/g' > t patch -p1 < t rm t