Supposons que j'ai 5 commits locaux. Je souhaite n'en envoyer que 2 à un référentiel centralisé (en utilisant un workflow de style SVN). Comment puis-je faire cela?
Cela n'a pas fonctionné:
git checkout HEAD~3 #set head to three commits ago
git Push #attempt Push from that head
Cela finit par pousser les 5 commits locaux.
Je suppose que je pourrais faire git reset pour annuler réellement mes commits, suivi de git stash puis git Push - mais j'ai déjà écrit des messages de commit et des fichiers organisés et je ne veux pas les refaire.
Mon sentiment est qu'un drapeau passé à Push ou reset fonctionnerait.
Si ça aide, voici ma configuration git
[ramanujan:~/myrepo/.git]$cat config
[core]
repositoryformatversion = 0
filemode = true
bare = false
logallrefupdates = true
[remote "Origin"]
url = ssh://server/git/myrepo.git
fetch = +refs/heads/*:refs/remotes/Origin/*
[branch "master"]
remote = Origin
merge = refs/heads/master
En supposant que vos validations se trouvent sur la branche principale et que vous souhaitez les envoyer à la branche principale distante:
$ git Push Origin master~3:master
Si vous utilisiez git-svn:
$ git svn dcommit master~3
Dans le cas de git-svn, vous pouvez également utiliser HEAD ~ 3, car il attend un commit. Dans le cas de git simple, vous devez utiliser le nom de la branche car HEAD n'est pas évalué correctement dans la refspec.
Vous pouvez également adopter une approche plus longue de:
$ git checkout -b tocommit HEAD~3
$ git Push Origin tocommit:master
Si vous prenez l'habitude de ce type de flux de travail, vous devriez envisager de faire votre travail dans une branche distincte. Ensuite, vous pourriez faire quelque chose comme:
$ git checkout master
$ git merge working~3
$ git Push Origin master:master
Notez que la partie "Origin master: master" est probablement facultative pour votre configuration.
Ce que je fais, c'est travailler sur une branche locale appelée "travail". Cette branche contient toutes les validations temporaires (comme des solutions de contournement ou des options de construction privées ou autre) que je n'ai pas l'intention de pousser vers le référentiel en amont. Je travaille loin sur cette branche, puis lorsque je veux valider, je passe à la branche principale, je sélectionne les commits appropriés que je veux vouloir valider , puis Push master.
Après avoir tiré les modifications de l'amont vers ma branche principale, je git checkout work
et git rebase master
. Cela réécrit tous mes changements locaux pour être à la fin de l'histoire.
J'utilise en fait git svn
avec ce flux de travail, donc mon opération "Push" implique git svn dcommit
. J'utilise également tig
qui est une visionneuse de référentiel gui en mode texte agréable, pour sélectionner les commits appropriés à maîtriser.
Par défaut, git-Push pousse toutes les branches. Lorsque vous faites cela:
git checkout HEAD~3 #set head to three commits ago
git Push #attempt Push from that head
Vous vous déplacez vers un HEAD (vous n'êtes sur aucune branche) détaché, puis vous poussez toutes les branches, y compris le maître local (qui est toujours là où il était) vers le maître distant.
La solution manuelle est:
git Push Origin HEAD:master
Si vous trouvez le comportement par défaut de pousser toutes les branches déroutant (et dangereux!), Ajoutez ceci à votre ~/.gitconfig:
[remote.Origin]
Push = HEAD
Ensuite, seule la branche sur laquelle vous vous trouvez est poussée. Dans votre exemple (une tête détachée), vous auriez eu ce message d'erreur, plutôt que de pousser accidentellement les mauvais commits:
error: unable to Push to unqualified destination: HEAD
git Push <latest commit SHA1 until you want commits to be pushed>
Exemples:
git Push fc47b2
git Push HEAD~2
Les validations sont liées entre elles comme une chaîne avec un mécanisme parent/enfant. Ainsi, pousser un commit pousse également tous les commit parents à ce commit qui n'était pas connu de la télécommande. Cela se fait implicitement lorsque vous git Push
le commit actuel: tous les commits précédents sont également poussés car cette commande est équivalente à git Push HEAD
.
Ainsi, la question pourrait être réécrite en Comment pousser un commit spécifique et ce commit spécifique pourrait être HEAD ~ 2, par exemple.
Si les validations que vous souhaitez pousser ne sont pas consécutives, il vous suffit de les réorganiser avec un git rebase -i
avant le Push spécifique.
1) Utilisez "git rebase" pour réorganiser vos commits, si vous le souhaitez.
git rebase -i
Cette commande affichera quelque chose comme ça dans votre éditeur (j'utilise vim)
pick 4791291 commitA
pick a2bdfbd commitB
pick c3d4961 commitC
pick aa1cefc commitD
pick 9781434 commitE
# Rebase ..............
#
# Commands:
# p, pick = use commit
# r, reword = use commit, but edit the commit message
# e, edit = use commit, but stop for amending
# s, squash = use commit, but meld into previous commit
# f, fixup = like "squash", but discard this commit's log message
# x, exec = run command (the rest of the line) using Shell
#
# These lines can be re-ordered; they are executed from top to bottom.
#
# If you remove a line here THAT COMMIT WILL BE LOST.
#
# However, if you remove everything, the rebase will be aborted.
#
# Note that empty commits are commented out
^G Get Help ^O WriteOut ^R Read File ^Y Prev Page ^K Cut Text ^C Cur Pos
^X Exit ^J Justify ^W Where Is ^V Next Page ^U UnCut Text ^T To Spell
2) Réorganisez vos commits selon votre choix par simple pâte coupée. Supposons que la nouvelle commande soit
pick 9781434 commitE
choisissez c3d4961 commitC
pick 4791291 commitA
choisissez aa1cefc commitD
choisissez a2bdfbd commitB
Apportez ces modifications dans votre éditeur et appuyez sur ctrl + O (writeOut)
Ou vous pouvez également utiliser
git rebase -i HEAD~<commitNumber>
Vous pouvez vérifier la nouvelle séquence avec
git log
3) Utilisez maintenant
git Push <remoteName> <commit SHA>:<remoteBranchName>
Si une seule branche à distance (origine) et une au niveau local (maître), utilisez simplement
git Push <commit SHA>
git Push aa1cefc
Cela poussera commitB et commitD.