web-dev-qa-db-fra.com

Outil simple pour "accepter les leurs" ou "accepter les miens" sur tout un fichier en utilisant git

Je ne veux pas d'outil de fusion visuelle, et je ne veux pas non plus devoir vier le fichier en conflit et choisir manuellement entre HEAD (le mien) et le changement importé (le leur). La plupart du temps, je veux tous leurs changements ou tous les miens. Généralement, c'est parce que mon changement est arrivé en amont et qu'il me revient par traction, mais peut être légèrement modifié à divers endroits.

Existe-t-il un outil en ligne de commande permettant de supprimer les marqueurs de conflit et de choisir toutes les méthodes en fonction de mon choix? Ou un ensemble de commandes git que je peux me nommer pour faire chacune.

# accept mine
alias am="some_sequence;of;commands"
alias at="some_other_sequence;of;commands"

Faire cela est plutôt ennuyant. Pour 'accepter le mien' j'ai essayé:

randy@Sabotage ~/linus $ git merge test-branch
Auto-merging Makefile
CONFLICT (content): Merge conflict in Makefile
Automatic merge failed; fix conflicts and then commit the result.

randy@Sabotage ~/linus $ git checkout Makefile 
error: path 'Makefile' is unmerged

andy@Sabotage ~/linus $ git reset --hard HEAD Makefile 
fatal: Cannot do hard reset with paths.

Comment suis-je supposé me débarrasser de ces marqueurs de changement?

Je peux faire:

git reset HEAD Makefile; rm Makefile; git checkout Makefile

Mais cela semble plutôt rond, il doit y avoir un meilleur moyen. Et à ce stade, je ne sais pas si git pense même que la fusion a eu lieu, alors je ne pense pas que cela fonctionne nécessairement.

Aller de l’autre côté, faire "accepter les leurs" est également désordonné. La seule façon de le comprendre est de faire:

git show test-branch:Makefile > Makefile; git add Makefile;

Cela me donne également un message de commit gâché, qui contient Conflicts: Makefile dedans deux fois.

Quelqu'un peut-il s'il vous plaît indiquer comment faire les deux actions ci-dessus d'une manière plus simple? Merci

365
nosatalian

La solution est très simple. git checkout <filename> essaie d'extraire le fichier de l'index, et échoue donc lors de la fusion.

Ce que vous devez faire est (c.-à-d. Commander a commit):

Pour commander votre propre version vous pouvez utiliser un de:

git checkout HEAD -- <filename>

ou

git checkout --ours -- <filename>

ou

git show :2:<filename> > <filename> # (stage 2 is ours)

Pour acheter l'autre version vous pouvez utiliser l'un de:

git checkout test-branch -- <filename>

ou

git checkout --theirs -- <filename>

ou

git show :3:<filename> > <filename> # (stage 3 is theirs)

Vous devez également exécuter 'add' pour le marquer comme résolu:

git add <filename>
561
Jakub Narębski

Essaye ça:

Pour accepter leurs modifications: git merge --strategy-option theirs

Pour accepter le vôtre: git merge --strategy-option ours

73
Siva Mandadi

Sur la base de la réponse de Jakub, vous pouvez configurer les alias git suivants pour plus de commodité:

accept-ours = "!f() { git checkout --ours -- \"${@:-.}\"; git add -u \"${@:-.}\"; }; f"
accept-theirs = "!f() { git checkout --theirs -- \"${@:-.}\"; git add -u \"${@:-.}\"; }; f"

Ils prennent éventuellement un ou plusieurs chemins de fichiers à résoudre et résolvent par défaut à tout résoudre dans le répertoire en cours si aucun n’est indiqué.

Ajoutez-les à la section [alias] de votre ~/.gitconfig ou exécutez

git config --global alias.accept-ours '!f() { git checkout --ours -- "${@:-.}"; git add -u "${@:-.}"; }; f'
git config --global alias.accept-theirs '!f() { git checkout --theirs -- "${@:-.}"; git add -u "${@:-.}"; }; f'
50
kynan

D'après la réponse de kynan, voici les mêmes alias, modifiés pour pouvoir gérer les espaces et les tirets initiaux dans les noms de fichiers:

accept-ours = "!f() { [ -z \"$@\" ] && set - '.'; git checkout --ours -- \"$@\"; git add -u -- \"$@\"; }; f"
accept-theirs = "!f() { [ -z \"$@\" ] && set - '.'; git checkout --theirs -- \"$@\"; git add -u -- \"$@\"; }; f"
17
Dar

La situation idéale pour résoudre les conflits est lorsque vous savez à l'avance quelle méthode vous souhaitez résoudre et que vous pouvez passer les options de stratégie de fusion récursive _-Xours_ ou _-Xtheirs_. En dehors de cela, je peux voir trois scénarios:

  1. Vous souhaitez conserver une seule version du fichier (elle ne devrait probablement être utilisée que sur des fichiers binaires non fusionnables, car sinon des fichiers en conflit ou non risquent de ne plus être synchronisés entre eux).
  2. Vous voulez simplement décider de tous les conflits dans une direction particulière.
  3. Vous devez résoudre certains conflits manuellement, puis résoudre tout le reste dans une direction donnée.

Pour résoudre ces trois scénarios, vous pouvez ajouter les lignes suivantes à votre fichier _.gitconfig_ (ou équivalent):

_[merge]
  conflictstyle = diff3
[mergetool.getours]
  cmd = git-checkout --ours ${MERGED}
  trustExitCode = true
[mergetool.mergeours]
  cmd = git-merge-file --ours ${LOCAL} ${BASE} ${REMOTE} -p > ${MERGED}
  trustExitCode = true
[mergetool.keepours]
  cmd = sed -I '' -e '/^<<<<<<</d' -e '/^|||||||/,/^>>>>>>>/d' ${MERGED}
  trustExitCode = true
[mergetool.gettheirs]
  cmd = git-checkout --theirs ${MERGED}
  trustExitCode = true
[mergetool.mergetheirs]
  cmd = git-merge-file --theirs ${LOCAL} ${BASE} ${REMOTE} -p > ${MERGED}
  trustExitCode = true
[mergetool.keeptheirs]
  cmd = sed -I '' -e '/^<<<<<<</,/^=======/d' -e '/^>>>>>>>/d' ${MERGED}
  trustExitCode = true
_

L'outil get(ours|theirs) ne conserve que la version respective du fichier et supprime toutes les modifications de l'autre version (de sorte qu'aucune fusion ne se produit).

L'outil merge(ours|theirs) répète la fusion à trois voies à partir des versions locale, de base et distante du fichier, en choisissant de résoudre les conflits dans la direction indiquée. Cela comporte certaines réserves, notamment: il ignore les options diff qui ont été transmises à la commande de fusion (telles que la gestion des algorithmes et des espaces); fusionne proprement des fichiers d'origine (de sorte que toute modification manuelle du fichier est supprimée, ce qui peut être bon ou mauvais); et a l’avantage de ne pas pouvoir être confondu avec les marqueurs diff supposés être dans le fichier.

L'outil keep(ours|theirs) édite simplement les marqueurs diff et les sections fermées, en les détectant par une expression régulière. Cela présente l'avantage de préserver les options de diff de la commande de fusion et de vous permettre de résoudre certains conflits à la main, puis de résoudre automatiquement le reste. L'inconvénient est que s'il y a d'autres marqueurs de conflit dans le fichier, cela pourrait être confus.

Ceux-ci sont tous utilisés en exécutant git mergetool -t (get|merge|keep)(ours|theirs) [<filename>] où, si _<filename>_ n'est pas fourni, il traite tous les fichiers en conflit.

En règle générale, à supposer que vous sachiez qu'il n'y a pas de marqueur diff pour confondre l'expression régulière, les variantes _keep*_ de la commande sont les plus puissantes. Si vous laissez l'option _mergetool.keepBackup_ non définie ou true, après la fusion, vous pouvez comparer le fichier _*.orig_ au résultat de la fusion afin de vérifier sa pertinence. Par exemple, je lance ce qui suit après le mergetool juste pour vérifier les modifications avant de valider:

_for f in `find . -name '*.orig'`; do vimdiff $f ${f%.orig}; done
_

Note: Si le _merge.conflictstyle_ n'est pas _diff3_, alors le modèle _/^|||||||/_ dans la règle sed doit être _/^=======/_.

1
Parakleta