Changer de branche Git sans extraction de fichiers

100

Est-il possible dans Git de passer à une autre branche sans extraire tous les fichiers?

Après avoir changé de branche, je dois supprimer tous les fichiers, les régénérer, valider et revenir en arrière. Donc, extraire des fichiers n'est qu'une perte de temps (et il y a environ 14 000 fichiers - c'est une longue opération).

Pour que tout soit clair:

J'ai besoin de tout cela pour télécharger la documentation sur GitHub.

J'ai un référentiel avec la branche gh-pages . Lorsque je reconstruis la documentation localement, je la copie dans le répertoire du référentiel, je la valide et la pousse sur GitHub. Mais je n'étais pas content, car j'avais deux copies de la documentation localement. Et j'ai décidé de créer une branche vide et après m'être engagé, passer à vide et supprimer des fichiers. Mais revenir en arrière est une longue opération - j'ai donc posé cette question.

Je sais que je peux simplement laisser sur la branche gh-pages et supprimer des fichiers, mais je n'aime pas les arbres sales.

tig
la source
Combien de temps est "long" pour vous? Sur quelle plateforme travaillez-vous? Travaillez-vous sur un réseau tel que NFS ou autre partage de fichiers?
Greg Hewgill
Quel est le but de cet exercice? Voulez-vous avoir deux branches, l'une avec des validations détaillées, la seconde enregistrant uniquement les changements majeurs (à gros grains)?
Jakub Narębski
Il est peut-être moins coûteux de créer un clone temporaire (ou permanent?) De votre copie de travail. Ma réponse associée et un résumé montrent comment cela fonctionne même en tant que sous-répertoire du référentiel principal.
krlmlr

Réponses:

106

Oui, vous pouvez le faire.

git symbolic-ref HEAD refs/heads/otherbranch

Si vous devez vous engager sur cette branche, vous voudrez également réinitialiser l'index, sinon vous finirez par commettre quelque chose en fonction de la dernière branche extraite.

git reset
CB Bailey
la source
1
Utilisez echo "ebff34ffb665de0694872dceabe0edeaf50ec5a9" > .git/HEADsuivi de git resetpour pointer vers une référence au lieu d'une branche.
cadorn
1
L'écriture directe dans le fichier HEAD est moins fiable. Et si vous êtes dans un sous-répertoire? Pour la tête détachée (tête pointant directement vers SHA1), essayez ceci: git update-ref HEAD refs/heads/otherbranch
Alexander Bird
2
Si vous souhaitez récupérer une nouvelle branche de la branche actuelle, une autre façon de le faire est de 1. git stash2. git checkout -b otherBranch3.git stash pop
Winny
@AlexanderBird: git update-refest utile, mais il déplace également la pointe de la branche courante.
tomekwi
47

Utilisation des commandes git de base uniquement:

Cette réponse est un peu plus longue que celle de Charles, mais elle consiste uniquement en des commandes git de base que je peux comprendre et donc me souvenir, ce qui élimine le besoin de continuer à la chercher.

Marquez votre emplacement actuel (validez d'abord si nécessaire):

git checkout -b temp

Réinitialisez (déplace) le marqueur vers l'autre branche sans changer de répertoire de travail:

git reset <branch where you want to go>

maintenant temp et d'autres branches pointent vers le même commit, et votre répertoire de travail n'est pas touché.

git checkout <branch where you want to go>

puisque votre HEAD pointe déjà vers le même commit, le répertoire de travail n'est pas touché

git branch -d temp

Notez que ces commandes sont également facilement disponibles à partir de n'importe quel client graphique.


la source
7
Je préférerais git reset --soft <branch where you want to go>éviter de mettre à jour l'index
JoelFan
7
Je suis d'accord avec votre stratégie consistant à éviter les commandes de plomberie git et à favoriser celles en porcelaine.
user64141
26

Dans la v2.24, git switchc'est quelque chose comme un coffre-fort git checkout.
Par conséquent, j'ai renommé l'alias ci-dessous en git hoppour
"sauter sur la branche sans changer d'arbre de travail"

Pour le bénéfice du lecteur:

Bien que je pense que la solution de Charles Bailey est correcte, cette solution nécessite un ajustement lors du passage à quelque chose, qui n'est pas une branche locale. Il devrait également y avoir un moyen de le faire avec des commandes régulières faciles à comprendre. Voici ce que j'ai trouvé:

git checkout --detach
git reset --soft commitish
git checkout commitish

Expliqué:

  • git checkout --detachest le même que celui git checkout HEAD^{}qui laisse la branche actuelle derrière et entre dans «l'état de tête détaché». Ainsi, la prochaine modification de HEADno plus n'affecte aucune branche. Le HEADdétachement n'affecte ni l'arbre de travail ni l'index.
  • git reset --soft commitishpuis passe HEADau SHA du donné commitish. Si vous souhaitez également mettre à jour l'index, laissez de --softcôté, mais je ne recommande pas de le faire. Ceci, encore une fois, ne touche pas l'arbre de travail et ( --soft) pas l'index.
  • git checkout commitishpuis s'attache à nouveau HEADà la commitish(branche) donnée . (Si commitishest un SHA, rien ne se passe.) Cela n'affecte pas non plus l'index ni l'arbre de travail.

Cette solution accepte tout ce qui fait référence à un commit, c'est donc idéal pour certains gitalias. Ce qui rev-parsesuit est juste un test pour s'assurer que rien ne casse la chaîne, de sorte que les fautes de frappe ne passent pas accidentellement à l'état de tête détachée (la récupération d'erreur serait beaucoup plus complexe).

Cela conduit à l' git hop treeishalias suivant :

git config --global alias.hop '!f() { git rev-parse --verify "$*" && git checkout "HEAD^{}" && git reset --soft "$*" && git checkout "$*"; }; f'

FYI, vous pouvez le trouver dans ma liste d' gitalias .

Tino
la source
Vous ne voulez pas utiliser $@plutôt que $*? La différence est que $ @ avec des arguments non développés entre guillemets, qui ont des espaces à l'intérieur.
kyb
1
@kyb L'astuce de la fonction est volée à une autre réponse SO . Et ce $@n'est définitivement pas ici. $*est utilisé à la place de $1, de sorte que cela git switch -f bdevient le même que git switch '-f b'ce qui devrait être une erreur. De cette façon, je peux raccourcir l'alias en laissant de côté une gestion des erreurs comme!f() { [ 1 = $# ] || { echo 'WTF!'; return 1; }; ..
Tino
Très bonne solution. Surtout qu'il peut être utilisé pour les succursales distantes!
Nils-o-mat le
14

Ne serait-il pas une meilleure solution d'avoir deux répertoires de travail (deux zones de travail) avec un référentiel, voire deux référentiels?

Il existe un outil git-new-workdir dans la contrib/section pour vous aider.

Jakub Narębski
la source
Git-new-workdir est-il identique à la propre commande worktree de git? J'utilise worktree lorsque je souhaite extraire une branche dans un dossier différent (sans avoir à cloner le dépôt entier).
Ryuu
Le git-new-worktreescript est antérieur à la git worktreesous-commande; cette commande n'était pas disponible lorsque la réponse a été écrite. Le script, par exemple, nécessite la prise en charge des liens symboliques; IMHO, il est préférable d'utiliser le support natif.
Jakub Narębski
8

Je pense que vous recherchez la commande de plomberie git read-tree. Cela mettra à jour l'index mais ne mettra à jour aucun fichier dans votre répertoire de travail. Par exemple, en supposant que branchle nom de la branche à lire est:

branche d'arbre de lecture git

Si vous souhaitez ensuite vous engager dans la branche que vous venez de lire, vous devrez également:

git symbolic-ref HEAD refs / heads / branch
Greg Hewgill
la source
non je n'ai besoin que de changer de branche, pas d'autres changements - donc symbolic-ref est assez bon
tig
read-treegénère l'erreur: fatal: Not a valid object name branchs'il n'y en avait pas git switch branchencore
Andry
7

Vous pouvez écraser votre fichier HEAD avec un nom de branche différent:

echo "ref: refs / heads / MyOtherBranch"> .git / HEAD

user157005
la source
13
Il est probablement préférable d'utiliser la commande symbolic-ref pour le faire pour vous: git symbolic-ref HEAD refs/heads/MyOtherBranch kernel.org/pub/software/scm/git/docs/git-symbolic-ref.html
Greg Hewgill
@GregHewgill, c'est le seul moyen que je connaisse pour déplacer le HEAD vers un hachage de validation. Pouvez-vous faire ça avec git symbolic-ref?
tomekwi
0

Avec autant de fichiers, il vaut peut-être mieux garder deux dépôts, un pour chaque branche. Vous pouvez extraire les modifications selon vos besoins. Cela va être moins surprenant que d'essayer de jouer des tours de scorbut avec git.

Norman Ramsey
la source
Vous pouvez utiliser git-new-worktreepour cela à la place (in contrib/)
Jakub Narębski
J'ai souvent fait quelque chose de similaire, c'est-à-dire copier mon répertoire local avant de faire des "trucs effrayants" en tant que débutant (comme changer de branche, etc.). J'encourage les gens à suivre cette voie jusqu'à ce que vous vous sentiez confiant dans votre git-fu, mais à s'en éloigner lorsque cela est possible. Garder deux dépôts distincts est correct, mais ajoute une couche de complication et ne vous permet pas de profiter des nombreuses fonctionnalités utiles de git (fusion, sélection de cerises, etc.).
David
0

Si vous essayez simplement de changer où pointe une branche distante, vous pouvez le faire avec "git push" sans toucher à votre copie locale.

http://kernel.org/pub/software/scm/git/docs/git-push.html

Le format d'un paramètre <refspec> est un signe plus + facultatif, suivi de la référence source <src>, suivi de deux points:, suivi de la référence de destination <dst>. Il est utilisé pour spécifier avec quel objet <src> la référence <dst> dans le référentiel distant doit être mise à jour.

Par exemple, pour mettre à jour foo pour valider c5f7eba, procédez comme suit:

git push origin c5f7eba:foo

Je ne sais pas si c'est ce que vous recherchiez ou non.

Tim Abell
la source
La question a déjà obtenu une réponse: stackoverflow.com/questions/1282639/…
tig
0

vous pouvez utiliser

      1. git checkout -f <new-branch>
      2. git cherry-pick -x <previous-branch-commit-id>

previous-branch-commit-id est le commit à partir duquel vous voulez copier les anciennes données.

Haseena Parkar
la source
0

Ou utilisez simplement un fichier de patch pour patcher de votre autre branche à votre maître

git diff otherbranch master > ~/tmp/otherbranch.diff
git checkout master
git apply ~/tmp/otherbranch.diff
Tomer Ben David
la source
-1

disons que vous voulez être dans la branche A, mais avec les fichiers de la branche B

trouver le commit ref actuel de la branche A avec git log, par exemple "99ce9a2",

git checkout A
git reset --hard B
git reset 99ce9a2

vous devriez maintenant être sur la branche A, avec une structure de dossiers correspondant à B, qui apparaissent comme des changements non étagés (un historique n'a pas changé).

Dugas
la source