web-dev-qa-db-ja.com

すべてのgitコミットを1つにまとめるにはどうすればいいですか?

リポジトリ全体を最初のコミットまでどのように縮小しますか?

私は最初のコミットにリベースすることができます、しかしそれは私に2コミットを残すでしょう。最初のコミットの前にコミットを参照する方法はありますか?

391
Verhogen

おそらく最も簡単な方法は、作業コピーの現在の状態で新しいリポジトリを作成することです。すべてのコミットメッセージを保持したい場合は、まずgit log > original.logを実行してから、新しいリポジトリの最初のコミットメッセージ用にそれを編集します。

rm -rf .git
git init
git add .
git commit

または

git log > original.log
# edit original.log as desired
rm -rf .git
git init
git add .
git commit -F original.log
120
Pat Notz

最近のバージョンのgitでは、git rebase --root -iを使うことができます。

最初のコミット以外のコミットごとに、picksquashに変更します。

571
Jordan Lewis

更新

私はエイリアスgit squash-allを作りました。
使用例git squash-all "a brand new start"

[alias]
  squash-all = "!f(){ git reset $(git commit-tree HEAD^{tree} -m \"${1:-A new start}\");};f"

警告:コメントを忘れずに入力してください。そうしないと、デフォルトのコミットメッセージ "A new start"が使用されます。

あるいは、次のコマンドでエイリアスを作成することができます。

git config --global alias.squash-all '!f(){ git reset $(git commit-tree HEAD^{tree} -m "${1:-A new start}");};f'

ワンライナー

git reset $(git commit-tree HEAD^{tree} -m "A new start")

:ここでの "A new start"は一例です。自分の言語を使用してください。

TL、DR

スカッシュする必要はありません。git commit-treeを使用して孤立コミットを作成し、それを実行します。

説明する

  1. git commit-treeを介して単一のコミットを作成する

    git commit-tree HEAD^{tree} -m "A new start"がすることは、

    提供されたツリーオブジェクトに基づいて新しいコミットオブジェクトを作成し、新しいコミットオブジェクトIDを標準出力に発行します。 -mまたは-Fオプションが指定されていない限り、ログメッセージは標準入力から読み取られます。

    HEAD^{tree}は、HEADに対応するツリーオブジェクト、つまり現在のブランチの先端を意味します。 Tree-Objects および Commit-Objects を参照してください。

  2. 現在のブランチを新しいコミットにリセットする

    それからgit resetは単に現在のブランチを新しく作成されたコミットオブジェクトにリセットします。

このようにして、ワークスペースの何も手を加えられたり、リベース/スカッシュの必要がなくなり、本当に速くなります。そして必要な時間は、リポジトリのサイズや履歴の深さとは無関係です。

バリエーション:プロジェクトテンプレートからの新しいリポジトリ

これはtemplate/archetype/seed/skeletonとして他のリポジトリを使って新しいプロジェクトで "初期コミット"を作成するのに役立ちます。例えば:

cd my-new-project
git init
git fetch --depth=1 -n https://github.com/toolbear/panda.git
git reset --hard $(git commit-tree FETCH_HEAD^{tree} -m "initial commit")

これにより、テンプレートレポジトリをリモート(Originなど)として追加することを避け、テンプレートレポジトリの履歴を最初のコミットにまとめます。

269
ryenus

あなたがしたいのがあなたのコミットの全てをルートコミットまで押しつぶすことであるならば、

git rebase --interactive --root

なぜなら、リベース操作は対話式リベースエディタのコミットリストを生成するのに非常にゆっくりと実行され、リベース自体も実行されるからです。

大量のコミットを回避している場合の、2つのより速くより効率的な解決策は次のとおりです。

代替ソリューション#1:孤児の枝

現在のブランチの先端(つまり最新のコミット)に新しいOrphanブランチを作成するだけです。このOrphanブランチは、まったく新しい個別のコミット履歴ツリーの初期ルートコミットを形成します。これは、すべてのコミットを潰すのと実質的に同じです。

git checkout --Orphan new-master master
git commit -m "Enter commit message for your new initial commit"

# Overwrite the old master branch reference with the new one
git branch -M new-master master

ドキュメンテーション:

代替ソリューション#2:ソフトリセット

もう1つの効率的な解決策は、単純にルートコミット<root>への混合リセットまたはソフトリセットを使用することです。

git branch beforeReset

git reset --soft <root>
git commit --amend

# Verify that the new amended root is no different
# from the previous branch state
git diff beforeReset

ドキュメンテーション:

146
user456814
echo "message" | git commit-tree HEAD^{tree}

これはHEADのツリーで孤立したコミットを作成し、その名前(SHA-1)を標準出力に出力します。それからブランチをリセットしてください。

git reset SHA-1
46
kusma

これが他の人のために機能するのを念のために、私がこれをやってしまった方法は次のとおりです。

このようなことをすることには常にリスクがあることを忘れないでください。開始する前にsaveブランチを作成することは決して悪い考えではありません。

ログ記録から始める

git log --oneline

最初のコミットまでスクロールし、SHAをコピーする

git reset --soft <#sha#>

ログからコピーしたSHAを付けて<#sha#>を置き換えます

git status

すべてが緑色であることを確認し、そうでなければgit add -Aを実行してください。

git commit --amend

現在のすべての変更を現在の最初のコミットに修正する

今すぐこのブランチをプッシュすると、そこにあるものが上書きされます。

36
Logan

最も簡単な方法は、現在のブランチを削除するために 'plumbing'コマンドupdate-refを使うことです。

現在のブランチを削除するのを防ぐ安全弁があるので、git branch -Dを使用することはできません。

これにより、あなたは新たな初期コミットから始めることができる「初期コミット」状態に戻ります。

git update-ref -d refs/heads/master
git commit -m "New initial commit"
32
CB Bailey

私は移植片を使うことについて何かを読んだが、それをあまり調べなかった。

とにかく、あなたはこれらの最後の2つのコミットを次のようなもので手動で潰すことができます:

git reset HEAD~1
git add -A
git commit --amend
28

まず、git rebase --interactiveを使用して、すべてのコミットを単一のコミットにまとめます。今、あなたはスカッシュするために2つのコミットを残しました。そうするために、のいずれかを読んでください

16
Frerich Raabe

6ワード1行に

git checkout --Orphan new_root_branch  &&  git commit
10
kyb

移植片を使って潰すには

ファイル.git/info/graftsを追加し、そこにあなたのルートになりたいコミットハッシュを置きます。

git logはそのコミットから始まります

それを '本当の'ものにするためにはgit filter-branchを実行してください。

4
dimus

バックアップを作成する

git branch backup

指定したコミットにリセット

git reset --soft <#root>

その後、すべてのファイルをステージングに追加します

git add .

メッセージを更新せずにコミットする

git commit --amend --no-edit

圧縮されたコミットで新しいブランチにリポジトリをプッシュする

git Push -f
3
David

この答えは上記の2つの方法で改善されています(投票してください)。1つのコミットを作成する(親なし、履歴なし)のに加え、あなたはすべてのコミットデータを保持したいと思いますそのコミットの

  • 作者(名前とメールアドレス)
  • 作成日
  • コミッター(名前とEメール)
  • 確定日
  • ログメッセージの送信

もちろん、new/singleコミットのcommit-SHAは変わります。なぜなら、それは新しい(非)履歴を表し、親のない/ root-commitになるからです。

これはgit logを読み、git commit-treeのためにいくつかの変数を設定することによって行うことができます。上記のcommit-dataを保持したまま、新しいブランチone-commitmasterから単一のコミットを作成したいと仮定します。

git checkout -b one-commit master ## create new branch to reset
git reset --hard \
$(eval "$(git log master -n1 --format='\
COMMIT_MESSAGE="%B" \
GIT_AUTHOR_NAME="%an" \
GIT_AUTHOR_EMAIL="%ae" \
GIT_AUTHOR_DATE="%ad" \
GIT_COMMITTER_NAME="%cn" \
GIT_COMMITTER_EMAIL="%ce" \
GIT_COMMITTER_DATE="%cd"')" 'git commit-tree master^{tree} <<COMMITMESSAGE
$COMMIT_MESSAGE
COMMITMESSAGE
')
1
javabrett

私は通常このようにします:

  • すべてがコミットされていることを確認し、問題が発生した場合に備えて最新のコミットIDを書き留めるか、バックアップとして別のブランチを作成します。

  • git reset --soft `git rev-list --max-parents=0 --abbrev-commit HEAD`を実行して頭を最初のコミットにリセットしますが、インデックスは変更しません。最初のコミット以降のすべての変更はコミットする準備ができているように見えます。

  • コミットを最初のコミットに修正してコミットメッセージを変更する場合はgit commit --amend -m "initial commit"を実行します。既存のコミットメッセージをそのまま使用する場合はgit commit --amend --no-editを実行します。

  • git Push -fを実行して変更をプッシュする