管理 - perforce git 連携




Gitを使って私の最後のXを一緒にコミットする (20)

私の最後のXコミットをGitを使ってコミットする方法を教えてください。


⚠️警告:「私の最後のXコミット」はあいまいかもしれません。

  (MASTER)  
Fleetwood Mac            Fritz
      ║                    ║
  Add Danny  Lindsey     Stevie       
    Kirwan  Buckingham    Nicks                                              
      ║         ╚═══╦══════╝     
Add Christine       ║          
   Perfect      Buckingham
      ║           Nicks            
    LA1974══════════╝                                    
      ║                  
      ║                  
    Bill <══════ YOU ARE EDITING HERE
  Clinton        (CHECKED OUT, CURRENT WORKING DIRECTORY)              

この非常に簡潔なhttps://github.com/fleetwood-macリポジトリの履歴では、Bill Clintonのコミットを元の( MASTER )Fleetwoodd Macのコミットにマージするプルリクエストを開いています。

あなたはプルリクエストを開き、GitHubでこれを見ることができます:

4つのコミット:

  • Danny Kirwanを追加
  • Christine Perfectを追加
  • LA1974
  • ビル・クリントン

誰も完全なリポジトリ履歴を読む気にはならないと考えている。 (実際にはリポジトリがありますので、上記のリンクをクリックしてください!)あなたはこれらのコミットを押しつぶすことにします。 だから、 git reset --soft HEAD~4 && git commit 。 それからGitHubにgit push --forceしてPRを整理してください。

そして何が起こるのですか? あなたはフリッツからビル・クリントンに至るまで一回のコミットをしました。 あなたは昨日、このプロジェクトのBuckingham Nicksバージョンで作業していたことを忘れています。 そしてgit logはGitHubで見られるものと一致しません。

ストーリーの真実

  1. あなたが望む正確なファイルを見つけ、それらをgit checkoutする
  2. 過去のコミットを正確に探し、 git reset --soft that
  3. fromからtoへ直接ワープするgit commitを行います。

1)コミット・ショート・ハッシュを特定する

# git log --pretty=oneline --abbrev-commit
abcd1234 Update to Fix for issue B
cdababcd Fix issue B
deab3412 Fix issue A
....

ここでもgit log --onelineを使って短いハッシュを得ることができます。

2)最後の2つのコミットをスカッシュ(マージ)したい場合

# git rebase -i deab3412 

3)これは、マージのためのnanoエディタを開きます。 そしてそれは以下のように見える

....
pick cdababcd Fix issue B
pick abcd1234 Update to Fix for issue B
....

4) abcd1234より前に存在するsquash単語pick名前を変更しabcd1234 。 名前を変更した後は、以下のようになります。

....
pick cdababcd Fix issue B
squash abcd1234 Update to Fix for issue B
....

5) nanoエディタを保存して閉じます。 ctrl + oを押してEnterを押して保存します。 ctrl + xを押してエディタを終了します。

6)その後、必要に応じてコメントを更新するためにnanoエディタが再度開きます。

7)正常に押しつぶされたら、ログを確認することで確認できます。

# git log --pretty=oneline --abbrev-commit
1122abcd Fix issue B
deab3412 Fix issue A
....

8)今repoにプッシュします。 ブランチ名の前に+記号を追加することに注意してください。 これは強制押しを意味します。

# git push origin +master

注:これはgitをubuntuシェルで使用することに基づいています。 別のOS( WindowsまたはMac )を使用している場合、上記のコマンドはエディタを除いて同じです。 あなたは別の編集者を得るかもしれません。


この記事に基づいて私はこの方法を私のユースケースの方が簡単に見つけました。

私の 'dev'ブランチは 'origin / dev'よりも96のコミット分だけ先行していました(これらのコミットはまだリモートにプッシュされていませんでした)。

私は変更を押す前に、これらのコミットを1つにまとめたいと思っていました。 私はブランチを 'origin / dev'の状態にリセットすることを勧めます(これは96個のコミットからのすべての変更をステージングせずに残します)。

git reset origin/dev
git add --all
git commit -m 'my commit message'

