2009-03-02 5 views
123

Supponiamo che abbia 5 commit locali. Voglio spingere solo 2 di loro su un repository centralizzato (utilizzando un flusso di lavoro in stile SVN). Come faccio a fare questo?come si spinge solo alcuni dei vostri commit git locali?

Questo non ha funzionato:

git checkout HEAD~3 #set head to three commits ago 
git push #attempt push from that head 

che finisce per spingere tutti i 5 commit locali.

Suppongo che potrei fare git reset per annullare effettivamente i miei commit, seguito da git stash e poi git push - ma ho già ricevuto messaggi di commit scritti e file organizzati e non voglio rifarli.

La mia sensazione è che qualche bandiera passata a push o reset funzionasse.

Se aiuta, ecco il mio git config

[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 

risposta

153

Assumendo che il commit sono sul ramo principale e si desidera spingerli al ramo principale remoto:

$ git push origin master~3:master 

Se si sta utilizzando git-svn:

$ git svn dcommit master~3 

Nel caso di git-svn, potresti anche usare HEAD ~ 3, poiché si aspetta un commit. Nel caso di git dritto, è necessario utilizzare il nome del ramo perché HEAD non viene valutato correttamente nel refspec.

Si potrebbe anche adottare un approccio più di:

$ git checkout -b tocommit HEAD~3 
$ git push origin tocommit:master 

Se si sta facendo l'abitudine di questo tipo di flusso di lavoro, si dovrebbe prendere in considerazione di fare il lavoro in un ramo separato. Quindi è possibile fare qualcosa del tipo:

$ git checkout master 
$ git merge working~3 
$ git push origin master:master 

Si noti che la parte "master originale: master" è probabilmente facoltativa per l'installazione.

+10

Nota: non è necessario utilizzare 'master ~ 3'. Qualsiasi riferimento al commit "fino a" desiderato è ugualmente valido, come ad esempio "HEAD ~ 3" o "HEAD ~~~", o lo specifico SHA, o un tag con le etichette che si impegnano. – Kaz

+1

Roba buona. Un avvertimento però: questi esempi spingono al master di origine. Se stai copiando e incollando questa soluzione, potresti finire per aggiornare accidentalmente il ramo principale. (Naturalmente, si dovrebbe sempre fare attenzione e ricontrollare il comando prima di emettere un 'git push' ...) – nofinator

+0

Sembra che questo spinga il commit, ma non aggiunga il ramo da remoto. – Nateowami

15

Quello che faccio è lavorare su un ramo locale chiamato "lavoro". Questo ramo contiene tutti i commit temporanei (come soluzioni temporanee o opzioni di build private o qualsiasi altra cosa) che non intendo inviare al repository upstream. Lavoro su quel ramo, poi quando voglio commetterlo passo al ramo principale, seleziono i commit appropriati che io do voglio commettere, quindi premi master.

Dopo aver effettuato le modifiche dall'upstream nel mio ramo principale, I git checkout work e git rebase master. Questo riscrive tutti i miei cambiamenti locali alla fine della storia.

Sto effettivamente utilizzando git svn con questo flusso di lavoro, quindi la mia operazione "push" riguarda git svn dcommit. Io uso anche tig che è un bel visualizzatore di file in modalità testo, per selezionare i commit appropriati da padroneggiare.

+0

con git svn dcommit, è possibile specificare un commit to dcommit fino a, quindi l'effetto desiderato è piuttosto banale con git-svn. –

+0

Ci sono degli svantaggi in questo approccio (riassunto qui http://stackoverflow.com/a/881014/1116674). Una buona alternativa è creare rami per ogni funzione su cui stai lavorando e un ramo 'lavoro'. Quindi, unisci rami specifici in 'master' in modo da non perdere la cronologia su di essi. Quando lavori con 'work', unisci tutti i tuoi rami in esso. È più sovraccarico, ma potrebbe valerne la pena in alcuni casi. – Hudon

11

Per impostazione predefinita, git-push spinge tutti i rami. Quando si esegue questa operazione:

git checkout HEAD~3 #set head to three commits ago 
git push #attempt push from that head 

Si sposta ad una testa staccata (non sei su qualsiasi ramo) e poi spingere tutti i rami, tra cui il maestro locale (che è ancora in cui è stato) per il telecomando maestro.

La soluzione manuale è: (! E pericolosa)

git push origin HEAD:master 

Se si trova il comportamento predefinito di spingere tutti i rami di confusione, aggiungere questo al tuo ~/.gitconfig:

[remote.origin] 
    push = HEAD 

Poi viene spinto solo il ramo su cui ti trovi. Nel tuo esempio (una testa staccata), si sarebbe ottenuto questo messaggio di errore, piuttosto che spingere accidentalmente i commit sbagliate:

error: unable to push to unqualified destination: HEAD 
4

1) Utilizzare "git rebase" per riordinare le commit, se si vuole.

git rebase -i 

Questo comando visualizzerà qualcosa di simile nel vostro editor (sto usando 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) Riordinare i tuoi commit secondo la vostra scelta con una semplice pasta di taglio. Supponiamo che il nuovo ordine è

raccogliere 9.781.434 commite

prelievo c3d4961 commitC

raccogliere 4.791.291 commitA

prelievo aa1cefc commitD

prelievo a2bdfbd commitB

apportare queste modifiche nel vostro editor e premi ctrl + O (writeOut)

Oppure si può anche utilizzare

git rebase -i HEAD~<commitNumber> 

È possibile controllare la nuova sequenza con

git log 

3) Ora usare

git push <remoteName> <commit SHA>:<remoteBranchName> 

Se solo un ramo in remoto (origine) e uno a livello locale (master), basta usare

git push <commit SHA> 
git push aa1cefc 

In questo modo verranno inseriti commitB e commitD.

3

Risposta breve:

git push <latest commit SHA1 until you want commits to be pushed>

Esempi:

git push fc47b2

git push HEAD~2

Risposta lunga:

impegna sono collegati tra loro come una catena con un meccanismo genitore/figlio.In questo modo, premendo un commit in realtà spinge anche tutti i genitori commettono in questo commit che non è noto al telecomando. Questo viene fatto implicitamente quando si esegue il commit corrente: tutti i commit precedenti vengono anche inseriti perché questo comando equivale a git push HEAD.

Quindi la domanda potrebbe essere riscritta in Come inviare un commit specifico e questo commit specifico potrebbe essere HEAD ~ 2, ad esempio.

Se i commit che si desidera eseguire sono non consecutivi, è sufficiente riordinarli con un git rebase -i prima del push specifico .