2010-03-14 17 views
4

C'est bizarre, mais je ne peux pas accomplir une opération assez courante avec git. Fondamentalement ce que je veux est de vérifier une branche de caractéristique, n'utilisant pas sa tête mais utilisant l'identification de SHA. Ce SHA pointe entre les fusions de la branche master. Le problème est que tout ce que je reçois est juste une branche maître sans un commit de la branche caractéristique. Actuellement, j'essaie de corriger une régression introduite plus tôt dans la branche master.Git. La branche de la fonctionnalité de paiement entre les validations de fusion

Juste pour être plus descriptif, je Crafted un petit script bash pour recréer un dépôt de problème:

#!/bin/bash 

rm -rf ./.git 
git init 

echo "test1" > test1.txt 
git add test1.txt 
git commit -m "test1" -a 

git checkout -b patches master 

echo "test2" > test2.txt 
git add test2.txt 
git commit -m "test2" -a 

git checkout master 

echo "test3" > test3.txt 
git add test3.txt 
git commit -m "test3" -a 

echo "test4" > test4.txt 
git add test4.txt 
git commit -m "test4" -a 

echo "test5" > test5.txt 
git add test5.txt 
git commit -m "test5" -a 

git checkout patches 
git merge master  

#Now how to get a branch having all commits from patches + test3.txt + test4.txt - test5.txt ??? 

Fondamentalement, tout ce que je veux est juste pour la branche caisse « patches » avec des fichiers 1-4, mais non compris test5.txt.

Faire: git checkout [sha_where_test4.txt_entered]

... juste donne une branche avec test1, test3, test4, mais à l'exclusion test2.txt

exemple plus complexe:

#!/bin/bash 

rm -rf ./.git 
git init 

echo "test1" > test1.txt 
git add test1.txt 
git commit -m "test1" -a 

git checkout -b patches master 

echo "test2" > test2.txt 
git add test2.txt 
git commit -m "test2" -a 

git checkout master 

echo "test3" > test3.txt 
git add test3.txt 
git commit -m "test3" -a 

echo "test4" > test4.txt 
git add test4.txt 
git commit -m "test4" -a 

echo "test5" > test5.txt 
git add test5.txt 
git commit -m "test5" -a 

git checkout patches 
git merge master 

echo "test6" > test6.txt 
git add test6.txt 
git commit -m "test6" -a 

#Now how to get a branch having all commits from patches + test3.txt + test4.txt - test5.txt ??? 
git log --topo-order | cat 

# Now I need something to help me going back to history 
# without manually calculating that patches~2 sha's 
git checkout -b patches.tmp master~1 
git merge patches~2 

Merci.

Répondre

1

En ce qui concerne votre premier exemple, vous devez rejouer test3 et 4 sur le dessus de test2: c'est un case of rebase --onto classique:

Départ:

alt text http://img169.imageshack.us/img169/2255/gitr1.png

Marquer la mise en place actuelle des correctifs et déplacer la branche de patches où vous souhaitez mettre fin à (test4):

C:\Prog\Git\tests\rep\main>git checkout patches 
Switched to branch 'patches' 

C:\Prog\Git\tests\rep\main>git checkout -b tmp 
Switched to a new branch 'tmp' 

C:\Prog\Git\tests\rep\main>git checkout patches 
Switched to branch 'patches' 

C:\Prog\Git\tests\rep\main>git reset --hard master~1 
HEAD is now at 8448d0f test4 

Cela vous donne:

alt text http://img169.imageshack.us/img169/4826/gitr2.png

Et rebasage sur ce que vous voulez la séquence correcte de commits:

C:\Prog\Git\tests\rep\main>git checkout tmp 
Switched to branch 'tmp' 

C:\Prog\Git\tests\rep\main>git rebase --onto tmp tmp~1 patches 
First, rewinding head to replay your work on top of it... 
Applying: test3 
Applying: test4 

Ce qui donne:

alt text http://img52.imageshack.us/img52/372/gitr3.png

Cela ne fonctionne que pour ensemble linéaire de commits être déplacé.

+0

