Comment créer une nouvelle (et vide!) Branche «racine»?

135

Je voudrais définir une nouvelle branche "racine" dans ce dépôt git. Par branche "racine", j'entends une branche qui est entièrement indépendante de toutes les autres branches du référentiel 1 .

Malheureusement, même le commit (appelons-le A) à la base même de l'arborescence de commit du dépôt contient beaucoup de fichiers (il s'agissait d'un dépôt initialisé sur un projet déjà assez mature).

Cela signifie que même si je donnais Acomme nouvelle branche <start-point>, cette nouvelle branche ne partirait pas d'une "table rase", mais contiendrait plutôt tous les fichiers qui ont été validés A.

Existe-t-il un moyen de créer une branche complètement nue dans ce référentiel, avec le <start-point>plus près Apossible?


1 BTW, c'est n'équivaut pas à créer un nouveau repo. Des dépôts séparés seraient moins pratiques pour de nombreuses raisons.


EDIT : OK, c'est ce que j'ai fait, basé sur la réponse de vcsjones :

# save rev of the current earliest commit
OLDBASE=$(git rev-list --max-parents=0 HEAD)

# create a new orphan branch and switch to it
git checkout --orphan newbranch
# make sure it's empty
git rm -rf .

# create a new empty commit in the new branch, and
# save its rev in NEWBASE
git commit --allow-empty -m 'base commit (empty)'
NEWBASE=$(git rev-list HEAD)

# specify $NEWBASE as the new parent for $OLDBASE, and
# run filter-branch on the original branch
echo "$OLDBASE $NEWBASE" > .git/info/grafts
git checkout master
git filter-branch

# NOTE: this assumes that the original repo had only one
# branch; if not, a git-filter-branch -f <branch> command
# need to be run for each additional branch.

rm .git/info/grafts

Bien que cette procédure soit un peu compliquée, le résultat final est un commit de base vide qui peut servir de <start-point>pour toute nouvelle "branche propre"; tout ce que je devrais faire alors c'est

git checkout -b cleanslate $(git rev-list --max-parents=0 HEAD)

À l'avenir, je créerai toujours de nouveaux référentiels comme celui-ci:

git init
git commit --allow-empty -m 'base commit (empty)'

... pour que le premier commit soit vide , et toujours disponible pour démarrer une nouvelle branche indépendante. (Ce serait, je sais, une installation très rarement nécessaire, mais il est assez facile de la rendre facilement disponible.)

kjo
la source
1
@Anonymoose: Juste pour information (plutôt que débat): je ne suis pas d'accord avec votre opinion.
kjo
1
Il semble y avoir une solution beaucoup plus simple basée sur git rebase --onto, voir stackoverflow.com/questions/645450/...
Stéphane Gourichon

Réponses:

223

Utilisez le --orphanlors de la création de la branche:

git checkout --orphan YourBranchName

Cela créera une nouvelle branche avec zéro commit, mais tous vos fichiers seront mis en scène. À ce stade, vous pouvez simplement les supprimer.
("les supprimer": Agit reset --hard videra l'index, vous laissant avec un arbre de travail vide)

Jetez un œil à page de manuel de vérification pour plus d'informations sur --orphan.

vcsjones
la source
Cela crée-t-il essentiellement une ardoise vierge? Comme dans, à partir de zéro? Ou garde-t-il toutes vos modifications précédentes, mais pas dans l'historique de git?
Con Antonakos
4
@ConAntonakos Cela crée une nouvelle branche sans parent. Les autres branches ne sont pas affectées, toutes leurs modifications sont conservées.
fuz
11

Pour ajouter à la réponse acceptée, la meilleure pratique pour revenir à l'état propre est de créer un commit initial vide afin que vous puissiez facilement rebaser lors de la configuration de vos branches pour la postérité. De plus, puisque vous voulez un état propre, vous avez probablement des fichiers validés que vous ne devriez pas, vous devez donc les supprimer de l'index. Dans cet esprit, vous devriez:

$ git checkout --orphan dev2
Switched to a new branch 'dev2'
$ git reset # unstage all the files, you probably don't want to commit all of them
$ git commit --allow-empty -m 'Initial empty commit'
[dev2 (root-commit) a515c28] Initial empty commit
Mr_and_Mrs_D
la source
1
Je pense que ce n'est pas nécessaire à partir de 2012 car vous pouvez rebase sur root .
Timmmm le
1

Si vous utilisez git 2.23 ou supérieur, vous pouvez être habitué à git switchet à lagit restore place de git checkout. Si tel est le cas, le drapeau est le même que celui mentionné dans cette réponse .

git switch --orphan YourBranchHere
Captain Man
la source
1

Existe-t-il un moyen de créer une branche complètement nue dans ce référentiel.

La commande réelle à utiliser (avec Git 2.28+) est:

git switch --discard-changes --orphan newBranch
# or
git switch -f --orphan newBranch

git switchest disponible à partir de Git 2.23 (août 2019) et remplace l' ancienne git checkoutcommande déroutante .

Mais je recommanderais Git 2.28 (Q3 2020), car git switch --discard-changes --orphan a été optimisé dans cette version.

Voir commit 8d3e33d , commit 8186128 (21 mai 2020) par brian m. Carlson (bk2204 ) .
(Fusionné par Junio ​​C Hamano - gitster- dans commit ded44af , 09 juin 2020)

builtin/checkout: simplifier l'initialisation des métadonnées

Signé par: Brian M. Carlson
Commenté par: Derrick Stolee

Lorsque nous appelons init_checkout_metadataàreset_tree, nous voulons transmettre l'ID d' objet de la livraison en question afin qu'il puisse être transmis à des filtres, ou s'il n'y a pas de commettre, l'arbre.

Nous avons anticipé ce dernier cas, qui peut se produire ailleurs dans le code de paiement, mais cela ne peut pas se produire ici.

Le seul cas dans lequel nous n'avons pas d'objet de validation est lors de l'appel git switchavec--orphan .

De plus, nous ne pouvons atteindre ce chemin de code que sans objet de validation en plus avec --forceou--discard-changes .

Dans un tel cas, il est inutile d'initialiser les métadonnées d'extraction avec un commit ou une arborescence car

  • (a) il n'y a pas de commit, seulement l'arbre vide, et
  • (b) nous n'utiliserons jamais les données, car aucun fichier ne sera maculé lors de l'extraction d'une branche sans fichier.

Passez l'ID d'objet entièrement zéros dans ce cas, car nous avons juste besoin d'une valeur qui est un pointeur valide.

Tester:

git switch master
echo foo >foo.txt
git switch --discard-changes --orphan new-orphan2
git ls-files >tracked-files
# test_must_be_empty tracked-files
VonC
la source