web-dev-qa-db-fra.com

Quelles sont les différences entre Prune distant git, Prune git, git fetch --Prune, etc.

Ma situation est la suivante ... quelqu'un qui travaille sur le même référentiel a supprimé une branche de son référentiel local et distant ...

La plupart des gens qui ont posé des questions sur ce type de problème sur Stack Overflow ou sur d'autres sites ont le problème des branches qui apparaissent toujours dans leur liste de branches de suivi à distance git branch -a en bas:

* master
  develop
  feature_blah
  remotes/Origin/master
  remotes/Origin/develop
  remotes/Origin/feature_blah
  remotes/Origin/random_branch_I_want_deleted

Cependant, dans MA situation, la branche qui ne devrait pas être là est locale:

* master
  develop
  feature_blah
  random_branch_I_want_deleted
  remotes/Origin/master
  remotes/Origin/develop
  remotes/Origin/feature_blah

Lorsque je fais l'une des choses suivantes, il n'est pas supprimé localement:

$ git Prune

J'ai aussi essayé:

$ git remote Prune Origin
$ git fetch --Prune

Plus d'infos utiles: Quand je vérifie git remote show Origin c'est à quoi ça ressemble:

* remote Origin
Fetch URL: utilities:homeconnections_ui.git
Push  URL: utilities:homeconnections_ui.git
HEAD branch: master
Remote branches:
 master                        tracked
 develop                       tracked
 feature_blah                  tracked
 other123                      tracked
 other444                      tracked
 other999                      tracked
Local branches configured for 'git pull':
 develop                      merges with remote develop
 feature_blah                 merges with remote other999
 master                       merges with remote master
 random_branch_I_want_deleted merges with remote random_branch_I_want_deleted
Local refs configured for 'git Push':
 develop         pushes to develop     (local out of date)
 master          pushes to master      (up to date)
 feature_blah    pushes to feature_blah(up to date)

Notez que ce n'est que dans la section intitulée Local branches configured for 'git pull':

Pourquoi?

318
gogogadgetinternet

Je ne vous en veux pas d'être frustré à ce sujet. La meilleure façon de regarder est la suivante. Il existe potentiellement trois versions de chaque branche distante:

  1. La branche réelle sur le référentiel distant
    (p. ex., prise en pension distante à https://example.com/repo.git , refs/heads/master)
  2. Votre capture instantanée de cette branche localement (stockée sous refs/remotes/...)
    (par exemple, dépôt local, refs/remotes/Origin/master)
  3. Et une branche locale qui pourrait suivre la branche distante
    (par exemple, dépôt local, refs/heads/master)

Commençons par git Prune. Cela supprime les objets qui ne sont plus référencés, cela ne supprime pas les références. Dans votre cas, vous avez une branche locale. Cela signifie qu'il existe une référence nommée random_branch_I_want_deleted qui fait référence à certains objets représentant l'historique de cette branche. Donc, par définition, git Prune ne supprimera pas random_branch_I_want_deleted. Vraiment, git Prune est un moyen de supprimer les données qui se sont accumulées dans Git mais qui ne sont référencées par rien. En général, cela n’affecte pas votre vue des branches.

git remote Prune Origin et git fetch --Prune fonctionnent tous deux sur des références sous refs/remotes/... (nous les désignerons par références à distance). Cela n'affecte pas les branches locales. La version git remote est utile si vous souhaitez uniquement supprimer des références distantes sous une télécommande particulière. Sinon, les deux font exactement la même chose. En bref, git remote Prune et git fetch --Prune agissent sur le numéro 2 ci-dessus. Par exemple, si vous supprimez une branche à l'aide de l'interface graphique Web de git et ne souhaitez plus qu'elle apparaisse dans votre liste de branches locales (git branch -r), il s'agit de la commande à utiliser.

Pour supprimer une branche locale, vous devez utiliser git branch -d (ou -D s'il n'est fusionné nulle part). FWIW, il n’existe pas de commande git pour supprimer automatiquement les branches de suivi locales si une branche distante disparaît.

594
John Szakmeister

git remote Prune et git fetch --Prune font la même chose: supprimer les références des branches qui n'existent pas dans la télécommande, comme vous l'avez dit. La deuxième commande se connecte à la télécommande et récupère ses branches actuelles avant l'élagage.

Cependant, il ne touche pas les branches locales que vous avez extraites, vous pouvez simplement les supprimer avec

git branch -d  random_branch_I_want_deleted

Remplacez -d par -D si la branche n'est pas fusionnée ailleurs

git Prune fait quelque chose de différent, il purge les objets inaccessibles, ces commits qui ne sont accessibles dans aucune branche ni étiquette, et ne sont donc plus nécessaires.

51
CharlesB

Notez que la différence entre git remote --Prune et git fetch --Prune est corrigée, avec commit 10a6cc8 , par Tom Miller (tmiller) (pour git 1.9/2.0, Q1 2014):

Lorsque nous avons une branche de suivi à distance nommée "frotz/nitfol" à partir d'une extraction précédente et que l'amont a maintenant une branche nommée "** frotz "**, fetch ne parviendrait pas à supprimer" frotz/nitfol "avec un" git fetch --Prune "de l'amont.
git demanderait à l'utilisateur d'utiliser "git remote Prune" pour résoudre le problème.

Donc: quand un dépôt en amont a une branche ("frotz") avec le même nom qu'un hiérarchie de branche ("frotz/xxx", un possible convention de dénomination de branche ), git remote --Prune réussissait (en nettoyant la télécommande suivi de branche depuis votre référentiel), mais git fetch --Prune échouait.

Plus maintenant:

Changez la façon dont "fetch --Prune" fonctionne en déplaçant l'opération d'élagage avant l'opération d'extraction.
Ainsi, au lieu d’avertir l’utilisateur d’un conflit, il le corrige automatiquement.

13
VonC

Dans le cas où quelqu'un serait intéressé. Voici un script Shell rapide qui supprimera toutes les branches locales qui ne sont pas suivies à distance. Un mot d'avertissement: cela supprimera toute branche qui n'est pas dépistée à distance, qu'elle ait été fusionnée ou non.

Si vous voyez un problème avec ceci, faites-le-moi savoir et je le corrigerai (etc. etc.)

Enregistrez-le dans un fichier nommé git-rm-ntb (appelez-le comme bon vous semble) sur PATH et exécutez-le:

git-rm-ntb <remote1:optional> <remote2:optional> ...

clean()
{
  REMOTES="$@";
  if [ -z "$REMOTES" ]; then
    REMOTES=$(git remote);
  fi
  REMOTES=$(echo "$REMOTES" | xargs -n1 echo)
  RBRANCHES=()
  while read REMOTE; do
    CURRBRANCHES=($(git ls-remote $REMOTE | awk '{print $2}' | grep 'refs/heads/' | sed 's:refs/heads/::'))
    RBRANCHES=("${CURRBRANCHES[@]}" "${RBRANCHES[@]}")
  done < <(echo "$REMOTES" )
  [[ $RBRANCHES ]] || exit
  LBRANCHES=($(git branch | sed 's:\*::' | awk '{print $1}'))
  for i in "${LBRANCHES[@]}"; do
    skip=
    for j in "${RBRANCHES[@]}"; do
      [[ $i == $j ]] && { skip=1; echo -e "\033[32m Keeping $i \033[0m"; break; }
    done
    [[ -n $skip ]] || { echo -e "\033[31m $(git branch -D $i) \033[0m"; }
  done
}

clean $@
12
D.Mill