2017-02-17 1 views
8

Je veux étendre sur une autre question que j'avais: Merge two Git repositories and keep the master historyFusionner deux prises en pension Git et de garder l'histoire

j'ai réussi à fusionner 2 différentes années prises en pension dans une pension. J'avais besoin d'un rebase pour le faire avec succès. Le maître est correct, mais Je veux également conserver l'historique de fusion. Est-ce possible?

J'ai 2 dépôts:

Repo A

Repo B

Ceci est le résultat après rebasage. Les heures du repo supérieur sont le temps de rebasage. La date d'origine est perdue!

Rebase

Voilà comment je l'ai fait:

# Assume the current directory is where we want the new repository to be created 
# Create the new repository 
git init 

# Before we do a merge, we have to have an initial commit, so we'll make a dummy commit 
dir > Read.md 
git add . 
git commit -m "initial commit" 

# Add a remote for and fetch the old RepoA 
git remote add -f RepoA https://github.com/DimitriDewaele/RepoA 

# Do the same thing for RepoB 
git remote add -f RepoB https://github.com/DimitriDewaele/RepoB 

# Rebase the working branch (master) on top of repoB 
git rebase RepoB/master 

# Rebase the working branch (master with RepoB) on top op repoA 
git rebase RepoA/master 

Est-il possible d'avoir quelque chose comme ça? (solution peint !!!)

Painted

Je voudrais garder le temps d'origine + l'histoire de fusion.

MISE À JOUR - RÉPONSE

La réponse qui fonctionne le mieux pour moi, travaillait avec des points de greffe. Mais d'autres réponses sont également très utilisables dans d'autres cas d'utilisation. J'ai ajouté mes résultats sur github, afin que tout le monde puisse évaluer.

Réponse 1: Meilleur travail dans mon cas La 'greffe' a révélé la bonne réponse de travail pour moi.

GitHub: RepoGraft

enter image description here

Réponse 2 l'option "remplacer" de "LeGEC" donne également de bons résultats pour certains cas d'utilisation. Une anomalie est restée pour moi:

GitHub: RepoHistory

enter image description here

Réponse 3: convient d'ajouter La réponse de 'VonC'. Je ne pouvais pas obtenir l'option '--preserve-merges' dans mon cas.Cela pourrait fonctionner dans d'autres scénarios, mais je n'ai pas testé ce furtner.

+0

Voulez-vous garder repoA juste pour être en mesure d'inspecter son histoire? ou sera repoA être un dépôt en direct, avec de nouveaux commits, tirer des demandes etc? – LeGEC

+0

@LeGEC Je voudrais seulement inspecter l'histoire avec l'histoire de la branche. De nouveaux travaux se produiront au-dessus du repo résultant. –

Répondre

4

