web-dev-qa-db-fra.com

Dans git, existe-t-il un moyen simple d'introduire une branche non liée dans un référentiel?

Tout en aidant un ami à résoudre un problème lié au git aujourd'hui, je devais introduire une branche Qui devait être totalement séparée de la branche master . Le contenu de cette branche avait vraiment une origine différente de celle de développés sur la branche master, mais ils allaient être fusionnés plus tard dans la branche master.

Je me suis souvenu de la lecture de Git de John Wiegley depuis le bas Up how Branches sont essentiellement une étiquette pour un commit qui suit une certaine convention Et comment un commit est lié à une arborescence de fichiers et , facultativement, au parent s’engage. Nous sommes allés créer un commit sans parent dans le dépôt existant En utilisant la plomberie de git:

Nous nous sommes donc débarrassés de tous les fichiers de l'index ...

$ git rm -rf .

... extrait des répertoires et des fichiers d'une archive, les a ajoutés à l'index ..

$ git add .

... et créé un objet arbre ...

$ git write-tree

(git-write-tree nous a indiqué le montant de l’arbre créé.)

Ensuite, nous avons commis l’arbre, sans spécifier de commits parent ...

$ echo "Imported project foo" | git commit-tree $TREE

(git-commit-tree nous a indiqué le montant de l'objet de validation créé.)

... et créé une nouvelle branche qui pointe vers notre nouvelle création commit.

$ git update-ref refs/heads/other-branch $COMMIT

Enfin, nous sommes retournés à la branche master pour continuer à y travailler.

$ git checkout -f master

Cela semble avoir fonctionné comme prévu. Mais ce n'est clairement pas le genre de procédure que je recommanderais à quelqu'un qui commence tout juste à commencer. À utiliser git, c'est le moins que l'on puisse dire. Existe-t-il un moyen plus simple de créer une nouvelle branche qui soit totalement indépendante de tout ce qui s'est passédans le référentiel?

296
hillu

Il existe une nouvelle fonctionnalité (depuis la version 1.7.2) qui rend cette tâche un peu plus complexe que les autres réponses.

git checkout supporte maintenant l'option --Orphan. De la page de manuel :

git checkout [-q] [-f] [-m] --Orphan <new_branch> [<start_point>]

Créez une nouvelle branche Orphan, nommée <new_branch>, a commencé à partir de <start_point> et passez à celui-ci. Le premier commit sur cette nouvelle branche n'aura pas de parents et ce sera la racine d'une nouvelle histoire totalement déconnecté de tous les autres branches et commits.

Cela ne fait pas exactement ce que le demandeur voulait, car il remplit l'index et l'arbre de travail à partir de <start_point> (puisqu'il s'agit, après tout, d'une commande d'extraction). La seule autre action nécessaire consiste à supprimer les éléments indésirables de l'arborescence et de l'index de travail. Malheureusement, git reset --hard ne fonctionne pas, mais git rm -rf . peut être utilisé à la place (je crois que cela est équivalent à rm .git/index; git clean -fdx donné dans d'autres réponses).


En résumé:

git checkout --Orphan newbranch
git rm -rf .
<do work>
git add your files
git commit -m 'Initial commit'

J'ai laissé <start_point> non spécifié car la valeur par défaut est HEAD, et de toute façon nous ne nous en soucions pas. Cette séquence fait essentiellement la même chose que la séquence de commandes dans réponse d'Artem , juste sans avoir recours à des commandes de plomberie effrayantes. 

459
tcovo

De Livre de la communauté Git :

git symbolic-ref HEAD refs/heads/newbranch 
rm .git/index 
git clean -fdx 
<do work> 
git add your files 
git commit -m 'Initial commit'
30
Artem Tikhomirov

Bien que la solution avec git symbolic-ref et la suppression de l'index fonctionne, il peut être conceptuellement plus propre de créer nouveau référentiel

$ cd /path/to/unrelated
$ git init
[edit and add files]
$ git add .
$ git commit -m "Initial commit of unrelated"
[master (root-commit) 2a665f6] Initial commit of unrelated
 1 files changed, 1 insertions(+), 0 deletions(-)
 create mode 100644 foo

puis aller chercher

$ cd /path/to/repo
$ git fetch /path/to/unrelated master:unrelated-branch
warning: no common commits
remote: Counting objects: 3, done.
Unpacking objects: 100% (3/3), done.
remote: Total 3 (delta 0), reused 0 (delta 0)
From /path/to/unrelated
 * [new branch]      master     -> unrelated-branch

Maintenant, vous pouvez supprimer/chemin/vers/sans relation

22
Jakub Narębski

Github a une fonctionnalité appelée Pages de projet où vous pouvez créer une branche nommée particulière dans votre projet pour fournir des fichiers qui seront servis par Github. Leurs instructions sont les suivantes:

$ cd /path/to/fancypants
$ git symbolic-ref HEAD refs/heads/gh-pages
$ rm .git/index
$ git clean -fdx

De là, vous avez un référentiel vide auquel vous pouvez ensuite ajouter votre nouveau contenu.

12
Greg Hewgill

La réponse actuellement choisie est correcte, je voudrais juste ajouter que par hasard ...

C’est en fait exactement comme cela que github.com permet aux utilisateurs de créer des pages Github pour leurs dépôts, via une branche orpheline appelée gh-pages. Les jolies étapes sont décrites et expliquées ici:

https://help.github.com/articles/creating-project-pages-manually

En gros, les commandes git pour configurer ceci sont les suivantes:

  1. git checkout --Orphan gh-pages (créer une branche sans parent appelée gh-pages sur votre repo)
  2. git rm -rf . (supprime tous les fichiers de l'arbre de travail de la branche)
  3. rm '.gitignore' (même le gitignore)
  4. Ajoutez maintenant le contenu du site Web (ajoutez index.html, etc.), commettez et poussez.
  5. Profit.

Notez que vous pouvez également désigner un dossier/docs sur votre référentiel comme source du "Site du projet" utilisé par Github pour créer le site Web.

J'espère que cela t'aides!

6
unknownprotocol

Parfois, je veux juste créer une branche vide dans le projet instantanément, puis commencer à travailler, je vais simplement exécuter la commande suivante: 

git checkout --Orphan unrelated.branch.name
git rm --cached -r .
echo "init unrelated branch" > README.md
git add README.md
git commit -m "init unrelated branch"
3
Sing

Si votre contenu existant a déjà été validé, vous pouvez maintenant (Git 2.18 Q2 2018) l'extraire dans sa propre nouvelle branche Orphan, car la mise en œuvre de "git rebase -i --root" a été mise à jour pour utiliser La machinerie du séquenceur.

Ce séquenceur est celui qui est maintenant permettant de transplanter la topologie entière du graphe commit ailleurs }.

Voir commit 8fa6eea _, commit 9c85a1c , commit ebddf39 , commit 21d0764 , commit d87d48b , commit ba97aea (03 mai 2018) de Johannes Schindelin (dscho) .
(Fusionné par Junio ​​C Hamano - gitster - dans commit c5aa4bc , 30 mai 2018.

séquenceur: permet d'introduire de nouveaux commits root

Dans le contexte du nouveau mode --rebase-merges, qui a été conçu spécifiquement pour permettre de modifier la topologie de branche existante libéralement, un utilisateur peut vouloir extraire les commits dans un fichier complètement nouveau. branche qui commence par un commit root nouvellement créé.

Ceci est maintenant possible en insérant la commande reset [new root] avant picking le commit qui veut devenir un commit racine. Exemple:

reset [new root]
pick 012345 a commit that is about to become a root commit
pick 234567 this commit will have the previous one as parent

Cela n'entre pas en conflit avec d'autres utilisations de la commande reset car [new root] ne fait pas (partie de) un nom de référence valide: à la fois le crochet d’ouverture ainsi que l'espace sont illégaux dans les noms de référence.

0
VonC

J'ai trouvé ce script sur http://wingolog.org/archives/2008/10/14/merging-in-un-unrelated-git-branches et cela fonctionne très bien!

#!/bin/bash

set -e

if test -z "$2" -o -n "$3"; then
    echo "usage: $0 REPO BRANCHNAME" >&2
    exit 1
fi

repo=$1
branch=$2

git fetch "$repo" "$branch"

head=$(git rev-parse HEAD)
fetched=$(git rev-parse FETCH_HEAD)
headref=$(git rev-parse --symbolic-full-name HEAD)

git checkout $fetched .

tree=$(git write-tree)

newhead=$(echo "merged in branch '$branch' from $repo" | git commit-tree $tree -p $head -p $fetched)
git update-ref $headref $newhead $head
git reset --hard $headref
0
Benoît