2009-03-02 7 views
123

Angenommen, ich habe 5 lokale Commits. Ich möchte nur zwei von ihnen zu einem zentralisierten Repo (mit einem SVN-Stil-Workflow) schieben. Wie mache ich das?Wie drücken Sie nur einige Ihrer lokalen Git-Commits?

arbeitet Dies geschah nicht:

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

, dass alle fünf lokal Commits drängen landet.

Ich könnte git reset machen, um tatsächlich meine commits rückgängig zu machen, gefolgt von git stash und dann git push - aber ich habe bereits commit messages geschrieben und dateien organisiert und ich will sie nicht wiederholen.

Mein Gefühl ist, dass einige Flag Push oder Reset würde funktionieren.

Wenn es hilft, ist hier meine 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 

Antwort

153

Angenommen, Ihre Commits sind auf dem Master-Zweig und Sie wollen, dass sie an den Remote-Master-Zweig drücken:

$ git push origin master~3:master 

Wenn Sie git-svn wurden mit:

$ git svn dcommit master~3 

Im Falle von git-svn, Sie könnten auch HEAD ~ 3 verwenden, da es ein Commit erwartet. Im Fall von straight git müssen Sie den Zweignamen verwenden, da HEAD in refspec nicht richtig ausgewertet wird.

Sie auch einen längeren Ansatz nehmen könnte:

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

Wenn Sie machen eine Gewohnheit, diese Art von Arbeit fließen, sollten Sie tun, um Ihre Arbeit in einem separaten Zweig betrachten. Dann könnten Sie etwas tun wie:

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

Beachten Sie, dass der "Origin Master: Master" Teil wahrscheinlich optional für Ihre Einrichtung ist.

+10

Hinweis: Sie müssen nicht 'master ~ 3' verwenden. Jede Bezugnahme auf das gewünschte "bis zu" -Commit ist ebenso gültig, wie zum Beispiel "HEAD ~ 3" oder "HEAD ~~~", oder das spezifische SHA oder ein Etikett, das dieses Commit kennzeichnet. – Kaz

+1

Gute Sachen. Eine Warnung allerdings: Diese Beispiele drücken zum Ursprungs-Master. Wenn Sie diese Lösung kopieren und einfügen, kann es passieren, dass Sie versehentlich den Master-Zweig aktualisieren. (Natürlich sollten Sie immer vorsichtig sein und Ihren Befehl überprüfen, bevor Sie einen 'git push' absetzen ...) – nofinator

+0

Es scheint, dass dies den Commit verschiebt, aber den Zweig nicht entfernt hinzufügt. – Nateowami

15

Was ich tue, ist die Arbeit an einem lokalen Zweig namens „Arbeit“. Dieser Zweig enthält alle temporären Commits (wie Workarounds oder private Build-Optionen oder was auch immer), die ich nicht zum Upstream-Repository übertragen möchte. Ich arbeite an diesem Zweig, dann, wenn ich festschreiben will, wechsle ich zum Master-Zweig, cherry-wähle die entsprechenden Commits aus, die ich tun möchte wollen, dann drücke Master.

Nach dem Ziehen von Änderungen von der Upstream- in meinen Master-Zweig, I git checkout work und git rebase master. Das schreibt alle meine lokalen Änderungen um, um am Ende der Geschichte zu sein.

Ich benutze tatsächlich git svn mit diesem Workflow, so dass meine "Push" -Operation git svn dcommit beinhaltet. Ich benutze auch tig, die ein netter Textmodus GUI-Repository-Viewer ist, um die passenden Commits zu meister.

+0

mit git svn dcommit, können Sie ein dcommit bis geben begehen so der gewünschte Effekt ist ziemlich trivial mit git-svn. –

+0

Dieser Ansatz hat Nachteile (zusammengefasst unter http://stackoverflow.com/a/881014/1116674). Eine gute Alternative ist das Erstellen von Verzweigungen für jede Funktion, an der Sie gerade arbeiten, und eine Verzweigung zum Arbeiten. Dann verschmelzen Sie bestimmte Zweige zu "Master", damit Sie die Historie nicht verlieren. Wenn Sie mit "Arbeit" arbeiten, verschmelzen Sie alle Ihre Zweige hinein. Es ist mehr Overhead, aber in einigen Fällen lohnt es sich. – Hudon

11

Standardmäßig schiebt git-push alle Zweige. Wenn Sie dies tun:

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

Sie zu einem frei stehenden HEAD bewegen (sind Sie auf jedem Zweig nicht) und dann schieben Sie alle Zweige, einschließlich der lokalen Master (die nach wie vor ist, wo es war) auf der Fernbedienung Meister.

Die manuelle Lösung ist: (! Und gefährlich)

git push origin HEAD:master 

Wenn Sie das Standardverhalten des Drückens Alle Branchen verwirrend finden, fügen Sie diese zu Ihrer ~/.gitconfig:

[remote.origin] 
    push = HEAD 

Dann nur der Zweig, auf dem du bist, wird gedrückt. In Ihrem Beispiel (ein abgetrenntes Kopf), würden Sie diese Fehlermeldung haben, anstatt aus Versehen die falschen Commits drängen:

error: unable to push to unqualified destination: HEAD 
4

1) Verwenden Sie „git rebase“ Ihre Commits neu zu ordnen, wenn Sie wollen. Ihre Commits neu ordnen nach Ihrer Wahl durch einfachen Schnitt Paste

git rebase -i 

Dieser Befehl wird so etwas in Ihrem Editor

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) (Ich bin mit vim) anzuzeigen. Angenommen, die neue Ordnung ist

9781434 commite

Pick c3d4961 commitC

holen 4.791.291 commitA

Pick aa1cefc commitD

Pick a2bdfbd commitB

diese Änderungen in Ihrem Editor Stellen und drücke Strg + O (writeOut)

Jetzt können

git rebase -i HEAD~<commitNumber> 

Sie können prüfen, die neue Sequenz mit

git log 

3)

Oder Sie auch

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

Wenn nur ein Zweig an entfernten (Herkunft verwenden) und ein bei local (master), verwenden Sie einfach

git push <commit SHA> 
git push aa1cefc 

Dies wird CommB und CommitD drücken.

3

Kurze Antwort:

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

Beispiele:

git push fc47b2

git push HEAD~2

Lange Antwort:

Commits sind miteinander verbunden als eine Kette mit einem Eltern/Kind-Mechanismus.Also, Push-Commit tatsächlich schiebt auch alle Eltern Commits zu diesem Commit, die nicht an die Remote bekannt. Dies geschieht implizit, wenn Sie git push das aktuelle Commit: alle vorherigen Commits werden auch gedrückt, da dieser Befehl git push HEAD entspricht.

So könnte die Frage in neu geschrieben werden, wie ein bestimmtes Commit schieben und diese spezifische begehen könnte HEAD ~ 2, zum Beispiel.

Wenn die Commits Sie sind nicht aufeinander folgende, einfach neu, um sie mit einem git rebase -i vor dem spezifischen Push schieben möchten.

Verwandte Themen