この便利なブログのポストのおかげで、 このコマンドを使って最後の3つのコミットを潰すことができます:

git rebase -i HEAD~3

トラッキング情報/リモートリポジトリを持たないローカルブランチにいるときでさえ、これは便利です。

このコマンドはインタラクティブなリベースエディタを開き、通常通りリオーダ、スカッシュ、リワードなどを行うことができます。

対話式リベースエディタの使用:

対話型のrebaseエディタには、最後の3つのコミットが表示されます。 この制約は、コマンドgit rebase -i HEAD~3実行するときにHEAD~3によって決定されました。

最新のコミットHEAD 、最初に1行目に表示されます。 #始まる行はコメント/ドキュメントです。

表示されるドキュメントはかなり明確です。 任意の行で、コマンドをpickから任意のコマンドに変更することができます。

私は、上記の行のコミットへのコミットの変更を "縮め"、コミットのメッセージを破棄するので、コマンドfixupを使用することを好みます。

1行目のコミットがHEAD場合、ほとんどの場合、これをpickとして残します。 コミットを縮めるための他のコミットがないので、 squashまたはfixupを使用することはできません。


git rebase -i <after-this-commit>を使用し、マニュアルで説明されいるように 2番目以降のコミットの "pick"を "squash"または "fixup"に置き換えてください。

この例では、 <after-this-commit>は、SHA1ハッシュ、または現在のブランチのHEADからの相対的な位置です。そこからrebaseコマンドのコミットが分析されます。 たとえば、ユーザーが過去の現在のHEADから5つのコミットを表示したい場合、コマンドはgit rebase -i HEAD~5です。


git rebase -i <hashbeforeyouwanttosquash>のコミットがある場合にこれを行う別の方法は、 git rebase -i <hashbeforeyouwanttosquash>ようなコミット後にスカッシュを行うことです

これはエディタを開いて通常のように選択/スカッシュします。

https://git-scm.com/docs/git-rebase#_interactive_modeを参照してください。


すべてのコミットを1回のコミットにまとめたい場合(プロジェクトを初めて公開する場合など)は、次のようにしてください。

git checkout --orphan <new-branch>
git commit

Anomiesの答えは良いですが、私はこれについて不安を感じましたので、私はいくつかのスクリーンショットを追加することにしました。

ステップ0:gitログ

あなたがgit logを使っているところを見てください。 最も重要なことは、スカッシュしたくない最初のコミットのコミットハッシュを見つけることです。 したがって、

ステップ1:git rebase

私の場合、 git rebase -i [your hash]実行しgit rebase -i [your hash]

$ git rebase -i 2d23ea524936e612fae1ac63c95b705db44d937d

ステップ2:あなたが望むものを選ぶ/スカッシュする

私の場合は、最初のコミットについてすべてをスカッシュしたい。 順序は最初から最後までです。つまり、 git log全く同じです。 私の場合、私はしたい:

ステップ3:メッセージを調整する

コミットを1つだけ選択して残りの部分を押しつぶした場合は、1つのコミットメッセージを調整できます。

それでおしまい。 これを保存すると( :wq )、完了です。 git logでそれを見てください。


このためにgit merge --squashを使うことができます。これはgit rebase -iよりやや洗練されていgit rebase -i 。 あなたがマスターしていて、最後の12回のコミットを1つに収縮させたいとします。

警告:まずgit statusがきれいであることを確認してください( git reset --hardは段階的な変更やgit reset --hardを捨てるので)

次に:

# Reset the current branch to the commit just before the last 12:
git reset --hard HEAD~12

# [email protected]{1} is where the branch was just before the previous command.
# This command sets the state of the index to be as it would just
# after a merge from that commit:
git merge --squash [email protected]{1}

# Commit those squashed changes.  The commit message will be helpfully
# prepopulated with the commit messages of all the squashed commits:
git commit

git mergeドキュメントでは、 - --squashオプションについて詳しく説明しています。

更新:より単純なgit reset --soft HEAD~12 && git commitよりもこのメソッドの唯一の本当の利点は、 彼の答えで Chris Johnsenが提案したgit reset --soft HEAD~12 && git commitです。あなたが潰しているすべてのコミットメッセージとともにコミットメッセージがあらかじめgit reset --soft HEAD~12 && git commitされています。


