tag practices delete crear commits commands best git bash shell

practices - Compruebe si es necesario tirar en Git



git tag commits (22)

Si tienes una sucursal upstream

git fetch <remote> git status

Si no tienes una sucursal upstream

Compara las dos ramas:

git fetch <remote> git log <local_branch_name>..<remote_branch_name> --oneline

Por ejemplo:

git fetch origin # See if there are any incoming changes git log HEAD..origin/master --oneline

(Supongo que origin/master es su rama de seguimiento remoto)

Si alguna confirmación aparece en la salida anterior, entonces tiene cambios entrantes, debe fusionar. Si no se enumeran las confirmaciones por git log entonces no hay nada que fusionar.

Tenga en cuenta que esto funcionará incluso si se encuentra en una rama de función, que no tiene un control remoto de seguimiento, ya que si se refiere explícitamente a origin/master lugar de utilizar implícitamente la rama ascendente recordada por Git.

¿Cómo verifico si el repositorio remoto ha cambiado y necesito extraer?

Ahora uso este simple script:

git pull --dry-run | grep -q -v ''Already up-to-date.'' && changed=1

Pero es bastante pesado.

¿Hay alguna manera mejor? La solución ideal sería verificar todas las sucursales remotas y devolver los nombres de las sucursales modificadas y el número de confirmaciones nuevas en cada una.


Aquí está mi versión de un script Bash que comprueba todos los repositorios en una carpeta predefinida:

https://gist.github.com/henryiii/5841984

Puede diferenciar entre situaciones comunes, como el tirón necesario y el empuje necesario, y está multiproceso, por lo que la recuperación se realiza de una vez. Tiene varios comandos, como pull y status.

Coloque un enlace simbólico (o la secuencia de comandos) en una carpeta en su ruta, entonces funciona como git all status (, etc.). Solo admite origen / master, pero puede editarse o combinarse con otro método.


Aquí hay un Bash de una sola línea que compara el hash de confirmación HEAD de la sucursal actual con su sucursal ascendente remota, sin git pull --dry-run una gran git fetch git pull --dry-run o git pull --dry-run operaciones de git pull --dry-run requeridas:

[ $(git rev-parse HEAD) = $(git ls-remote $(git rev-parse --abbrev-ref @{u} | / sed ''s//// /g'') | cut -f1) ] && echo up to date || echo not up to date

Así es como se descompone esta línea un tanto densa:

  • Los comandos se agrupan y anidan usando la sintaxis de command-substitution $(x) Bash.
  • git rev-parse --abbrev-ref @{u} devuelve una referencia ascendente abreviada (por ejemplo, origin/master ), que luego se convierte en campos separados por espacios mediante el comando piped sed , por ejemplo, origin master .
  • Esta cadena se alimenta a git ls-remote que devuelve la confirmación de encabezado de la rama remota. Este comando se comunicará con el repositorio remoto. El comando de cut canalizado extrae solo el primer campo (el hash de confirmación), eliminando la cadena de referencia separada por tabulaciones.
  • git rev-parse HEAD devuelve el hash de confirmación local.
  • La sintaxis de Bash [ a = b ] && x || y [ a = b ] && x || y completa una línea: esta es una string-comparison Bash = dentro de una construcción de [ test ] , seguida de las construcciones de lista y de or o lista && true || false && true || false

Basé esta solución en los comentarios de @jberger.

if git checkout master && git fetch origin master && [ `git rev-list HEAD...origin/master --count` != 0 ] && git merge origin/master then echo ''Updated!'' else echo ''Not updated.'' fi


Creo que la mejor manera de hacer esto sería:

git diff remotes/origin/HEAD

Suponiendo que tienes la refspec registrada. Debe hacerlo si ha clonado el repositorio, de lo contrario (es decir, si el repositorio se creó de novo localmente y se envió al control remoto), debe agregar el refspec explícitamente.


Después de leer muchas respuestas y varias publicaciones, y pasar medio día probando varias permutaciones, esto es lo que he encontrado.

Si está en Windows, puede ejecutar este script en Windows usando Git Bash proporcionado por Git para Windows (instalación o portátil).

Este script requiere argumentos.

- local path e.g. /d/source/project1 - Git URL e.g. https://[email protected]/username/project1.git - password if a password should not be entered on the command line in plain text, then modify the script to check if GITPASS is empty; do not replace and let Git prompt for a password

El guion sera

- Find the current branch - Get the SHA1 of the remote on that branch - Get the SHA1 of the local on that branch - Compare them.

Si hay un cambio como lo imprime el script, entonces puede proceder a buscar o extraer. El guión puede no ser eficiente, pero hace el trabajo por mí.

Actualización - 2015-10-30: stderr a dev null para evitar la impresión de la URL con la contraseña en la consola.

#!/bin/bash # Shell script to check if a Git pull is required. LOCALPATH=$1 GITURL=$2 GITPASS=$3 cd $LOCALPATH BRANCH="$(git rev-parse --abbrev-ref HEAD)" echo echo git url = $GITURL echo branch = $BRANCH # Bash replace - replace @ with :password@ in the GIT URL GITURL2="${GITURL/@/:$GITPASS@}" FOO="$(git ls-remote $GITURL2 -h $BRANCH 2> /dev/null)" if [ "$?" != "0" ]; then echo cannot get remote status exit 2 fi FOO_ARRAY=($FOO) BAR=${FOO_ARRAY[0]} echo [$BAR] LOCALBAR="$(git rev-parse HEAD)" echo [$LOCALBAR] echo if [ "$BAR" == "$LOCALBAR" ]; then #read -t10 -n1 -r -p ''Press any key in the next ten seconds...'' key echo No changes exit 0 else #read -t10 -n1 -r -p ''Press any key in the next ten seconds...'' key #echo pressed $key echo There are changes between local and remote repositories. exit 1 fi


Ejecute git fetch (remote) para actualizar sus refs remotos, le mostrará las novedades. Luego, cuando compruebe su sucursal local, le mostrará si está detrás del flujo ascendente.


El comando

git ls-remote origin -h refs/heads/master

listará la cabecera actual en el control remoto; puede compararlo con un valor anterior o ver si tiene el SHA en su repositorio local.


El siguiente script funciona perfectamente.

changed=0 git remote update && git status -uno | grep -q ''Your branch is behind'' && changed=1 if [ $changed = 1 ]; then git pull echo "Updated successfully"; else echo "Up-to-date" fi


Haría el camino sugerido por brool. La siguiente secuencia de comandos de una línea toma el SHA1 de su última versión comprometida y la compara con la del origen remoto, y extrae cambios solo si son diferentes. Y es aún más ligero que las soluciones basadas en git pull o git fetch .

[ `git log --pretty=%H ...refs/heads/master^` != `git ls-remote origin -h refs/heads/master |cut -f1` ] && git pull


Hay muchas respuestas muy ricas e ingeniosas ya. Para proporcionar algo de contraste, podría conformarme con una línea muy simple.

# Check return value to see if there are incoming updates. if ! git diff --quiet remotes/origin/HEAD; then # pull or whatever you want to do fi


Le sugiero que vaya a ver el script https://github.com/badele/gitcheck . He codificado este script para verificar en una sola pasada todos los repositorios de Git, y muestra quién no se ha comprometido y quién no ha presionado / tirado.

Aquí un ejemplo de resultado:


Para los usuarios de Windows que terminan esta pregunta buscando esto, he modificado algunas de las respuestas en un script de powershell. Modifique según sea necesario, guárdelo en un archivo .ps1 y ejecútelo a pedido o programado si lo desea.

cd C:/<path to repo> git remote update #update remote $msg = git remote show origin #capture status $update = $msg -like ''*local out of date*'' if($update.length -gt 0){ #if local needs update Write-Host (''needs update'') git pull git reset --hard origin/master Write-Host (''local updated'') } else { Write-Host (''no update needed'') }


Primero use git remote update para actualizar sus refs remotos. Entonces puedes hacer una de varias cosas, tales como:

  1. git status -uno le dirá si la sucursal que está rastreando está adelantada, atrasada o divergida. Si no dice nada, lo local y lo remoto son lo mismo.

  2. git show-branch *master le mostrará las confirmaciones en todas las ramas cuyos nombres terminan en ''master'' (por ejemplo, master y origin / master ).

Si usa -v con git remote update ( git remote -v update ) puede ver qué sucursales se actualizaron, por lo que no necesita más comandos.

Sin embargo, parece que desea hacer esto en un script o programa y terminar con un valor verdadero / falso. Si es así, hay formas de verificar la relación entre su compromiso HEAD actual y el jefe de la sucursal que está rastreando, aunque dado que hay cuatro resultados posibles, no puede reducirlo a una respuesta de sí / no. Sin embargo, si está preparado para realizar una pull --rebase entonces puede tratar "local está detrás" y "local ha divergido" como "necesidad de tirar", y los otros dos como "no es necesario tirar".

Puede obtener el ID de confirmación de cualquier ref usando git rev-parse <ref> , así que puede hacer esto para master y origin / master y compararlos. Si son iguales, las ramas son las mismas. Si son desiguales, quieres saber cuál está por delante de la otra. El uso de git merge-base master origin/master te dirá el ancestro común de ambas ramas, y si no se han desviado, esto será lo mismo que una u otra. Si obtienes tres identificaciones diferentes, las ramas han divergido.

Para hacer esto correctamente, por ejemplo, en un script, debe poder referirse a la rama actual y a la rama remota que está rastreando. La función de configuración de solicitud de bash en /etc/bash_completion.d tiene algún código útil para obtener los nombres de las sucursales. Sin embargo, probablemente no necesite obtener los nombres. Git tiene algunos métodos abreviados para referirse a ramas y confirmaciones (como se documenta en git rev-parse --help ). En particular, puede usar @ para la rama actual (suponiendo que no se encuentre en un estado de cabeza separada) y @{u} para su rama ascendente (por ejemplo, origin/master ). Así que git merge-base @ @{u} devolverá el (hash de) el commit en el cual la rama actual y su divergencia en sentido ascendente y git rev-parse @ y git rev-parse @{u} le darán los hashes del dos consejos Esto se puede resumir en el siguiente script:

#!/bin/sh UPSTREAM=${1:-''@{u}''} LOCAL=$(git rev-parse @) REMOTE=$(git rev-parse "$UPSTREAM") BASE=$(git merge-base @ "$UPSTREAM") if [ $LOCAL = $REMOTE ]; then echo "Up-to-date" elif [ $LOCAL = $BASE ]; then echo "Need to pull" elif [ $REMOTE = $BASE ]; then echo "Need to push" else echo "Diverged" fi

Nota: las versiones anteriores de git no permitían @ solo, por lo que es posible que tenga que usar @{0} lugar.

La línea UPSTREAM=${1:-''@{u}''} permite opcionalmente pasar una sucursal en sentido ascendente explícitamente, en caso de que desee verificar una sucursal remota diferente a la configurada para la rama actual. Esto normalmente sería de la forma remotename / branchname . Si no se proporciona ningún parámetro, el valor predeterminado es @{u} .

El script asume que primero has realizado una git remote update git fetch o git remote update , para actualizar las sucursales de seguimiento. No incorporé esto en el script porque es más flexible poder realizar la extracción y la comparación como operaciones separadas, por ejemplo, si desea comparar sin recuperar porque ya lo hizo recientemente.


Si ejecuta este script, probará si la rama actual necesita un git pull :

#!/bin/bash git fetch -v --dry-run 2>&1 | grep -qE "/[up/s+to/s+date/]/s+$( git branch 2>/dev/null | sed -n ''/^/*/s/^/* //p'' | sed -r ''s:(/+|/*|/$):///1:g'' )/s+" || { echo >&2 "Current branch need a ''git pull'' before commit" exit 1 }

Es muy conveniente ponerlo como un gancho previo de Git para evitar

Merge branch ''foobar'' of url:/path/to/git/foobar into foobar

Cuando te commit antes de pulling .

Para usar este código como un gancho, simplemente copie / pegue el script en

.git/hooks/pre-commit

y

chmod +x .git/hooks/pre-commit


Si esto es para un script, puedes usar:

git fetch $(git rev-parse HEAD) == $(git rev-parse @{u})

(Nota: el beneficio de esto frente a las respuestas anteriores es que no necesita un comando por separado para obtener el nombre de la rama actual. "HEAD" y "@ {u}" (el canal actual de la rama actual) cuídelo. Consulte "git rev-parse --help" para más detalles.)


Solo quiero publicar esto como una publicación real, ya que es fácil perderse esto en los comentarios.

La respuesta correcta y mejor a esta pregunta fue dada por @Jake Berger, Muchas gracias, todos lo necesitan y todos lo extrañan en los comentarios. Así que para todos los que luchan con esto aquí es la respuesta correcta, solo use la salida de este comando para saber si necesita hacer un tirón de git. Si la salida es 0, obviamente no hay nada que actualizar.

@, dale campanas a este chico. Gracias @ Jake Berger

git rev-list HEAD...origin/master --count will give you the total number of "different" commits between the two. – Jake Berger Feb 5 ''13 at 19:23


Tal vez esto, si desea agregar tarea como crontab:

#!/bin/bash dir="/path/to/root" lock=/tmp/update.lock msglog="/var/log/update.log" log() { echo "$(date) ${1:-missing}" >> $msglog } if [ -f $lock ]; then log "Already run, exiting..." else > $lock git -C ~/$dir remote update &> /dev/null checkgit=`git -C ~/$dir status` if [[ ! "$checkgit" =~ "Your branch is up-to-date" ]]; then log "-------------- Update ---------------" git -C ~/$dir pull &>> $msglog log "-------------------------------------" fi rm $lock fi exit 0


También puede encontrar un script de Phing que hace eso ahora.

Necesitaba una solución para actualizar mis entornos de producción automáticamente y estamos muy contentos gracias a este script que estoy compartiendo.

El script está escrito en XML y necesita Phing .


Usando regexp simple:

str=$(git status) if [[ $str =~ .*Your/ branch/ is/ behind.*by.*commits,/ and/ can/ be/ fast-forwarded ]]; then echo `date "+%Y-%m-%d %H:%M:%S"` "Needs pull" else echo "Code is up to date" fi


Utilizo una versión de un script basado en la respuesta de Stephen Haberman:

if [ -n "$1" ]; then gitbin="git -C $1" else gitbin="git" fi # Fetches from all the remotes, although --all can be replaced with origin $gitbin fetch --all if [ $($gitbin rev-parse HEAD) != $($gitbin rev-parse @{u}) ]; then $gitbin rebase @{u} --preserve-merges fi

Suponiendo que este script se llame git-fetch-and-rebase , se puede invocar con un directory name de directory name argumentos opcional del repositorio Git local para realizar la operación. Si se llama al script sin argumentos, se supone que el directorio actual es parte del repositorio Git.

Ejemplos:

# Operates on /abc/def/my-git-repo-dir git-fetch-and-rebase /abc/def/my-git-repo-dir # Operates on the Git repository which the current working directory is part of git-fetch-and-rebase

Está disponible here también.


git ls-remote | cut -f1 | git cat-file --batch-check >&-

listará todo lo que se menciona en cualquier control remoto que no esté en su repositorio. Para capturar ref ref los cambios a cosas que ya tenías (por ejemplo, restablecimientos a confirmaciones previas) toma un poco más:

git pack-refs --all mine=`mktemp` sed ''/^#/d;/^^/{G;s/./(.*/)/n.* /(.*/)//1 /2^{}/;};h'' .git/packed-refs | sort -k2 >$mine for r in `git remote`; do echo Checking $r ... git ls-remote $r | sort -k2 | diff -b - $mine | grep ^/< done