Comme vous l'avez découvert, rebase n'est pas la commande que vous souhaitez utiliser pour assembler les historiques (car elle réécrit l'historique). Early Git avait une fonctionnalité (hack) conçue spécifiquement pour ce que vous essayez de faire: graft points. Mieux encore, depuis 1.6.5, vous pouvez utiliser à la place git replace --graft:

git checkout master 
git replace --graft $(git log RepoB/master --format=%H | tail -1) HEAD 
git replace --graft $(git log RepoA/master --format=%H | tail -1) RepoB/master 
git reset --hard RepoA/master 

(git log RepoA/master --format=%H | tail -1 renvoie le commit initial de RepoA)

Techniquement, vous pouvez sauter la première replace si vous n'avez pas fait quelque chose de valeur encore dans master, rapportant juste l'histoire avec RepoB + RepoA.

Ces commandes créent des entrées dans refs/replace/* qui peuvent être poussées et tirées pour partager votre historique révisé avec d'autres. Ou, si vous ne se soucient pas de préserver l'SHAs de REPOA/RepoB, vous pouvez faire les remplacements permanent en exécutant git filter-branch --all pour produire un ensemble de commits de la lignée souhaitée « réelle ».

1

Il y a deux options rebasage git qui devrait intéresser dans votre cas:

p 
--preserve-merges 

fusion Recréer au lieu d'aplatir engage l'histoire en rejouant commet une fusion commit introduit.

--committer-date-is-author-date 

(de git am)

Par défaut, la commande enregistre la date du message électronique que la validation date de l'auteur, et utilise le temps de commettre la création comme la date de committers. Cela permet à l'utilisateur de mentir sur la date de l'auteur en utilisant la même valeur que la date de l'auteur.

test si le second rebasage ne donne pas un meilleur résultat avec:

git rebase -p --committer-date-is-author-date RepoA/master 
+0

Notez que '--committer-date-is-author-date' modifie encore l'auteur pour le rebaser, ce qui peut ou peut ne pas être un problème. Vous ne voulez vraiment pas utiliser 'rebase' pour ça. – dahlbyk

+1

@dahlbyk Je sais. J'ai proposé cela comme une solution rapide, mais les vieux points de greffe font aussi l'affaire. +1 – VonC

+0

En effet, de bonnes options à connaître. Juste pas pour ce problème particulier. :) – dahlbyk

1

Cette réponse suggère une autre façon d'utiliser RepoB comme repo actif, et ont encore accès à l'histoire RepoA:

utilisation git replace

# start with a regular clone of the active repo : 
$ git clone RepoB 

# add repoA as a remote : 
$ git remote add -f history https://github.com/DimitriDewaele/RepoA 

# get hash of *initial* commit on repoB : 
$ git log --oneline origin/master | tail -1 
abcdef Initial commit 

# get hash of last commit on repoA : 
$ git log --oneline history/master | head -1 
12345 Merge branch 'develop' 

# use 'git replace' to tell git to stitch histories in the log : 
$ git replace abcdef 12345 

note: cette L'opération est effectuée sur votre machine, pas sur les dépôts distants, elle devrait donc être répétée sur tous les nouveaux clones.

Variante:

Vous pouvez pousser RepoA:master à RepoB sous un nouveau nom (par exemple: RepoB:history/master), vous pouvez alors utiliser git replace abcdef history/master, sur commits qui sont tous stockés dans RepoB.

1

Essayez de suivre ces étapes:

  1. Créer un nouveau référentiel vide Nouveau.

  2. Effectuez une validation initiale car nous en avons besoin avant d'effectuer une fusion.

  3. Ajouter un ancien référentiel distant à OldA.

  4. Fusionner OldA/master à nouveau/maître.

  5. Créez un sous-répertoire OldA.

  6. Déplacez tous les fichiers dans le sous-répertoire OldA.
  7. Validez tous les déplacements de fichiers.
  8. Répétez 3-6 pour OldB.

Un script Powershell pour ces étapes pourrait ressembler à ceci:

Supposons que le répertoire courant est l'endroit où nous voulons que le nouveau référentiel à créer Créer le nouveau référentiel

$ git initialisation

Avant de faire une fusion, nous devons avoir un commit initial, donc nous allons faire un commit factice

$ dir> deleteme.txt $ git add.

$ git commit -m « factice commit initial »

Ajouter une télécommande pour quérir l'ancien repo

$ git ajouter à distance -f old_a

fusionner les fichiers de old_a/master à nouveau/master

$ git merge old_a/master

Nettoyer notre dossier fictif parce que nous ne avons pas besoin plus

rm git $. \ Deleteme.txt

$ git commit -m « Nettoyer fichier initial »

Déplacer les fichiers et les dossiers repo old_a dans un sous-répertoire afin qu'ils ne se touchent pas l'autre repo à venir plus tard

$ mkdir old_a

$ dir -exclude old_a | % {Git mv $ _. Nom old_a}

Commit le mouvement

$ git commit -m « Déplacer les fichiers old_a dans subdir »

Faites la même chose pour old_b

$ git ajouter à distance -f old_b

fusion git $ old_b/maître

mkdir $ old_b

$ dir -exclude old_a, old_b | % {git mv $ _.Nom old_b}

commit -m $ git « fichiers Déplacer old_b dans subdir »

Apportez sur une branche caractéristique d'un des anciens repo $ git checkout -b fonction en cours

-Xsubtree récursive -s fusion git $ = old_a old_a/fonctionnalité en cours

it helps.