2010-06-24 16 views
12

J'ai déjà fait une recherche approfondie, lu beaucoup de questions et de solutions SO et essayé de différentes façons, mais j'ai été incapable de faire ce que je veux, ce qui est assez simple. J'ai la branche principale, où réside tout le code principal, et la branche de conception, où la conception de l'application rails est construite par l'équipe de conception. Ils ont ajouté un dossier appelé "photoshop" au dossier public pour garder leurs sources pour les images également sous contrôle de version. Mais je ne veux pas que ce dossier soit copié lors de la fusion à la branche master car, bon, ce n'est pas nécessaire.Comment configurer un pilote git pour ignorer un dossier lors de la fusion

Apparemment, la façon de faire cela est à travers un pilote de fusion. Alors, je l'ai créé le "ignorer" pilote:

[merge "ignore"] 
name = always ignore during merge 
driver = ignore.sh %0 %A %B 

et a créé le fichier sur mon ignore.sh $ PATH:

exit 0 

J'ai créé fichier les .gitattributes à l'intérieur du public /, parce que le dossier Photoshop doit être ignorée en tout et il va apparaître sous public /:

photoshop merge=ignore 
photoshop/ merge=ignore 
photoshop/* merge=ignore 
photoshop/**/* merge=ignore 

Comme vous pouvez le voir, je l'ai essayé plusieurs modèles différents pour ignorer tout le dossier, mais il ne fonctionne pas. Je crois que c'est parce qu'il n'y a pas de dossier sur la branche master, donc il n'y a pas de conflit et donc git n'utilise pas le driver ignore. Y at-il un moyen d'y parvenir sans avoir à créer un dossier public/photoshop sur le master?

Merci!

+0

duplication possible de [Comment puis-je dire à git de toujours sélectionner ma version locale pour les fusions en conflit sur un fichier spécifique?] (Http://stackoverflow.com/questions/928646/how-do-i-tell-git- to-always-select-ma-version-locale-pour-conflit-fusionne-sur-as) – givanse

Répondre

16

Comme suggéré par mon autre réponse, voici la version généralisée et industrielle de la solution.

(oui, je me suis ennuyé à la maison et avait rien d'autre de mieux à faire: P)

Ce script ajoutera un nouveau détaché commit en fonction de votre branche de conception locale, il n'affectera ni le référentiel de conception ni votre branche de conception. Le commit aura tous les fichiers désirés supprimés. Ensuite, il effectue la fusion.

Pour ceux qui sont trop paresseux pour lire le code complet, le « noyau » de ces étapes peut être simplifiée comme:

original=$(gitbranch HEAD) # current branch name, or sha1 if not in a branch 
branchsha=$(gitsha "$branch") # sha1 of a ref, to force detached commit 

git checkout "$branchsha" && 
git rm -rf "${files[@]}" && 
git commit -m "$msgcommit" && 
newsha=$(gitsha HEAD)  && 
git checkout "$original" && 
git merge -m "$msgmerge" "${mergeopts[@]}" "$newsha" 

Et voici le script complet:

(un peu modifié pour faire face à la faiblesse et la coloration de syntaxe limitée de SO, il est donc préférable d'obtenir la source vierge à partir du lien ci-dessous)

git-strip-merge

#!/bin/bash 
# 
# git-strip-merge - a git-merge that delete files on branch before merging 
# 
# Copyright (C) 2012 Rodrigo Silva (MestreLion) <[email protected]> 
# 
# This program is free software: you can redistribute it and/or modify 
# it under the terms of the GNU General Public License as published by 
# the Free Software Foundation, either version 3 of the License, or 
# (at your option) any later version. 
# 
# This program is distributed in the hope that it will be useful, 
# but WITHOUT ANY WARRANTY; without even the implied warranty of 
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 
# GNU General Public License for more details. 
# 
# You should have received a copy of the GNU General Public License 
# along with this program. If not see <http://www.gnu.org/licenses/gpl.html> 
# 
# Answer for "How to setup a git driver to ignore a folder on merge?" 
# See http://stackoverflow.com/questions/3111515 

#Defaults: 
msgcommit="remove files from '<branch>' before merge" 
msgmerge="Merge stripped branch '<branch>'" 
verbose=0 
quiet=(--quiet) 

usage() { 
    cat <<- USAGE 
    Usage: $myname [git-merge options] [-M <commitmsg>] <branch> FILE... 
    USAGE 
    if [[ "$1" ]] ; then 
     cat >&2 <<- USAGE 
     Try '$myname --help' for more information. 
     USAGE 
     exit 1 
    fi 
    cat <<-USAGE 

    "git-merge that delete files on "foreign" <branch> before merging 

    Useful for ignoring a folder in <branch> before merging it with 
    current branch. Works by deleting FILE(S) in a detached commit based 
    on <branch>, and then performing the merge of this new commit in the 
    current branch. Note that <branch> is not changed by this procedure. 
    Also note that <branch> may actually be any reference, like a tag, 
    or a remote branch, or even a commit SHA. 

    For more information, see <http://stackoverflow.com/questions/3111515> 

    Options: 
     -h, --help 
     show this page. 

     -v, --verbose 
     do not use -q to supress normal output of internal steps from git 
     checkout, rm, commit. By default, only git merge output is shown. 
     Errors, however, are never supressed 

     -M <message>, --msgcommit=<message> 
     message for the removal commit in <branch>. Not to be confused 
     with the message of the merge commit, which is set by -m. Default 
     message is: "$msgcommit" 

     -m <message>, --message=<message> 
     message for the merge commit. Since we are not merging <branch> 
     directly, but rather a detached commit based on it, we forge a 
     message similar to git's default for a branch merge. Otherwise 
     git would use in message the full and ugly SHA1 of our commit. 
     Default message is: "$msgmerge" 

     For both commit messages, the token "<branch>" is replaced for the 
     actual <branch> name. 

    Additional options are passed unchecked to git merge. 

    All options must precede <branch> and FILE(s), except -h and --help 
    that may appear anywhere on the command line. 

    Example: 
     $myname design "photoshop/*" 

    Copyright (C) 2012 Rodrigo Silva (MestreLion) <[email protected]> 
    License: GPLv3 or later. See <http://www.gnu.org/licenses/gpl.html>" 
    USAGE 
    exit 0 
} 

# Helper functions 
myname="${0##*/}" 
argerr() { printf "%s: %s\n" "${0##*/}" "${1:-error}" >&2 ; usage 1 ; } 
invalid() { argerr "invalid option: $1" ; } 
missing() { argerr "missing ${2:+$2 }operand${1:+ from $1}." ; } 

# Option handling 
files=() 
mergeopts=() 
for arg in "[email protected]"; do case "$arg" in -h|--help) usage ;; esac; done 
while (($#)); do 
    case "$1" in 
    -v|--verbose ) verbose=1   ;; 
    -M   ) shift ; msgcommit=$1 ;; 
    -m   ) shift ; msgmerge=$1 ;; 
    --msgcommit=*) msgcommit=${1#*=} ;; 
    --message=* ) msgmerge=${1#*=}  ;; 
    -*   ) mergeopts+=("$1") ;; 
    *   ) branch="$1" 
        shift ; break  ;; 
    esac 
    shift 
