git stash -p
Git 2.17(2018年第2四半期)で失敗が少なくなるはずです。
その前は、 " git add -p
"(とロジックを共有しgit stash
ている)は、結果を基になる ""に渡す前に、分割パッチの合体に怠惰でありgit apply
、コーナーケースのバグにつながりました。ハンクの選択が厳しくされた後に適用されるパッチを準備するロジック。
Phillip Wood()によるcommit 3a8522f、commit b3e0fcf、commit 2b8ea7f(2018年3月5日)、commit fecc6f3、commit 23fea4c、commit 902f414(01 Mar 2018)、およびcommit 11489a6、commit e4d671c、commit 492e60c(2018年2月19日)を参照してください。(濱野純雄による合併---コミット436d18f、2018年3月14日)phillipwood
gitster
add -p
:1つがスキップされたときに、後続のハンクのオフセットを調整します
(追加しますが、ここでも、スタッシュに適用できます)
commit 8cbd431(" git-add--interactive
:ハンクの再カウントをapply --recountに置き換えます"、2008-7-2、Git v1.6.0-rc0)なので、ハンクがスキップされた場合、コンテキスト行に依存して後続のハンクを適切な場所に適用します。
これはほとんどの場合機能しますが、ハンクが間違った場所に適用される可能性があります。
これを修正するには、後続のハンクのオフセットを調整して、スキップされたハンクによる挿入または削除の数の変化を修正します。挿入または削除の数が変更された編集済みハンクによるオフセットの変更は、ここでは無視され、次のコミットで修正されます。
ここでいくつかのテストを見ることができます。
Git 2.19の改善git add -p
:ユーザーが " git add -p
"でパッチを編集し、ユーザーのエディターが末尾の空白を無差別に削除するように設定されている場合、パッチで変更されていない空の行は完全に空になります(SPが1つしかない行ではありません)。
Git 2.17の時間枠で導入されたコードは、そのようなパッチの解析に失敗しましたが、今では状況に気づき、それに対処することを学びました。
Phillip Wood()によるcommit f4d35a6(2018年6月11日)を参照してください。( Junio C Hamanoによってマージされました---コミット5eb8da8、2018年6月28日)phillipwood
gitster
add -p
:編集されたパッチの空のコンテキスト行のカウントを修正
recount_edited_hunk()
commit 2b8ea7f ( "add -p:編集されたパッチのオフセットデルタの計算"、2018-03-05、Git v2.17.0)で導入されたものでは、すべてのコンテキスト行がスペースで始まる必要があり、空の行はカウントされません。
これは、ユーザーがパッチの編集時に最後に空の行を導入した場合の再カウントの問題を回避することを目的としています。
ただしgit add -p
、パッチを編集するときに編集者が空のコンテキスト行から末尾の空白を削除して、カウントする必要のある空の行を導入するのが一般的であるため、これにより''に回帰が導入されました。
「gitapply」はそのような空の行を処理する方法を知っており、POSIXは、空のコンテキスト行にスペースがあるかどうかは実装で定義されていると述べています(diffコマンドを参照)。
改行のみで構成される行と、スペースで始まる行をコンテキスト行としてカウントすることで回帰を修正し、将来の回帰を防ぐためのテストを追加します。
Git 2.23(Q3 2019)は、パッチを逆に選択的に適用する必要があるgit add -p
""によって使用されるを改善しgit checkout -p
ます。以前はうまく機能しませんでした。
Phillip Wood()によるcommit 2bd69b9(2019年6月12日)を参照してください。( Junio C Hamanoによってマージされました---コミット1b074e1、2019年7月9日)phillipwood
gitster
add -p
checkout -p
:病理学的コンテキストで修正
コミットfecc6f3( " add -p
:スキップされたときに後続のハンクのオフセットを調整する"、2018-03-01、Git v2.17.0-rc0)は、前のハンクがスキップされたときに正しい場所にハンクを追加することを修正しました。
ただし、逆に適用されるパッチには対応していません。
その場合、パッチを逆に適用したときにポストイメージオフセットが正しく調整されるように、プレイメージオフセットを調整する必要があります。
パッチが逆になっているため、デルタを加算するのではなく減算します(これを考える最も簡単な方法は、スキップされた削除の塊を検討することです。その場合、オフセットを減らしたいので、減算する必要があります)。
Git 2.25(2020年第1四半期)では、" git-add--interactive
"PerlスクリプトをCに移行する取り組みが続いています。
その結果、上記の修正が再実装されます。
commit 2e40831、commit 54d9d9b、commit ade246e、commit d6cf873、commit 9254bdf、commit bcdd297 、 commit b38dd9e 、 commit 11f2c0d、commit 510aeca、commit 0ecd9d2、commit 5906d5d 、commit 47dc4fd 、commit 80399 e3bd11b、commit 1942ee4、commit f6aa7ec(2019年12月13日)Johannes Schindelin(dscho
)。( Junio C Hamano
によってマージされました---コミット45b96a6、2019年12月25日)gitster
サインオフ-作成者:Johannes Schindelin
削除する行数とは異なる行数を追加するハンクをスキップする場合、スキップされないハンクの後続のハンクヘッダーを調整する必要があります。病理学的な場合、コンテキストはパッチを適用する場所を正確に決定するのに十分ではありません。
この問題は23fea4c240( " t3701
:add
病理学的コンテキスト行のテストに失敗しました"、2018-03-01、Git v2.17.0-rc0 --merge )で識別され、 fecc6f3a68のPerlバージョンで修正されました( " add -p
:後続のハンクのオフセットを調整する場合1つはスキップされます」、2018-03-01、Git v2.17.0-rc0 --merge )。
そして、このパッチはのCバージョンでそれを修正しgit add -p
ます。
Perlバージョンとは対照的に、ハンクヘッダー(通常、ハンク内でコードが変更される関数のシグネチャを含む)の余分なテキストをそのまま維持しようとします。
注:Cバージョンはこの段階でステージングモードの変更をサポートしていませんが、古いオフセットと新しいオフセットの両方が0の場合はハンクヘッダーをスキップするだけでこれに備えています(これは通常のハンクでは発生しないため、これを特別な塊を見ていることを示すインジケーター)。
同様に、ハンクヘッダーに余分なテキストがないことを適切に処理することで、ハンク分割の準備をすでに行っています。最初の分割されたハンクだけがそのテキストを持ち、他の部分は持っていません(空の余分なテキストの開始/終了範囲で示されます)。この段階ですでにハンク分割の準備をすることで、後でハンクヘッダー印刷ブロック全体のインデントを変更する必要がなくなり、その処理を行わない場合とほぼ同じように簡単に確認できます。
git stash -p
Git 2.27(2020年第2四半期)より前では、「 」がうまく機能していないときにユーザーがパッチハンクを分割できるようになりました。これを(部分的に)より良く機能させるために、バンドエイドが追加されました。
Johannes Schindelin()によるcommit 7723436、commit 121c0d4(2020年4月8日)を参照してください。(濱野純雄による合併---コミットe81ecff、 2020年4月28日)dscho
gitster
stash -p
:(部分的に)スプリットハンクに関するバグを修正
サインオフ-作成者:Johannes Schindelin
ハンクを分割し、分割されたビットとピースを部分的にのみ受け入れることによってワークツリーの変更の一部を隠そうとすると、ユーザーにはかなり不可解なエラーが表示されます。
error: patch failed: <file>:<line>
error: test: patch does not apply
Cannot remove worktree changes
また、コマンドは、ワークツリーの変更の目的の部分を隠しておくことができません(stash
参照が実際に正しく更新された場合でも)。
その失敗を実証するテストケースもあり、すでに4年間使用しています。
説明:ハンクを分割するとき、変更された行は3行(Gitのdiffがデフォルトで使用するコンテキスト行の量)を超えて区切られなくなりますが、それより少なくなります。
したがって、diffハンクの一部のみをスタッシュするためにステージングする場合、逆にワークツリーに適用する結果のdiffには、3つのコンテキスト行で囲まれたドロップされる変更が含まれますが、diffはワークツリー、これらのコンテキスト行は一致しません。
時間の例。ファイルREADMEに次の行が含まれていると仮定します。
We
the
people
ワークツリーは、代わりにこれらの行を含むようにいくつかの行を追加しました。
We
are
the
kind
people
ユーザーが「are」を含む行を隠そうとすると、コマンドはこの行を一時的なインデックスファイルに内部的にステージングし、HEADとそのインデックスファイル間の差分を元に戻そうとします。元に戻そうとする
diffハンクは次のようになります。git stash
@@ -1776,3 +1776,4
We
+are
the
people
これで、末尾のコンテキスト行が、ユーザーが隠したくない元の差分ハンクの部分と重なっていることは明らかです。
diffのコンテキスト行は、diffが正確に適用されない場合(ただし、パッチを適用するファイルの正確な行番号がdiffに示されている行番号と異なる場合)、正確な場所を見つけるという主な目的を果たします。これを回避するには、コンテキスト行の量を減らします。差分が生成されたばかりです。
注:これは問題の完全な修正ではありません。
t3701の「add-pは病理学的コンテキストラインで機能する」テストケースで示されているように、diff形式にはあいまいさがあります。もちろん、実際には、このような繰り返しの行に遭遇することは非常にまれです。
このような場合の完全な解決策は、スタッシュから差分を生成し、それをエミュレートすることによって逆に適用するgit revert
(つまり、3方向マージを行う)アプローチを置き換えることです。ただし、これはワークツリーにgit stash -p
は適用されませんがHEAD
、代わりにワークツリーに適用されます。これにより、スクリプトバージョンのを維持している限り、これを実装するのは簡単ではありませんadd -i
。
Git 2.29(2020年第4四半期)は、git add -p
(によって使用されるstash -p
)にリークフィックスをもたらします
Phillip Wood()によるcommit 324efcf(2020年9月7日)を参照してください。( Junio C Hamanoによってマージされました---コミット3ad8d3e、2020年9月18日)phillipwood
gitster
サインオフ-作成者:Phillip Wood
Acked-作成者:Johannes Schindelin
asanは、のCバージョンがadd -p
割り当てたすべてのメモリを解放していないことを報告しています。
struct
add_p_state``をクリアし、個々のメンバーを解放する代わりにそれを使用する関数を導入することにより、これを修正します。