45 votes

Création d'un référentiel GitHub avec seulement un sous-ensemble de l'historique d'un référentiel local

Le contexte: je suis fait de se rapprocher de l'approvisionnement ouvert une recherche personnelle de code que j'ai travaillé pendant plus de deux ans. Il a commencé sa vie comme un dépôt SVN, mais j'ai déménagé à Git sur un an, et j'aimerais partager le code sur GitHub. Cependant, il a accumulé beaucoup de trucs au fil des années, et je préfère que la version publique de commencer sa vie dans son état actuel. Cependant, je voudrais encore y contribuer et d'intégrer d'autres personnes contributions potentielles.

La question: est-il un moyen de "fourche" un dépôt git à ce qu'aucun historique est conservé au niveau de la fourche (qui se trouve sur GitHub), mais que mon dépôt local a toujours une histoire complète, et je peux tirer/pousser à GitHub?

Je n'ai aucune expérience sur l'administration de la fin des grands référentiels, afin de détail est très apprécié.

69voto

Brian Campbell Points 101107

Vous pouvez créer une nouvelle histoire assez facilement dans Git. Permet de dire que vous voulez que votre master branche à celui qui vous va le pousser à GitHub, et votre histoire complète pour être stocké dans old-master. Vous pouvez simplement déplacer votre master branche d' old-master, puis de démarrer une nouvelle branche avec aucune histoire à l'aide de git checkout --orphan:

git branch -m master old-master
git checkout --orphan master
git commit -m "Import clean version of my code"

Maintenant vous avez un nouveau master de la direction, avec pas d'histoire, que vous pouvez pousser GitHub. Mais, comme vous le dites, vous voulez être en mesure de voir tous les anciens de l'histoire dans votre référentiel local; et aimerait sans doute pour elle de ne pas être déconnecté.

Vous pouvez faire cela en utilisant git replace. Un remplacement ref est un moyen de spécifier un autre à commettre tout le temps Git ressemble à un commit. Donc, vous pouvez indiquer à Git de regarder le dernier commit de votre vieille branche, au lieu de la première validation de votre nouvelle branche, lorsque l'on regarde l'histoire. Pour ce faire, vous devez apporter dans le déconnectée de l'histoire de l'ancien repo.

git replace master old-master

Maintenant que vous avez votre nouvelle branche, dans laquelle vous pouvez voir l'ensemble de votre histoire, mais les commits sont déconnectés de l'histoire ancienne, et donc vous pouvez pousser la nouvelle s'engage à GitHub sans le vieux s'engage à venir le long. Poussez votre master de la branche de GitHub, et seule la nouvelle s'engage ira à GitHub. Mais jetez un oeil à l'histoire en gitk ou git log, et vous pourrez voir l'intégralité de l'histoire.

git push github master:master
gitk --all

Pièges

Si jamais vous la base de toutes les nouvelles branches sur le vieux s'engage, vous devrez faire attention à garder l'histoire distincte; sinon, les nouvelles s'engage sur ces branches seront vraiment les vieux s'engage, dans leur histoire, et vous aurez donc tirer le tout le long de l'histoire si vous poussez jusqu'à GitHub. Aussi longtemps que vous gardez toutes vos nouveaux commits en fonction de votre nouveau master, cependant, vous serez amende.

Si jamais vous exécutez git push --tags github, qui va pousser tous vos tags, y compris les anciennes, qui sera la cause de toutes vos anciennes de l'histoire à être tiré avec elle. Vous pourriez faire face à cette par la suppression de toutes vos anciennes balises (git tag -d $(git tag -l)), ou par ne jamais utiliser l' git push --tags , mais seulement et toujours pousser les balises manuellement, ou à l'aide de deux référentiels comme décrit ci-dessous.

