Comment puis-je dire à git de toujours sélectionner ma version locale pour les fusions conflictuelles sur un fichier spécifique?

dit que je collabore avec quelqu'un via un dépôt git, et il y a un fichier particulier sur lequel je ne veux jamais accepter de modifications externes.

y a-t-il un moyen pour moi de mettre en place mon repo local pour ne pas me plaindre d'une fusion conflictuelle à chaque fois que je tire? J'aimerais toujours choisir ma version locale lors de la fusion de ce fichier.

87
demandé sur Micah 2009-05-30 04:29:53
la source

2 ответов

sur l'instance spécifique d'un fichier de configuration, je serais d'accord avec réponse de Ron :

une configuration doit être " privée "de votre espace de travail (donc" ignorée", comme dans "déclarée dans un .gitignore fichier").

Vous pouvez avoir un fichier de configuration template avec valeurs tokenisées , et un script transformant ce fichier config.template en un fichier de configuration privé (et ignoré).


Toutefois, cette remarque spécifique ne répond pas à une question plus générale, c'est-à-dire à votre question(!):

Comment dire à git de toujours sélectionner ma version locale pour les fusions conflictuelles sur un fichier spécifique ? (pour tout fichier ou groupe de fichiers)

ce type de fusion est une" fusion de copie", dans laquelle vous copierez toujours "notre" ou "leur" version d'un fichier en cas de conflit.

(comme Brian Vandenberg notes dans les commentaires , ' ours ' et theirs " sont ici utilisés pour une fusion .

Ils sont inversé pour un rebase : voir " Why is the meaning of “ours” and “theirs” reversed with git-svn ", qui utilise un rebase, " git rebase , suivi de "local" et "éloigné " ")

pour "un fichier "(un fichier en général, ne parlant pas d'un fichier" config", car c'est un mauvais exemple), vous obtiendriez cela avec un script personnalisé appelé par des fusions.

Git appellera ce script parce que vous aurez défini une gitattributes valeur , qui définit une Fusion personnalisée le pilote .

le "pilote de fusion personnalisé" est, dans ce cas, un script très simple qui maintiendra essentiellement inchangée la version actuelle, vous permettant ainsi de toujours sélectionner votre version locale.


testons que dans un scénario simple, avec un msysgit 1.6.3 sur Windows, dans une simple session DOS:

cd f:\prog\git\test
mkdir copyMerge\dirWithConflicts
mkdir copyMerge\dirWithCopyMerge
cd copyMerge
git init
Initialized empty Git repository in F:/prog/git/test/copyMerge/.git/

maintenant, faisons deux fichiers, qui auront tous les deux des conflits, mais qui seront regroupées différemment.

echo a > dirWithConflicts\a.txt
echo b > dirWithCopyMerge\b.txt
git add -A
git commit -m "first commit with 2 directories and 2 files"
[master (root-commit) 0adaf8e] first commit with 2 directories and 2 files

Nous allons introduire un "conflit" dans le contenu de ces deux fichiers dans deux différentes branches git:

git checkout -b myBranch
Switched to a new branch 'myBranch'
echo myLineForA >> dirWithConflicts\a.txt
echo myLineForB >> dirWithCopyMerge\b.txt
git add -A
git commit -m "add modification in myBranch"
[myBranch 97eac61] add modification in myBranch

git checkout master
Switched to branch 'master'
git checkout -b hisBranch
Switched to a new branch 'hisBranch'
echo hisLineForA >> dirWithConflicts\a.txt
echo hisLineForB >> dirWithCopyMerge\b.txt
git add -A
git commit -m "add modification in hisBranch"
[hisBranch 658c31c] add modification in hisBranch

maintenant, essayons de fusionner "hisBranch" sur "myBranch", avec:

  • manuel de résolution de conflits fusionne
  • sauf pour dirWithCopyMerge\b.txt où j'ai toujours envie de garder mon version de b.txt .

"puisque la fusion se produit dans MyBranch ", nous allons revenir à elle, et ajouter les directives " gitattributes " qui personnaliseront le comportement de fusion.

git checkout myBranch
Switched to branch 'myBranch'
echo b.txt merge=keepMine > dirWithCopyMerge\.gitattributes
git config merge.keepMine.name "always keep mine during merge"
git config merge.keepMine.driver "keepMine.sh %O %A %B"
git add -A
git commit -m "prepare myBranch with .gitattributes merge strategy"
[myBranch ec202aa] prepare myBranch with .gitattributes merge strategy

nous avons un fichier .gitattributes défini dans le répertoire dirWithCopyMerge (défini seulement dans la branche où la fusion aura lieu: myBranch ), et nous avons un fichier .git\config qui contient maintenant un pilote de fusion.

