Quelle est la meilleure façon d'annuler une fusion Git qui efface les fichiers du dépôt?

13

Imaginez donc ce qui se passe (et que nous utilisons tous SourceTree):

  1. Nous travaillons tous hors origine / développement.
  2. Je pars en vacances pendant une semaine.
  3. Mon collègue travaille localement depuis plusieurs jours sans fusionner l'origine / le développement dans sa branche de développement locale.
  4. Il essaie de faire un push, on lui dit qu'il doit d'abord fusionner, puis fait un pull.
  5. Il obtient un conflit, empêchant la validation automatique après fusion de continuer.
  6. En supposant que Git est comme SVN, mon collègue supprime les "nouveaux" fichiers dans sa copie de travail, puis valide la fusion - en essuyant ces "nouveaux" fichiers de la tête d'origine / développement.
  7. Une semaine de travail de développement se poursuit en plus de cette révision.
  8. Je reviens de vacances et découvre qu'il manque plusieurs jours de travail.

Nous sommes tous très nouveaux à Git (c'est notre premier projet à l'utiliser), mais ce que j'ai fait pour le réparer était:

  1. Renommez "develop" en "develop_old".
  2. Fusionnez develop_old dans une nouvelle branche "develop_new".
  3. Réinitialisez la branche develop_new au dernier commit avant la mauvaise fusion.
  4. Cherry pick chaque commit depuis lors, un par un, résolvant les conflits à la main.
  5. Poussez develop_old et develop_new jusqu'à l'origine.

À ce stade, develop_new est, j'espère, une "bonne" copie de toutes nos modifications avec les semaines suivantes de travail réappliqué. Je suppose aussi que « Commit inverse » fera des choses bizarres sur une fusion, d' autant plus que la prochaine quelques semaines de travail est basé sur - et depuis cette fusion contient beaucoup de choses que nous ne voulons ainsi que des choses nous ne » t.

J'espère que cela ne se reproduira plus jamais, mais si cela se reproduit, j'aimerais connaître une manière plus facile / meilleure de réparer les choses. Y a-t-il une meilleure façon d'annuler une «mauvaise» fusion, alors que beaucoup de travail a été effectué dans le référentiel basé sur cette fusion?

George
la source
1
Pourriez-vous publier une capture d'écran de l'arbre git (expurgée de manière appropriée) ou la sortie de votre git logformat préféré avec des annotations appropriées sur ce qui s'est passé lors des différents commits? (Je bifferais / annoterais git log --graph --pretty=oneline --abbrev-commitet j'irais de là)
1
Il est trop tard pour vous, mais les tests unitaires auraient compris cela.
nalply
1
@nalply: Pas si la mauvaise fusion a également supprimé les tests unitaires.
Aaronaught
Wow, c'est vraiment de la malchance insidieuse.
2014 à 9h04

Réponses:

6

Si j'ai bien compris, voici votre situation:

    ,-c--c--c--c--M--a--a--X ← develop
o--o--y--y--y--y-´

Après une histoire commune (o), vous vous êtes engagé et avez poussé votre travail (y). Votre collègue (c) a travaillé sur son référentiel local et a effectué une mauvaise fusion (M). Par la suite, il pourrait y avoir des commits supplémentaires (a) au-dessus de M.

git reset --hard develop M^2
git branch coworker M^1

Votre graphique ressemble maintenant exactement avant la mauvaise fusion:

    ,-c--c--c--c ← coworker
o--o--y--y--y--y ← develop

Faites une bonne fusion (G):

git checkout develop
git merge coworker

Résultant en:

    ,-c--c--c--c-、
o--o--y--y--y--y--G ← develop

Transplantez maintenant les commits supplémentaires:

git reset --hard X
git rebase --onto G M develop

Cela donne le résultat final:

    ,-c--c--c--c-、
o--o--y--y--y--y--G--a--a--X ← develop

N'oubliez pas que cela peut entraîner davantage de conflits de fusion. Vous venez également de modifier l'historique, c'est-à-dire que tous vos collègues devraient cloner / réinitialiser / rebaser vers la nouvelle histoire.

PS: bien sûr vous devez remplacer G, Met Xdans vos commandes par l'id de commit correspondant.

michas
la source
Il semble assez évident dans la question que tous ces commits ont déjà été poussés vers un référentiel partagé, donc je ne pense pas que le rebasage soit un bon choix. Il est plus sûr de revenir sur tous les commits récents, puis de sélectionner ceux qui ne sont pas conflictuels, en plus de la bonne fusion.
Aaronaught
C'était la partie avec le clone / reset / rebase. - S'il n'y a que quelques développeurs, leur dire de mettre à jour leurs référentiels peut être une option valide.
michas
1

Il est bon que vous réfléchissiez à la façon de réparer le référentiel, mais si votre collègue n'a supprimé que de nouveaux fichiers et n'a pas écrasé beaucoup de mises à jour, alors une approche beaucoup plus simple serait de simplement restaurer les fichiers qui ont été supprimés.

Je commencerais probablement par essayer de simplement sélectionner (sur la tête actuelle) les commits originaux dans lesquels vous avez ajouté le code qui a maintenant disparu. Si, pour une raison quelconque, cela ne fonctionne pas, vérifiez simplement l'ancienne révision avec les fichiers que vous avez ajoutés et ré-ajoutez-les dans un nouveau commit.

Ce que vous décrivez est en fait un sous-ensemble d'un anti-pattern Git bien connu, dont je ne me souviens pas du nom pour la vie - mais l'essentiel est de faire des "modifications manuelles" pendant une fusion Git (c'est-à-dire des modifications qui ne résolvent en fait aucun conflit de fusion mais qui apportent des changements totalement indépendants) est considéré comme une très mauvaise pratique car ils sont essentiellement masqués par la fusion elle-même et sont facilement ignorés dans les révisions de code ou les sessions de débogage.

Expliquez donc à votre collègue qu'il s'agissait d'un échec épique, mais envisagez de mettre un pansement avant de vous préparer à une intervention chirurgicale majeure.

Aaronaught
la source
Je suis d'accord, si ce sont des fichiers entiers qui ont disparu, une chose que vous pouvez faire est la suivante si vous ne vous souciez pas de l'historique dans les anciens fichiers: 1. créez une nouvelle branche à partir de la branche actuellement foirée. 2. retournez à la mauvaise branche et créez une autre nouvelle branche qui est votre branche de sauvetage 3. De votre branche de sauvetage, revenez à la validation avant l'échec de la validation. 4. Copiez les fichiers supprimés quelque part en dehors de git 5. Basculez vers l'autre nouvelle branche. 6. Copiez les nouvelles versions des fichiers supprimés dans la nouvelle branche et validez. Il y a une manière plus compliquée qui sauve l'histoire qui est un célèbre article de Linus T.
Elin
1
En fait, cela montre comment vous pouvez utiliser le paiement jasonrudolph.com/blog/2009/02/25/… C'est beaucoup plus agréable.
Elin