このようなワークフローに関連する質問の答えはどうですか?

  1. 多くのローカルコミット、 マスターからの複数のマージと混在
  2. そして、
  3. PRを行い、査読者がマスターに合併する。 (はい、開発者がmerge --squashする方が簡単です - PRの後にmerge --squashしますが、チームはプロセスが遅くなると考えました)

私はこのページのようなワークフローを見ていません。 (それは私の目であるかもしれません。) rebase正しく理解すると、複数のマージには複数の競合解決が必要です。 私はそれについて考えることさえしたくない!

だから、これは私たちのために働くようです。

  1. git pull master
  2. git checkout -b new-branch
  3. git checkout -b new-branch-temp
  4. ローカルでたくさんの編集とコミット、マスターの定期的なマージ
  5. git checkout new-branch
  6. git merge --squash new-branch-temp //すべての変更をステージに入れます
  7. git commit 'one message to rule them all'
  8. git push
  9. レビューアーはPRを行い、マスターにマージします。

これは超クーパーなのですが、一種のクールな方法で、私はただリングに投げます:

GIT_EDITOR='f() { if [ "$(basename $1)" = "git-rebase-todo" ]; then sed -i "2,\$s/pick/squash/" $1; else vim $1; fi }; f' git rebase -i foo~5 foo

