私は通常、レビューのためにコミットのリストを提出します。次のコミットがある場合:
HEAD
Commit3
Commit2
Commit1
... head commit を で変更できることは知っていgit commit --amend
ます。しかし、それがコミットCommit1
ではない場合、どうすれば変更できますか?HEAD
私は通常、レビューのためにコミットのリストを提出します。次のコミットがある場合:
HEAD
Commit3
Commit2
Commit1
... head commit を で変更できることは知っていgit commit --amend
ます。しかし、それがコミットCommit1
ではない場合、どうすれば変更できますか?HEAD
git rebaseを使用できます。たとえば、 commit を変更する場合は、次bbc643cd
を実行します。
$ git rebase --interactive 'bbc643cd^'
コマンドの最後のキャレットに注意してください。実際には、変更したいコミットの前のコミット^
にリベースする必要があるためです。
デフォルトのエディターで、「bbc643cd」に言及している行を変更pick
します。edit
ファイルを保存して終了します。git はファイル内のコマンドを解釈して自動的に実行します。commit を作成したばかりの前の状況にいることに気付くでしょうbbc643cd
。
この時点で、bbc643cd
が最後のコミットであり、簡単に修正できます。変更を加えてから、次のコマンドでコミットします。
$ git commit --all --amend --no-edit
その後、次のように入力します。
$ git rebase --continue
前の HEAD コミットに戻ります。
警告: これにより、そのコミットとすべての子の SHA-1 が変更されることに注意してください。つまり、これにより、その時点からの履歴が書き換えられます。コマンドを使用してプッシュすると、これを行うリポジトリを壊すことができますgit push --force
git rebase -i @~9 # Show the last 9 commits in a text editor
目的のコミットを見つけて( ) に変更pick
し、ファイルを保存して閉じます。Git はそのコミットまで巻き戻して、次のいずれかを実行できるようにします。e
edit
git commit --amend
して変更を行う、またはgit reset @~
ファイルへの変更ではなく、最後のコミットを破棄するために使用します (つまり、ファイルを編集したが、まだコミットしていない時点に移動します)。後者は、複数のコミットに分割するなど、より複雑なことを行うのに役立ちます。
次に、 を実行するgit rebase --continue
と、Git は変更されたコミットに基づいて後続の変更を再生します。マージの競合を修正するよう求められる場合があります。
注:@
は の省略形でHEAD
あり~
、指定されたコミットの前のコミットです。
履歴の書き換えについて詳しくは、Git のドキュメントをご覧ください。
ProTip™: 履歴を書き換える「危険な」コマンドを試すことを恐れないでください* — Git はデフォルトで 90 日間コミットを削除しません。それらはreflogで見つけることができます:
$ git reset @~3 # go back 3 commits
$ git reflog
c4f708b HEAD@{0}: reset: moving to @~3
2c52489 HEAD@{1}: commit: more changes
4a5246d HEAD@{2}: commit: make important changes
e8571e4 HEAD@{3}: commit: make some changes
... earlier commits ...
$ git reset 2c52489
... and you're back where you started
*や などのオプションに注意してください — これらはデータを破棄する可能性があります。--hard
--force
* また、共同作業しているブランチの履歴を書き換えないでください。
多くのシステムでgit rebase -i
は、デフォルトで Vim が開きます。Vim は最新のテキスト エディターのようには機能しないため、Vim を使用してリベースする方法をご覧ください。別のエディターを使用したい場合は、 で変更してgit config --global core.editor your-favorite-text-editor
ください。
Interactive rebase with--autosquash
は、以前のコミットの履歴をより深く修正する必要があるときによく使用するものです。これは基本的に、ZelluX の回答が示すプロセスを高速化し、編集する必要があるコミットが複数ある場合に特に便利です。
ドキュメントから:
--autosquash
コミット ログ メッセージが「squash! … 」(または「fixup! … 」)で始まり、タイトルが同じ… で始まるコミットがある場合、rebase -i の todo リストを自動的に変更して、コミットが修正するコミットの直後にスカッシュのマークが付けられます
次のような履歴があるとします。
$ git log --graph --oneline
* b42d293 Commit3
* e8adec4 Commit2
* faaf19f Commit1
Commit2に修正したい変更があり、次を使用して変更をコミットします
$ git commit -m "fixup! Commit2"
または、コミット メッセージの代わりに commit-sha を使用すること"fixup! e8adec4
も、コミット メッセージのプレフィックスだけを使用することもできます。
次に、コミットのインタラクティブなリベースを開始してから
$ git rebase e8adec4^ -i --autosquash
エディターは、コミットが既に正しく順序付けられた状態で開きます
pick e8adec4 Commit2
fixup 54e1a99 fixup! Commit2
pick b42d293 Commit3
保存して終了するだけです
走る:
$ git rebase --interactive commit_hash^
それぞれ^
は、編集するコミットの数を示します。それが 1 つのみ (指定したコミット ハッシュ) の場合は、1 つ追加するだけ^
です。
Vim を使用して、変更したいコミットの単語pick
を変更し、保存して終了します( )。次に、git は、コミット メッセージを変更できるように、reword としてマークしたコミットごとにプロンプトを表示します。reword
:wq
:wq
次のコミットメッセージに移動するには、保存して終了する必要がある各コミットメッセージ
変更を適用せずに終了する場合は、 を押します。:q!
EDIT : ナビゲートするにはvim
、j
上k
に移動し、下に移動し、h
左に移動し、l
右に移動します (これらはすべてNORMAL
モードで、 を押しESC
てNORMAL
モードに移動します)。テキストを編集するには、 を押して、テキストを挿入するモードにi
入ります。INSERT
を押しESC
てモードに戻りNORMAL
ます:)
更新: github リストからのすばらしいリンクです。git で(ほぼ) 何かを元に戻す方法
これに使用しているエイリアスを共有したいと思いました。非対話型の対話型リベースに基づいています。これを git に追加するには、次のコマンドを実行します (以下に説明があります)。
git config --global alias.amend-to '!f() { SHA=`git rev-parse "$1"`; git commit --fixup "$SHA" && GIT_SEQUENCE_EDITOR=true git rebase --interactive --autosquash "$SHA^"; }; f'
または、ステージングされていないファイルも処理できるバージョン (stash してから un-stash することにより):
git config --global alias.amend-to '!f() { SHA=`git rev-parse "$1"`; git stash -k && git commit --fixup "$SHA" && GIT_SEQUENCE_EDITOR=true git rebase --interactive --autosquash "$SHA^" && git stash pop; }; f'
このコマンドの最大の利点は、no-vimであることです。
(1)もちろん、リベース中に競合がない場合
git amend-to <REV> # e.g.
git amend-to HEAD~1
git amend-to aaaa1111
名前amend-to
は適切なようです。フローを次のものと比較し--amend
ます。
git add . && git commit --amend --no-edit
# vs
git add . && git amend-to <REV>
git config --global alias.<NAME> '!<COMMAND>'
<NAME>
- git 以外のコマンドを実行するという名前のグローバル git エイリアスを作成します<COMMAND>
f() { <BODY> }; f
- 「匿名」bash 関数。SHA=`git rev-parse "$1"`;
- 引数を git リビジョンに変換し、結果を変数に割り当てますSHA
git commit --fixup "$SHA"
- の修正コミットSHA
。ドキュメントを見るgit-commit
GIT_SEQUENCE_EDITOR=true git rebase --interactive --autosquash "$SHA^"
git rebase --interactive "$SHA^"
一部は他の回答でカバーされています。--autosquash
と組み合わせて使用されるものです。詳細についてはドキュメントgit commit --fixup
を参照してくださいgit-rebase
GIT_SEQUENCE_EDITOR=true
全体を非インタラクティブにするものです。このハックは、このブログ投稿から学びました。なんらかの理由でインタラクティブ エディターが気に入らない場合は、 を使用できますgit rebase --onto
。
を変更したいとしますCommit1
。まず、before Commit1
から分岐します:
git checkout -b amending [commit before Commit1]
次に、次のようにグラブCommit1
しcherry-pick
ます。
git cherry-pick Commit1
次に、変更を修正して、次を作成しますCommit1'
。
git add ...
git commit --amend -m "new message for Commit1"
そして最後に、他の変更を隠した後、残りのコミットをmaster
新しいコミットの上に移植します。
git rebase --onto amending Commit1 master
読んでください:「リベース、ブランチに、 (非包括的)と(包括的)のamending
間のすべてのコミット」。つまり、Commit2 と Commit3 で、古い Commit1 を完全に切り捨てます。それらをチェリーピックすることもできますが、この方法の方が簡単です.Commit1
master
枝をきれいにすることを忘れないでください!
git branch -d amending
過去のコミットを頻繁に修正していることに気づき、そのためのスクリプトを書きました。
ワークフローは次のとおりです。
git commit-edit <commit-hash>
これにより、編集したいコミットにドロップされます。
そもそもコミットを修正してステージングします。
(git stash save
コミットしていないファイルを保持するために使用することができます)
でコミットをやり直します--amend
。例:
git commit --amend
リベースを完了します。
git rebase --continue
上記を機能させるには、次のスクリプトを実行可能ファイルに入れgit-commit-edit
ます$PATH
。
#!/bin/bash
set -euo pipefail
script_name=${0##*/}
warn () { printf '%s: %s\n' "$script_name" "$*" >&2; }
die () { warn "$@"; exit 1; }
[[ $# -ge 2 ]] && die "Expected single commit to edit. Defaults to HEAD~"
# Default to editing the parent of the most recent commit
# The most recent commit can be edited with `git commit --amend`
commit=$(git rev-parse --short "${1:-HEAD~}")
message=$(git log -1 --format='%h %s' "$commit")
if [[ $OSTYPE =~ ^darwin ]]; then
sed_inplace=(sed -Ei "")
else
sed_inplace=(sed -Ei)
fi
export GIT_SEQUENCE_EDITOR="${sed_inplace[*]} "' "s/^pick ('"$commit"' .*)/edit \\1/"'
git rebase --quiet --interactive --autostash --autosquash "$commit"~
git reset --quiet @~ "$(git rev-parse --show-toplevel)" # Reset the cache of the toplevel directory to the previous commit
git commit --quiet --amend --no-edit --allow-empty # Commit an empty commit so that that cache diffs are un-reversed
echo
echo "Editing commit: $message" >&2
echo