done 
files+=("[email protected]") 

# Argument handling 

msgcommit=${msgcommit//<branch>/$branch} 
msgmerge=${msgmerge//<branch>/$branch} 

[[ "$msgcommit" ]] || missing "msgcommit" "MSG" 
[[ "$branch" ]] || missing ""   "<branch>" 
((${#files[@]})) || missing ""   "FILE" 

((verbose)) && quiet=() 

# Here the fun begins... 
gitsha() { git rev-parse "$1" ; } 
gitbranch() { 
    git symbolic-ref "$1" 2> /dev/null | sed 's/refs\/heads\///' || 
    gitsha "$1" 
} 

original=$(gitbranch HEAD) 
branchsha=$(gitsha "$branch") 

trap 'git checkout --quiet "$original"' EXIT 

git checkout "$branchsha" "${quiet[@]}" && 
git rm -rf "${files[@]}" "${quiet[@]}" && 
git commit -m "$msgcommit" "${quiet[@]}" && 
newsha=$(gitsha HEAD)     && 
git checkout "$original" "${quiet[@]}" && 
git merge -m "$msgmerge" "${mergeopts[@]}" "$newsha" 

Profitez-en!

Une image vaut plus que mille mots ...

Avant fusion:

enter image description here

Après fusion:

enter image description here

Notez que la pointe de la branche "design" n'a pas été affecté du tout, étant même une branche locale, grâce à le tour de commit détaché. Autre que cela, les deux commits (la suppression et la fusion) sont des commits réguliers, avec des messages de validation appropriés et les parents. Et "master" branche est propre de tous les fichiers indésirables.

+0

Approche intéressante. +1 Je vais devoir le tester. En fusionnant un HEAD détaché, cela signifierait que vous ne verrez pas vraiment (dans un gitk) toutes ces fusions, n'est-ce pas? Plus ce qui arrive quand vous répétez cette fusion plusieurs fois? Git se rappellera-t-il de ce qui a déjà été fusionné (surtout quand ces HEAD détachés ont été purgés?) – VonC

+1

@VonC: Ok, peut-être que "détaché commit" était un peu trompeur: c'est un commit normal, la seule différence est qu'il ne bouge pas '' conseil. – MestreLion

+0

Et oui, puisque c'est un commit régulier, et une fusion régulière, vous verrez les deux, et ils ne seront jamais élagués/purgés. La chose «détachée» était juste une astuce pour laisser la pointe locale «» sans être dérangée. – MestreLion

0

Avez-vous essayé d'ajouter un fichier .gitignore dans votre branche master pour ignorer le contenu du répertoire photopshop?
Ensuite, une fusion de la conception à master ne doit pas ajouter ce nouveau répertoire dans master.

Si cela fonctionne, vous avez toujours besoin d'un pilote de fusion, mais cette fois pour gérer le contenu du fichier .gitignore.

+0

Ou vous pouvez simplement mettre .gitignore dans votre $ HOME (ie, en dehors de votre répertoire de rails) et en profiter :) – rmk

+0

@rmk: très vrai, mais il pourrait être intéressant d'avoir ce paramètre (en ignorant ''photoshop'' dans la branche '' master' ') poussé de repo à repo. – VonC

+0

Il n'accepte pas la fusion: erreur: Le fichier de l'arborescence de travail non suivi 'public/photoshop/photoshop/bar.psd' serait écrasé par fusion. Abandon –

10

Pas une réponse en soi, mais quelques notes sur .gitignore: il ne sera pas vous aide dans votre scénario.

.gitignore est d'ignorer les fichiers du arbre de travail être ajouté-index (zone de stockage intermédiaire). Donc, il n'est efficace que lorsque vous utilisez git add <files>, et il peut toujours être remplacé en utilisant git add --force <files>. Il est destiné comme une commodité pour empêcher les fichiers indésirables soient ajoutés, mais il n'a aucun effet sur les fichiers à l'intérieur du dépôt

Dans votre scénario, .gitignore n'est pas nécessaire, puisque vous n'avez pas locale ./photoshop, donc vous n'aurez jamais de fichiers photoshop à ajouter à votre branche principale. Cependant, cela ne ferait pas de mal d'en créer un juste au cas où. Et pour l'équipe de conception .gitignore n'est pas la bienvenue, car ils veulent fichiers photoshop à ajouter à leur branche.Par conséquent, puisque les transactions de fusion avec ont été validées, les fichiers et ./photoshop sont déjà dans le référentiel, votre approche d'utilisation d'un pilote de fusion était correcte.

Le problème est ... par défaut un pilote de fusion ne se déclenche en cas de entre en conflit. Et, puisque la branche master n'a aucun dossier ou fichiers ./photoshop, il n'y a aucun conflit, ils sont proprement fusionnés. Donc, votre pilote de fusion n'a également eu aucun effet, quels que soient les chemins que vous avez parcourus (en passant, votre 2e, photoshop/, était correct). Je ne sais pas si git merge peut être configuré pour déclencher un pilote de fusion, même pour des fichiers non conflictuels, mais cela vaut la peine de faire des recherches.

Comme je l'ai déjà dit, ma réponse n'est pas une vraie solution à votre problème. J'espérais juste faire la lumière sur le sujet, en expliquant pourquoi vos tentatives d'utiliser le pilote de fusion et .gitignore ont échoué. Je suggère de lire plus sur (configuration) pilotes de fusion. Les sous-modules méritent également d'être étudiés.

Espérons que cela aide!

MISE À JOUR

Maybe my other answer will help you:

Usage: git-strip-merge [git-merge options] [-M <commitmsg>] <branch> FILE... 

git-strip-merge

Amusez-vous!

+2

+1 pour l'effort et les commentaires. Même si vous vous rendez compte que le PO n'a pas été vu sur SO depuis 18 mois, n'est-ce pas? J'espère que cela peut donner des idées aux autres. – VonC

+2

@VonC: oui, je me rends compte que c'est une question ancienne, et probablement personne ne va lire/se soucier. Mais, encore, SO est un bon site de référence, et d'autres (ou même moi-même) pourraient trébucher sur ce problème à l'avenir, tout comme je l'ai fait maintenant. – MestreLion

+0

Bien joué quand même. Et j'ai * toujours * lu depuis 3 ans et demi. Et attention. – VonC