翻訳:gitの新しい "エディタ"を提供します。編集するファイル名がgit-rebase-todo (対話型のrebaseプロンプト)の場合、最初の "pick"を除くすべてが "squash"に変更され、そうでなければvimが生成されます。潰れたコミットメッセージを編集するように指示されたら、vimを取得します。 (そして、明らかに、私はブランチfooの最後の5つのコミットを潰していましたが、あなたはそれを変更することができます。

私はおそらくマークロンエアーが提案したことをやっているだろう。


これを行うには、以下のgitコマンドを使用します。

 git rebase -i HEAD~n

n(ここでは4)は最後のコミットの番号です。 次に、以下のオプションがあります。

pick 01d1124 Message....
pick 6340aaa Message....
pick ebfd367 Message....
pick 30e0ccb Message....

以下のように更新してください。

p 01d1124 Message....
s 6340aaa Message....
s ebfd367 Message....
s 30e0ccb Message....

詳細はLinkクリックしてください

がんばろう!!


より一般的な解決法は、 'N'コミットを指定するのではなく、あなたがスカッシュしたいブランチ/コミットIDを見つけることです。 これは、特定のコミットまでコミットをカウントするのではなく、タグを直接指定するだけでなく、本当にカウントしたい場合はHEAD〜Nを指定することができます。

私のワークフローでは、ブランチを開始し、そのブランチでの最初のコミットが目標を要約します(つまり、通常、この機能のための最終メッセージとして公開リポジトリにプッシュします)。私は最初のメッセージにgit squash master戻したいと思っています。そして私はプッシュする準備ができています。

私は別名を使用します:

squash = !EDITOR="\"_() { sed -n 's/^pick //p' \"\\$1\"; sed -i .tmp '2,\\$s/^pick/f/' \"\\$1\"; }; _\"" git rebase -i

これにより、履歴が破棄される前にダンプされます。元に戻す場合は、コンソールから古いコミットIDを取得してリカバリすることができます。 (SolarisユーザーはGNU sed -iオプションを使用していることに注意してください。MacとLinuxのユーザーはこれでうまくいくはずです)。


クリス・ジョンセンの答えに基づいて、

bashからグローバルな "squash"エイリアスを追加してください:(Windowsの場合はGit Bash)

git config --global alias.squash '!f(){ git reset --soft HEAD~${1} && git commit --edit -m"$(git log --format=%B --reverse [email protected]{1})"; };f'

...またはWindowsのコマンドプロンプトを使用して:

git config --global alias.squash "!f(){ git reset --soft HEAD~${1} && git commit --edit -m\"$(git log --format=%B --reverse [email protected]{1})\"; };f"


~/.gitconfigこのエイリアスが含まれているはずです:

[alias]
    squash = "!f(){ git reset --soft HEAD~${1} && git commit --edit -m\"$(git log --format=%B --reverse [email protected]{1})\"; };f"


使用法:

git squash N

...最後のNコミットを含めて自動的に一緒に縮小します。

注:結果として得られるコミットメッセージは、すべての潰れたコミットを順番に組み合わせたものです。 あなたがそれに不満があるなら、あなたは常にgit commit --amendことができます - それは手動で変更することです。 (または、あなたの好みに合わせてエイリアスを編集します)。


ブランチでは、コミットを組み合わせて実行したい:

git rebase -i HEAD~(n number of commits back to review)

これによりテキストエディタが開き、これらのコミットを併合したい場合は、各コミットの前にある 'pick'を 'squash'で切り替える必要があります。 たとえば、すべてのコミットを1つにマージしようとしている場合、 'pick'は最初にコミットしたもので、それ以降のものはすべて 'squash'に設定する必要があります。 vimを使用している場合は、挿入モードでxを使用して、エディタを保存して終了します。

次に、リベースを終了します。

git rebase --continue

これと他のコミット履歴を書き換える方法については、 この便利な記事を参照してください


マスターブランチに切り替え、最新のものを確認してください:

sh git checkout master && git fetch && git pull

フィーチャーブランチをマスターブランチにローカルにマージします。

sh git merge feature_branch

ローカルマスタブランチを原点の状態にリセットします。

sh git reset origin/master

これであなたの変更のすべてがunstagedに変更されたものとみなされます。 1つ以上のコミットにステージングしてコミットできます。

sh git add . --all git commit


最後の10回のコミットを1回のシングルコミットにスカッシュするには:

git reset --soft HEAD~10 && git commit -m "squashed commit"

squashedされたコミットでリモートブランチを更新したい場合は、次のようにします。

git push -f

本当に便利なもの:
上にスカッシュしたいコミットハッシュをd43e15ます。例えば、 d43e15と言いd43e15

今すぐ使用する

git reset d43e15
git commit -am 'new commit name'

私はこれを行う最も簡単な方法は、新しいブランチをマスターから外し、マージを行うことです - 機能ブランチのスカッシュ。

git checkout master
git checkout -b feature_branch_squashed
git merge --squash feature_branch

その後、すべての変更をコミットする準備が整いました。


質問では、「最後」が意味するものが曖昧になる可能性があります。

たとえば、 git log --graphは次のように出力します(簡体字)。

* commit H0
|
* merge
|\
| * commit B0
| |
| * commit B1
| | 
* | commit H1
| |
* | commit H2
|/
|

最後に、時間によるコミットはH0、マージ、B0です。 それらをスカッシュするには、H1のコミット時にマージされたブランチをリベースする必要があります。

問題はH0にH1とH2が含まれていることです(通常はマージ前と分岐後にコミットします)。 したがって、少なくともH0、マージ、H1、H2、B0からの変更を管理する必要があります。

リベースを使用することは可能ですが、別の方法でリバースを使用することもできます。

rebase -i HEAD~2

これはあなたに選択肢のオプションを表示します(他の回答に記載されています):

pick B1
pick B0
pick H0

H0を選ぶのではなく、スカッシュを入れる:

pick B1
pick B0
s H0

保存して終了した後、rebaseはH1の後に順番にコミットを適用します。 つまり、競合をもう一度解決するように求められます(HEADは最初はH1になり、適用されるとコミットが蓄積されます)。

リベース終了後、あなたは押しつぶされたH0とB0のメッセージを選択できます:

* commit squashed H0 and B0
|
* commit B1
| 
* commit H1
|
* commit H2
|

PS BOにリセットするだけです(たとえば、 reset --mixedを使用している場合はhttps://.com/a/18690845/2405850詳しく説明していhttps://.com/a/18690845/2405850 )。

git reset --mixed hash_of_commit_B0
git add .
git commit -m 'some commit message'

H0、H1、H2のB0の変化にスカッシュされます(分岐後の変更とマージ前の変更は完全に失われます)。





git-squash