[merge "keepMine"]
        name = always keep mine during merge
        driver = keepMine.sh %O %A %B

si vous ne définissez pas encore keepMine.sh, et de lancer la fusion de toute façon, voici ce que vous obtenez.

git merge hisBranch
sh: keepMine.sh: command not found
fatal: Failed to execute internal merge
git st
# On branch myBranch
# Changed but not updated:
#   (use "git add <file>..." to update what will be committed)
#   (use "git checkout -- <file>..." to discard changes in working directory)
#
#       modified:   dirWithConflicts/a.txt
#
no changes added to commit (use "git add" and/or "git commit -a")

type dirWithConflicts\a.txt
a
<<<<<<< HEAD:dirWithConflicts/a.txt
myLineForA
=======
hisLineForA
>>>>>>> hisBranch:dirWithConflicts/a.txt

C'est très bien:

  • a.txt est prêt à être fusionné et a un conflit en elle
  • b.txt est encore intact, puisque le pilote de fusion est censé s'en occuper (en raison de la directive dans le fichier .gitattributes dans son répertoire).

définissez un keepMine.sh n'importe où dans votre %PATH% (ou $PATH pour notre ami Unix. Je fais les deux, bien sûr: j'ai une session Ubuntu dans VirtualBox session)

Comme , a commenté par lrkwz , et décrit dans le " Fusionner les Stratégies de " de la section Personnalisation de Git - Git Attributs , vous pouvez remplacer le script shell avec le shell la commande true .

git config merge.keepMine.driver true

Mais dans le cas général, vous pouvez définir un fichier de script:

keepMine.sh

# I want to keep MY version when there is a conflict
# Nothing to do: %A (the second parameter) already contains my version
# Just indicate the merge has been successfully "resolved" with the exit status
exit 0

(qui était un pilote de fusion simple;) (encore plus simple dans ce cas, utilisez true )

(Si vous souhaitez conserver l'autre version, il suffit d'ajouter avant la ligne exit 0 :

cp -f .

C'est tout. La fusion conducteur souvenirs conservez la version à venir de l'autre branche, en remplaçant toute modification locale)

maintenant, réessayons la fusion depuis le début:

git reset --hard
HEAD is now at ec202aa prepare myBranch with .gitattributes merge strategy

git merge hisBranch
Auto-merging dirWithConflicts/a.txt
CONFLICT (content): Merge conflict in dirWithConflicts/a.txt
Auto-merging dirWithCopyMerge/b.txt
Automatic merge failed; fix conflicts and then commit the result.

la fusion échoue... uniquement pour a.txt .

Modifier a.txt et quittez la ligne de 'hisBranch', puis:

git add -A
git commit -m "resolve a.txt by accepting hisBranch version"
[myBranch 77bc81f] resolve a.txt by accepting hisBranch version

vérifions que b.txt a été préservé lors de cette fusion

type dirWithCopyMerge\b.txt
b
myLineForB

Le dernier commit représentent le plein fusionner:

git show -v 77bc81f5e
commit 77bc81f5ed585f90fc1ca5e2e1ddef24a6913a1d
Merge: ec202aa 658c31c
git merge hisBranch
Already up-to-date.

(la ligne commençant par la fusion prouve que)


Considérez que vous pouvez définir, de combiner et/ou remplacer fusion pilote, comme Git:

  • examiner <dir>/.gitattributes (qui est dans le même répertoire que le chemin en question): prévaudra sur l'autre .gitattributes dans les répertoires
  • ensuite, il examine .gitattributes (qui est dans le répertoire parent), ne définira les directives que si elles ne sont pas déjà définies
  • enfin, il examine $GIT_DIR/info/attributes . Ce fichier est utilisé pour remplacer les paramètres de l'arborescence. Il écrasera les directives <dir>/.gitattributes .

par" combinaison", j'entends le pilote de fusion multiple" aggregate".

Nick Green tente, les commentaires , pour réellement combiner des pilotes de fusion: voir " fusionner des pom's via Python git driver ".

Cependant , comme mentionné dans son autre question , il ne fonctionne qu'en cas de conflits (modification simultanée dans les deux branches).

127
répondu VonC 2017-11-20 12:53:03
la source

nous avons plusieurs fichiers de configuration que nous ne voulons jamais effacer. Cependant. gitignore et .gitattributes n'a pas fonctionné dans notre situation. Notre solution était de stocker les fichiers de configuration dans une branche de configs. Puis, permettez aux fichiers d'être modifiés pendant la fusion git, mais immédiatement après la fusion utilisez la branche "git checkout -- ."pour copier nos fichiers de configuration de la branche configs après chaque Fusion. détail stackoverflow réponse ici

0
répondu HamletHub 2017-05-23 15:03:06
la source

Autres questions sur git git-merge