Assez soigné. Cela ressemble à une magie noire. J'essaie juste de comprendre pourquoi les commits se sont déplacés au-dessus des correctifs au lieu de tmp, comme - tmp suggéré. Selon le manuel, git rebase [--onto ] [], newbase est tmp! Quelque chose me manque? – MageSlayer

+0

@mageslayer: commits ne s'est pas déplacé au-dessus de 'patches', mais en plus de' tmp'. 'newbase' est en effet' tmp'. "patches" se termine à droite commit simplement parce que, avant le 'rebase --onto', je l'ai réinitialisé au bon endroit de destination je voulais qu'il soit à. – VonC

+0

@mageslayer: comme une "branche" dans Git est vraiment juste une étiquette à la pointe d'un chemin de graphe, vous pouvez vous sentir libre de déplacer cette étiquette ... sauf si vous avez déjà publié cette branche ('push'), ce qui signifierait un monde blessé pour quiconque tirant de votre (nouvelle) branche: tout serait à nouveau fusionné. – VonC

0

Une opération git merge ne revient pas en arrière et modifie l'historique, elle crée plutôt un nouveau commit pointant vers les deux historiques d'origine. Ainsi, en images, ce que vous avez quelque chose comme ceci:

 
    2-----------\ 
/   \ 
1---3---4---5---M (HEAD) 

Lorsque vous rembobiner l'histoire pour revenir à la révision 4, vous obtenez les fichiers 1, 3 et 4, mais pas 2.

+0

Oui. Tu as raison. Le problème est que j'ai besoin de test2.txt – MageSlayer

+0

La réponse de @ calmh décrit une façon de le faire, en créant un commit de fusion * new *. –

+0

J'apprécie sa réponse, mais c'est trop de travail à mon humble avis. Je suis déjà en train de creuser dans la direction cherrypick. Pourtant, pas tout à fait réussi cependant. – MageSlayer

1

Il n'y a pas de tel point. Vous avez ici deux chemins de développement parallèles, l'un contenant les fichiers test1 et test2, l'autre contenant les fichiers test1, test3, test4 et test5. Vous pouvez cependant créer un tel point avec une fusion.

Extrayez le SHA1 pour le commit qui ajoute test4, et fusionnez avec le commit qui ajoute test2. Par exemple, après l'exécution de votre script mon dépôt ressemble à ceci:

* b054987 (HEAD, patches) Merge branch 'master' into patches 
|\ 
* | 5ae790f test2 
| * f2a3dac (master) test5 
| * 70e8cd2 test4 
| * c4102ed test3 
|/ 
* d448eaa test1 

Sur ce, exécutez:

% git checkout 70e8c 
% git merge 5ae79 

Le résultat est une tête qui contient des fichiers 1-4:

* bcc8f7a (HEAD) Merge commit '5ae79' into HEAD 
|\ 
| | * b054987 (patches) Merge branch 'master' into patches 
| | |\ 
| |// 
| * | 5ae790f test2 
| | * f2a3dac (master) test5 
| |/ 
|/| 
* | 70e8cd2 test4 
* | c4102ed test3 
|/ 
* d448eaa test1 

% ls 
test1.txt test2.txt test3.txt test4.txt 

Vous pouvez maintenant créer une branche à partir de ce point de votre choix.

+0

Bien sûr, je peux le faire manuellement, mais cela demande beaucoup de travail dans la réalité. J'ai bien peur que Git Bisect ne m'aide pas ici aussi. – MageSlayer

+0

Mais cela fait ce que vous voulez, il suffit d'appeler la branche 'patches' après la fusion. Sinon, je ne suis pas sûr de ce que vous voulez réaliser? Il n'y a aucun intérêt dans le développement que vous décrivez qui contient les fichiers 1 à 4, vous devez donc créer un tel point. Je ne pense pas que d'autres VCS seraient en mesure d'extraire un commit qui n'existe pas ... –

+0

Fondamentalement, j'essaie de présenter cette vérification comme un ensemble linéaire de correctifs pour pouvoir diviser cette branche. Votre solution est parfaitement valide, sauf que j'ai besoin de trouver manuellement les refs commits pour fusionner dans deux branches. – MageSlayer