リポジトリ全体を最初のコミットまでどうやって潰すのですか?
最初のコミットにリベースできますが、2つのコミットが残ります。最初のコミットの前にコミットを参照する方法はありますか?
--root
はありません(スカッシュするコミットがたくさんある場合、実際にはすべてのコミットをスカッシュする最善の解決策ではありません):Gitリポジトリの最初の2つのコミットを結合しますか?。
リポジトリ全体を最初のコミットまでどうやって潰すのですか?
最初のコミットにリベースできますが、2つのコミットが残ります。最初のコミットの前にコミットを参照する方法はありますか?
--root
はありません(スカッシュするコミットがたくさんある場合、実際にはすべてのコミットをスカッシュする最善の解決策ではありません):Gitリポジトリの最初の2つのコミットを結合しますか?。
回答:
おそらく最も簡単な方法は、作業コピーの現在の状態で新しいリポジトリを作成することです。すべてのコミットメッセージを保持する場合は、最初に実行して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
git rebase -i --root
。参照:stackoverflow.com/a/9254257/109618
以下のようにgit 1.6.2は、使用することができますgit rebase --root -i
。
最初のコミットを除く各コミットについて、に変更pick
しsquash
ます。
squash
すべてのコミットに使用しないでください。一番最初のものはする必要がありますpick
。
エイリアスを作成しました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"
警告:コメントを提供することを忘れないでください。そうしないと、デフォルトのコミットメッセージ「新しいスタート」が使用されます。
または、次のコマンドでエイリアスを作成できます。
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
」は単なる例です。自分の言語を自由に使用してください。
スカッシュする必要はありませんgit commit-tree
。孤立したコミットを作成してそれを使用するために使用します。
を介して単一のコミットを作成する git commit-tree
何git commit-tree HEAD^{tree} -m "A new start"
が:
指定されたツリーオブジェクトに基づいて新しいコミットオブジェクトを作成し、新しいコミットオブジェクトIDをstdoutに出力します。-mまたは-Fオプションが指定されていない限り、ログメッセージは標準入力から読み取られます。
この式HEAD^{tree}
は、に対応するツリーオブジェクトHEAD
、つまり現在のブランチの先端を意味します。Tree-ObjectsおよびCommit-Objectsを参照してください。
現在のブランチを新しいコミットにリセットする
次に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
またはその他)として追加することが回避され、テンプレートリポジトリの履歴が最初のコミットに折りたたまれます。
git push -f
伝播に使用します。
git clone
。あなたが追加した場合--hard
にgit reset
、スイッチHEAD
とFETCH_HEAD
してgit commit-tree
、あなたは、最初に作成できるテンプレートのレポをフェッチした後にコミットします。これを示す最後のセクションで回答を編集しました。
${1?Please enter a message}
すべてのコミットをルートコミットに押しつぶすだけの場合は、
git rebase --interactive --root
リベース操作はおそらく非常に遅く実行されてインタラクティブなリベースエディタのコミットリストを生成するだけでなく、リベース自体を実行するため、多数のコミット(たとえば、数百のコミット)には実用的ではありません。
多数のコミットを押しつぶしているときの2つのより速くより効率的なソリューションを次に示します。
現在のブランチの先端(つまり、最新のコミット)に新しい孤立したブランチを作成するだけです。この孤立したブランチは、まったく新しい別のコミット履歴ツリーの最初のルートコミットを形成します。これは、すべてのコミットを押しつぶすことと実質的に同等です。
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
ドキュメンテーション:
別の効率的な解決策は、ルートコミットに対して混合リセットまたはソフトリセットを使用すること<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
ドキュメンテーション:
git push origin master --force
。
git push --force
echo "message" | git commit-tree HEAD^{tree}
これにより、HEADのツリーで孤立したコミットが作成され、その名前(SHA-1)がstdoutに出力されます。次に、ブランチをリセットします。
git reset SHA-1
git reset $(git commit-tree HEAD^{tree} -m "commit message")
簡単になります。
echo "message" | git commit-tree "HEAD^{tree}"
他の誰かのためにうまくいく場合に備えて、これが私がこれをやった方法です:
このようなことには常にリスクがあり、開始する前に保存ブランチを作成することは決して悪い考えではないことを覚えておいてください。
ロギングから始める
git log --oneline
最初のコミットまでスクロールし、SHAをコピーします
git reset --soft <#sha#>
<#sha#>
ログからコピーされたSHAを置き換えます
git status
すべてが緑色であることを確認します。それ以外の場合は実行します git add -A
git commit --amend
現在のすべての変更を現在の最初のコミットに修正します
このブランチを強制的にプッシュすると、そこにあるものが上書きされます。
まず、を使用して、すべてのコミットを1つのコミットに圧縮しgit rebase --interactive
ます。これで、スカッシュへの2つのコミットが残りました。これを行うには、
git checkout --orphan new_root_branch && git commit
git help checkout
について--orphan
git help checkout --orphan
バックアップを作成する
git branch backup
指定したコミットにリセット
git reset --soft <#root>
次に、すべてのファイルをステージングに追加します
git add .
メッセージを更新せずにコミット
git commit --amend --no-edit
押しつぶされたコミットで新しいブランチをリポジトリにプッシュする
git push -f
<root>
リセットしたコミットになります。git commit --amend --no-edit
現在のコミットに対するすべての変更を<root>
コミットします。コミットメッセージを編集する必要はありません。
この回答は、1つのコミット(no-parents no-history)の作成に加えて、そのコミットのすべてのcommit-data も保持したい場合を想定して、上記の2つを改善します(投票してください)。
もちろん、新規/単一コミットのcommit-SHAは変更されます。これは、新しい(非)履歴を表し、親なし/ root-commitになるためです。
これはgit log
、のいくつかの変数を読み取って設定することで実行できますgit commit-tree
。上記のcommit-dataを保持したまま、master
新しいブランチから単一のコミットを作成するとしますone-commit
。
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
')
私にとっては、次のように機能しました。合計4つのコミットがあり、インタラクティブなリベースを使用しました。
git rebase -i HEAD~3
一番最初のコミットが残っており、私は最新のコミットを3つ取りました。
次に表示されるエディターで立ち往生している場合は、次のように表示されます。
pick fda59df commit 1
pick x536897 commit 2
pick c01a668 commit 3
あなたは最初のコミットを取り、それに他の人をつぶす必要があります。あなたが持っているべきものは:
pick fda59df commit 1
squash x536897 commit 2
squash c01a668 commit 3
そのためには、INSERTキーを使用して「挿入」モードと「編集」モードを変更します。
エディタを保存して終了するには、を使用します:wq
。カーソルがこれらのコミット行の間または他の場所にある場合は、ESCを押して再試行してください。
結果として、2つのコミットがありました。1つ目は残ったコミット、もう1つは「これは3つのコミットの組み合わせです」というメッセージが表示されます。
詳細はこちらで確認してください:https : //makandracards.com/makandra/527-squash-several-git-commits-into-a-single-commit
私は通常、次のようにします。
すべてがコミットされていることを確認し、問題が発生した場合に備えて最新のコミット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
して変更を強制的にプッシュします