ローカルgitコミットの一部のみをどのようにプッシュしますか?


160

5つのローカルコミットがあるとします。そのうちの2つだけを(SVNスタイルのワークフローを使用して)一元化されたリポジトリにプッシュしたいと思います。どうすればよいですか?

これは機能しませんでした:

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

これで、5つのローカルコミットがすべてプッシュされます。

私は実際にコミットを元に戻すためにgit resetを実行し、次にgit stashを実行してからgit pushを実行できると思います-しかし、すでにコミットメッセージが書き込まれ、ファイルが整理されているため、やり直したくありません。

私の感じでは、プッシュまたはリセットに渡されたいくつかのフラグが機能すると思います。

それが役立つ場合は、ここに私の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

回答:


192

あなたのコミットがマスターブランチにあり、それらをリモートマスターブランチにプッシュしたいと仮定します:

$ git push origin master~3:master

git-svnを使用していた場合:

$ git svn dcommit master~3

git-svnの場合、コミットを想定しているため、HEAD〜3を使用することもできます。ストレートgitの場合、refspecではHEADが正しく評価されないため、ブランチ名を使用する必要があります。

また、次のような長いアプローチを取ることもできます。

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

このタイプのワークフローを習慣付ける場合は、別のブランチで作業を行うことを検討する必要があります。それからあなたは次のようなことをすることができます:

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

「origin master:master」の部分は、設定ではおそらくオプションであることに注意してください。


14
注:を使用する必要はありませんmaster~3HEAD~3またはなどの目的の「最大」コミットへの参照HEAD~~~、または特定のSHA、またはコミットをラベル付けするタグなども同様に有効です。
Kaz

2
いい物。しかし警告:これらの例はオリジンマスターにプッシュします。このソリューションをコピーして貼り付ける場合、誤ってマスターブランチを更新する可能性があります。(もちろん、常に注意して、git push...を発行する前にコマンドを再確認する必要があります)
nofinator

これはコミットをプッシュしているようですが、ブランチをリモートで追加していません。
Nateowami 2017

@Nateowamiのためのあなたは以外に指定する必要がありますということmasterのような、refspecのリモート側のためにgit push origin tocommit:newbramch
ライアン・グラハム

そうですか。ブランチ名はすでにローカルに存在しています。私はそれが好きではなかったと思います。リモートにはまだブランチ名がありませんでした。
Nateowami 2017

16

私がしていることは、「work」と呼ばれるローカルブランチで作業することです。このブランチには、アップストリームリポジトリにプッシュするつもりのないすべての一時的なコミット(回避策やプライベートビルドオプションなど)が含まれています。私はそのブランチに取り掛かり、コミットしたいときにマスターブランチに切り替え、コミットたい適切なコミットをチェリーピックしてからマスターをプッシュします。

アップストリームからマスターブランチに変更をプルした後、I git checkout workgit rebase master。これにより、ローカルでのすべての変更が履歴の最後になるように書き換えられます。

git svnこのワークフローでは実際に使用しているため、「プッシュ」操作にはが含まれgit svn dcommitます。私はまたtig、適切なコミットをマスターにチェリーピックするために、テキストモードのGUIリポジトリビューアとして使用しています。


git svn dcommitを使用すると、dcommitまでのコミットを指定できるため、目的の効果はgit-svnで非常に簡単です。
ライアングラハム、

このアプローチには欠点があります(ここで要約すると、stackoverflow.com/a/881014/1116674)。良い代替策は、作業しているすべての機能のブランチとブランチを作成することですwork。次に、特定のブランチをにマージして、ブランチmasterの履歴を失わないようにします。を使用する場合はwork、すべてのブランチをマージします。オーバーヘッドは大きくなりますが、場合によっては価値があるかもしれません。
Hudon、2012年

16

デフォルトでは、git-pushはすべてのブランチをプッシュします。これを行うと:

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

デタッチされたHEAD(どのブランチにもいない)に移動してから、ローカルマスター(まだそこにある)を含むすべてのブランチをリモートマスターにプッシュします。

手動による解決策は次のとおりです。

 git push origin HEAD:master

すべてのブランチをプッシュするデフォルトの動作が混乱する(そして危険!)とわかった場合は、これを〜/ .gitconfigに追加します。

 [remote.origin]
    push = HEAD

次に、現在のブランチのみがプッシュされます。あなたの例(分離されたヘッド)では、誤ったコミットを誤ってプッシュするのではなく、このエラーメッセージが表示されます:

 error: unable to push to unqualified destination: HEAD

10

短い答え:

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

例:

git push fc47b2

git push HEAD~2

長い答え:

コミットは、親/子メカニズムを持つチェーンとしてリンクされます。したがって、コミットをプッシュすると、実際には、リモートが認識していないすべての親コミットもこのコミットにプッシュされます。これはgit push、現在のコミット時に暗黙的に行われますgit push HEAD。このコマンドはと同等であるため、以前のすべてのコミットもプッシュされます。

したがって、質問は、特定のコミットをプッシュする方法に書き直される可能性があり、この特定のコミットは、たとえばHEAD〜2になる可能性があります。

プッシュするコミットが連続していない場合はgit rebase -i特定のプッシュの前にaを付けて単に並べ替えます。


5

1)必要に応じて、「git rebase」を使用してコミットを並べ替えます。

git rebase -i

このコマンドは、エディターに次のようなものを表示します(私は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)単純なカットペーストにより、選択に応じてコミットを並べ替えます。新しい注文が

選択9781434 commitE

c3d4961 commitCを選択

4791291 commitAを選択

aa1cefcを選択しましたcommitD

a2bdfbd commitBを選択

エディターでこれらの変更を行い、Ctrl + O(writeOut)を押します。

またはあなたも使うことができます

git rebase -i HEAD~<commitNumber>

新しいシーケンスを確認することができます

git log

3)今使う

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

remote(origin)に1つのブランチとlocal(master)に1つのブランチしかない場合は、

git push <commit SHA>
git push aa1cefc

これにより、commitBとcommitDがプッシュされます。

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.