Le problème fondamental sous-jacent à la fois de ces pièges, c'est que si jamais vous pousser ref qui se connecte à tout de l'histoire ancienne (autres que via le remplacer s'engage), vous aurez la pousser jusqu'à l'ensemble de l'histoire ancienne. Probablement la meilleure façon d'éviter cela est d'utiliser deux dépôts, l'un qui contient uniquement les nouveaux commits, et qui contient à la fois l'ancienne et la nouvelle histoire, à l'effet de vérifier l'historique complet. Vous faites tout votre travail, votre validation, votre en poussant et en tirant à partir de GitHub, dans le repo avec juste la nouvelle s'engage; de cette façon, vous ne pouvez pas probablement accidentellement pousser votre vieux s'engage jusqu'. Vous puis tirez sur tous vos nouveaux commits dans votre repo qui dispose de l'histoire, chaque fois que vous avez besoin de regarder l'ensemble de la chose. Vous pouvez soit tirer à partir de GitHub ou l'un de vos locaux repo, selon ce qui est plus commode. Il sera de votre archive, mais pour éviter accidentellement la publication de votre histoire ancienne, vous ne poussez jamais à GitHub de lui. Voici comment vous pouvez le configurer:

~$ mkdir newrepo
~$ cd newrepo
newrepo$ git init
newrepo$ git pull ~/oldrepo maître
# maintenant newrepo vient de la nouvelle histoire; nous pouvons mettre en place oldrepo pour tirer à partir d'elle
newrepo$ cd ~/oldrepo
oldrepo$ git remote add newrepo ~/newrepo
oldrepo$ git remote update
oldrepo$ git branch --set-en amont maître newrepo/master
# ... dans newrepo, de valider, de les pousser à GitHub, etc.
# Maintenant, si nous voulons nous pencher sur l'histoire complète dans oldrepo:
oldrepo$ git pull

Si vous êtes sur Git âgés de plus de 1.7.2

Vous n'avez pas d' git checkout --orphan, de sorte que vous devrez le faire manuellement par la création d'une nouvelle référentiel de l'actuelle révision de votre référentiel existant, puis en la tirant dans votre ancien déconnecté de l'histoire. Vous pouvez le faire avec, par exemple:

oldrepo$ mkdir ~/newrepo
oldrepo$ cp $(git ls-files) ~/newrepo
oldrepo$ cd ~/newrepo
newrepo$ git init
newrepo$ git add .
newrepo$ git commit-m "Importer propre version de mon code"
newrepo$ git fetch ~/oldrepo maître:vieux-maître

Si vous êtes sur Git âgés de plus de 1.6.5

git replace et remplacer les références ont été ajoutées dans 1.6.5, de sorte que vous aurez à utiliser un plus vieux, un peu moins souple mécanisme connu sous le nom des greffes, qui vous permettent de spécifier d'autres parents pour une validation donnée. Au lieu de l' git replace de commande, exécutez:

echo $(git rev-parse master) $(git rev-parse old-master) >> .git/info/grafts

Cela rendra l'air, localement, comme si l' master commit l' old-master s'engager en tant que parent, de sorte que vous verrez un de plus s'engager qu'avec git replace.

2voto

Guy Points 5270

La réponse de Brian ci-dessus semble être complète et bien informée, mais un peu complexe.

La solution la plus simple serait de conserver deux référentiels.

Un dépôt privé de github sur lequel vous travaillez. Vous effectuez tous les transferts d’historique complet vers ce référentiel.

Le deuxième référentiel est un référentiel github public sur lequel vous publiez uniquement lorsque vous souhaitez "publier" une nouvelle version au public. Vous publiez dessus en utilisant un simple patch + diff, puis vous validez + push.

1voto

Sumeet Pareek Points 574

Un très simple et très intéressante façon de le faire est comme ci-dessous -

Disons que vous avez dans REPO-UN s'engage C1 à C10, où C1 est la première s'engager et à C10 est le dernier de la TÊTE. Et vous voulez créer un nouveau REPO-B telle qu'elle s'engage C4 à C8 (un sous-ensemble).

REMARQUE: l'Utilisation de cette méthode serait de changer le commettre SHAs (par exemple: C4 à C8' dans ce cas), mais les changements chaque commit détient restera le même, et votre premier commit va maintenant commencer avec tous les changements de votre antérieure s'engage jusqu'à ce point combiné.

Que faire?


De manière récursive tout copier sur votre machine locale

cp -R REPO-A REPO-B

Éventuellement supprimer toutes les télécommandes de votre REPO-B, car probablement que vous souhaitez utiliser comme un référentiel distinct.

cd REPO-B
git remote -v 
git remote remove REMOTE_NAME

La Force de déplacer le pointeur de la direction de la plus tard à la fin de votre sous-ensemble. Pour le sujet C4 à C8 qui serait C8. Mais le plus probable que vous aurait besoin de sous-ensembles jusqu'à la TÊTE (par exemple: formulaire C4 à C10 ou C6 à C10), dans ce cas ci-dessous l'étape n'est pas nécessaire.

git checkout -b temp
git branch -f master C8
git checkout master
git branch -D temp

Entrez le commettre SHA de la première fin de votre sous-ensemble dans le fichier .git/info/grafts répertoire. Dans ce cas, il est le SHA de commettre C4.

git rev-parse --verify C4 >> .git/info/grafts

Faire un git branch de filtrage sans arguments

git filter-branch

Ou ce qui ne fonctionne pas

git filter-branch --all

Vous pouvez maintenant pousser cela à un autre/nouvelle télécommande si vous voulez

git remote add origin NEWREMOTE
git push -u origin master

Comment cela fonctionne?


Ce lien vous indique comment ça marche vraiment - http://git.661346.n2.nabble.com/how-to-delete-the-entire-history-before-a-certain-commit-td5000540.html

Vous pouvez lire sur les greffes de git-filter-branch(1) page de manuel, dans gitrepository-mise en page(5) le dépôt git de mise en page de description, et dans gitglossary(7) un git glossaire.

En bref, chaque ligne .git/info/les greffes sont constitués de sha1 id de l'objet, suivie par l'espace-liste séparée de son effectif (greffé) parents. Afin de couper l'histoire, par exemple, après s'engager a3eb250f996bf5e, vous avez besoin de mettre ligne ne contenant que cette SHA-1 .git/info/greffes de fichier, par exemple:

$ git rev-parse --vérifier a3eb250f996bf5e >> .git/info/greffes

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X