web-dev-qa-db-fra.com

Exécution d'une branche de filtre sur une plage de commits

git filter-branch --env-filter '
export GIT_AUTHOR_EMAIL="[email protected]"
export GIT_AUTHOR_NAME="foo"' -- commita..commitb

Résultats en Which ref do you want to rewrite?

Donc, il semble que filter-branch ne vous permet pas de utiliser la notation de distance utilisez une plage entre deux références arbitraires.

Quel est le moyen le plus simple d’exécuter un filtre sur une plage de validations consécutives (quelque part dans l’historique d’une branche) si cette approche n’est pas possible?.

38
Acorn

La solution la plus propre que j'ai trouvée consistait à:

  1. Créez une branche temporaire à refb.
  2. Appliquez le filtre de branche sur refa..temp.
  3. Rebassez-vous sur la branche temporaire et supprimez-la.

c'est à dire.

git branch temp refb

git filter-branch --env-filter '
export GIT_AUTHOR_EMAIL="[email protected]"' refa..temp

git rebase temp
git branch --delete temp
23
Acorn

Vous ne pouvez pas appliquer la branche de filtre au milieu de l'historique, comme le dit @kan. Vous devez postuler depuis votre engagement connu jusqu'à la fin de l'historique

git filter-branch --env-filter '...' SHA1..HEAD

Filter-branch peut vérifier l'auteur ou les autres informations du commit, choisir de modifier ou non le commit, il existe donc des moyens d'accomplir ce que vous voulez, voir http://git-scm.com/book/ch6-4 .html , recherchez "Modification des adresses électroniques dans le monde"

Rappelez-vous: si vous avez poussé les commits vers un référentiel public, vous ne devriez pas utiliser filter-branch

24
Sanção

git filter-branch accepte accepte la notation d'intervalle, mais la fin de l'intervalle doit être une référence et non l'ID d'un commit.

git checkout -b tofilter commitb
git filter-branch .... commita..tofilter

Si donné ne fait que valider, il ne saurait pas quelle référence mettre à jour avec la branche filtrée.

10
qqx

Vous pouvez filtrer les commandes dans une instruction if qui vérifie cette plage. Vous pouvez vérifier si un commit est dans une plage donnée avec cette commande:

git rev-list start..end | grep **fullsha**

Le commit en cours sera stocké dans $GIT_COMMIT dans votre filtre. Donc, votre filtre devient:

git filter-branch --env-filter '
  if git rev-list commita..commitb | grep $GIT_COMMIT; then
    export GIT_AUTHOR_EMAIL="[email protected]"
    export GIT_AUTHOR_NAME="foo"
  fi' -- ^commita --all

Si vous souhaitez uniquement réécrire votre branche actuelle, remplacez --all par HEAD

6
Chronial

Je le fais de cette façon.

Supposons que vous souhaitiez filtrer le contenu d'une branche appelée branche-vous-êtes-filtre.

Supposons qu'il existe un ancêtre engagé dans cette branche, avec une référence appelée ref-for-commit-to-stop-at.

git filter-branch --commit-filter 'YOUR_FILTER_COMMANDS' branch-you-are-filtering...ref-for-commit-to-stop-at

Après exécution, la validation de ref-for-commit-to-stop-at ne sera pas modifiée. Tous les commits filtrés\modifiés dans la branche que vous filtrez seront basés sur ref-for-commit-to-stop-at.

Que vous utilisiez ou non --commit-filter ou quelque chose d'autre dépend de vous.

4
Mark F Guerra

Vous ne pouvez pas simplement annuler des commits au milieu d'une histoire, car sha1 d'un commit dépend de celui d'un parent. Donc, le git ne sait pas où vous voulez pointer votre référence HEAD après la filtration. Donc, vous devriez tout réécrire à la tête.

Exemple:

A---B---C---D---E---F   master
            \
             \--G---H   branch

si vous voulez filtrer les commits B et C, vous devriez aussi filtrer tous les commits après: D, E, F, G, H . C'est pourquoi git vous dit d'utiliser un ref juste pas fini avec une tête détachée.

Après avoir modifié les commits B et C, l’arrêt aura l'aspect suivant:

A---B---C---D---E---F   master
\           \
 \           \--G---H   branch
  \-B'--C'      (HEAD or a temporary TAG?..)      

Ainsi, les variables master et branch ne seront pas modifiées. Je ne pense pas que c’est ce que vous voulez ... Cela signifie que vous devez annuler tous les commits. L'histoire sera alors:

A---B---C---D---E---F   (loose end, will be garbage collected one day)
\           \
 \           \--G---H   (loose end, will be garbage collected one day)
  \-B'--C'--D'--E'--F'  master
            \
             \--G'--H'  branch
2
kan

Utilisez le paramètre --setup de filter-branch et une alimentation Shell:

git filter-branch --setup '
for id in `git rev-list commitA..commitB`; do
         eval filterfor_$id=rewrite
done
rewrite() {
        GIT_AUTHOR_NAME="Frederick. O. Oosball"
        [email protected]
}
' --env-filter 'eval \$filterfor_$GIT_COMMIT'
0
jthill

La solution de @Acron me semble fausse. Je suggérerais ensuite de changer entre refa et refb, y compris les deux hashs:

  1. git tag master.bak
  2. git reset --hard refa
  3. git filter-branch --env-filter ' export GIT_AUTHOR_EMAIL="[email protected]"' refa^..master
  4. git cherry-pick refb..master.bak
  5. git tag -d master.bak
0
niels