Gitリポジトリには400以上のコミットがあり、最初の数十は試行錯誤を繰り返しました。これらのコミットをクリーンアップして、多くを1つのコミットにまとめます。当然、git-rebaseを使用する方法のようです。私の問題は、マージの競合が発生し、これらの競合を簡単に解決できないことです。コミットを押しつぶしているだけなので(削除や並べ替えではないため)、なぜ競合が発生するのか理解できません。おそらく、これはgit-rebaseがどのように押しつぶされるかを完全には理解していないことを示しています。
これが私が使用しているスクリプトの修正版です。
repo_squash.sh(これは実際に実行されるスクリプトです):
rm -rf repo_squash
git clone repo repo_squash
cd repo_squash/
GIT_EDITOR=../repo_squash_helper.sh git rebase --strategy theirs -i bd6a09a484b8230d0810e6689cf08a24f26f287a
repo_squash_helper.sh(このスクリプトはrepo_squash.shでのみ使用されます):
if grep -q "pick " $1
then
# cp $1 ../repo_squash_history.txt
# emacs -nw $1
sed -f ../repo_squash_list.txt < $1 > $1.tmp
mv $1.tmp $1
else
if grep -q "initial import" $1
then
cp ../repo_squash_new_message1.txt $1
elif grep -q "fixing bad import" $1
then
cp ../repo_squash_new_message2.txt $1
else
emacs -nw $1
fi
fi
repo_squash_list.txt:(このファイルはrepo_squash_helper.shでのみ使用されます)
# Initial import
s/pick \(251a190\)/squash \1/g
# Leaving "Needed subdir" for now
# Fixing bad import
s/pick \(46c41d1\)/squash \1/g
s/pick \(5d7agf2\)/squash \1/g
s/pick \(3da63ed\)/squash \1/g
「新着メッセージ」の内容はご想像にお任せします。最初に、「-strategy theirs」オプションなしでこれを実行しました(つまり、ドキュメントを正しく理解している場合は再帰的ですが、どの再帰的戦略が使用されているのかわからないデフォルトの戦略を使用しています)。 t動作します。また、repo_squash_helper.sh内のコメント化されたコードを使用して、sedスクリプトが機能する元のファイルを保存し、それに対してsedスクリプトを実行して、意図したとおりに動作していることを確認しました(そうだった)。繰り返しになりますが、なぜ衝突が発生するのかさえわかりません。そのため、どの戦略を使用するかはそれほど重要ではないようです。アドバイスや洞察は役に立ちますが、ほとんどの場合、このつぶしを機能させたいだけです。
Jefromiとの議論からの追加情報で更新:
大規模な「実際の」リポジトリに取り組む前に、テストリポジトリで同様のスクリプトを使用しました。これは非常に単純なリポジトリであり、テストは問題なく機能しました。
失敗したときに表示されるメッセージは次のとおりです。
Finished one cherry-pick.
# Not currently on any branch.
nothing to commit (working directory clean)
Could not apply 66c45e2... Needed subdir
これは、最初のスカッシュコミット後の最初のピックです。実行git status
すると、クリーンな作業ディレクトリが生成されます。次にを実行するとgit rebase --continue
、さらに数回のコミットを行った後に、非常によく似たメッセージが表示されます。その後、再度実行すると、数十回のコミット後に非常によく似たメッセージが表示されます。もう一度やり直すと、今度は約100回のコミットが行われ、次のメッセージが表示されます。
Automatic cherry-pick failed. After resolving the conflicts,
mark the corrected paths with 'git add <paths>', and
run 'git rebase --continue'
Could not apply f1de3bc... Incremental
次にを実行するとgit status
、次のようになります。
# Not currently on any branch.
# Changes to be committed:
# (use "git reset HEAD <file>..." to unstage)
#
# modified: repo/file_A.cpp
# modified: repo/file_B.cpp
#
# Unmerged paths:
# (use "git reset HEAD <file>..." to unstage)
# (use "git add/rm <file>..." as appropriate to mark resolution)
#
# both modified: repo/file_X.cpp
#
# Changed but not updated:
# (use "git add/rm <file>..." to update what will be committed)
# (use "git checkout -- <file>..." to discard changes in working directory)
#
# deleted: repo/file_Z.imp
これは単なるピックの結果だったので、「両方変更された」ビットは奇妙に聞こえます。また、「競合」を見ると、1つのバージョンが[タブ]文字で始まり、もう1つのバージョンが4つのスペースがある1行に要約されることにも注意してください。これは、構成ファイルの設定方法に問題があるように思えますが、そのようなものはありません。(core.ignorecaseがtrueに設定されていることに注意しましたが、明らかにgit-cloneがそれを自動的に実行しました。元のソースがWindowsマシン上にあることを考慮しても、完全に驚くことはありません。)
file_X.cppを手動で修正すると、すぐに失敗し、別の競合が発生します。今回は、1つのバージョンが存在すると考えられるファイル(CMakeLists.txt)と、1つのバージョンが存在すると考えないファイルとの間で競合します。このファイルが必要だと言ってこの競合を修正すると(私はそうします)、数回コミットすると、(同じファイルで)別の競合が発生し、かなり重要な変更が加えられます。それはまだ紛争を乗り越える道のほんの約25%です。
これは非常に重要かもしれないので、このプロジェクトはsvnリポジトリで始まったことも指摘しておきます。その最初の履歴は、そのsvnリポジトリからインポートされた可能性が非常に高いです。
アップデート#2:
ひばり(Jefromiのコメントの影響を受けた)で、repo_squash.shを次のように変更することにしました。
rm -rf repo_squash
git clone repo repo_squash
cd repo_squash/
git rebase --strategy theirs -i bd6a09a484b8230d0810e6689cf08a24f26f287a
その後、元のエントリをそのまま受け入れました。つまり、「リベース」によって状況が変わってはなりません。以前に説明したのと同じ結果になりました。
アップデート#3:
または、戦略を省略して最後のコマンドを次のように置き換えた場合:
git rebase -i bd6a09a484b8230d0810e6689cf08a24f26f287a
「コミットするものがありません」というリベースの問題は発生しなくなりましたが、まだ他の競合が残っています。
問題を再現するおもちゃリポジトリで更新します。
test_squash.sh(これは実際に実行するファイルです):
#========================================================
# Initialize directories
#========================================================
rm -rf test_squash/ test_squash_clone/
mkdir -p test_squash
mkdir -p test_squash_clone
#========================================================
#========================================================
# Create repository with history
#========================================================
cd test_squash/
git init
echo "README">README
git add README
git commit -m"Initial commit: can't easily access for rebasing"
echo "Line 1">test_file.txt
git add test_file.txt
git commit -m"Created single line file"
echo "Line 2">>test_file.txt
git add test_file.txt
git commit -m"Meant for it to be two lines"
git checkout -b dev
echo Meaningful code>new_file.txt
git add new_file.txt
git commit -m"Meaningful commit"
git checkout master
echo Conflicting meaningful code>new_file.txt
git add new_file.txt
git commit -m"Conflicting meaningful commit"
# This will conflict
git merge dev
# Fixes conflict
echo Merged meaningful code>new_file.txt
git add new_file.txt
git commit -m"Merged dev with master"
cd ..
#========================================================
# Save off a clone of the repository prior to squashing
#========================================================
git clone test_squash test_squash_clone
#========================================================
#========================================================
# Do the squash
#========================================================
cd test_squash
GIT_EDITOR=../test_squash_helper.sh git rebase -i HEAD@{7}
#========================================================
#========================================================
# Show the results
#========================================================
git log
git gc
git reflog
#========================================================
test_squash_helper.sh(test_sqash.shで使用):
# If the file has the phrase "pick " in it, assume it's the log file
if grep -q "pick " $1
then
sed -e "s/pick \(.*\) \(Meant for it to be two lines\)/squash \1 \2/g" < $1 > $1.tmp
mv $1.tmp $1
# Else, assume it's the commit message file
else
# Use our pre-canned message
echo "Created two line file" > $1
fi
PS:はい、私がemacsをフォールバックエディタとして使用しているのを見ると、うんざりする人もいます。
PPS:リベース後に、既存のリポジトリのすべてのクローンを一掃する必要があることはわかっています。(「公開後にリポジトリをリベースしてはならない」の方針に沿って。)
PPPS:賞金をこれに追加する方法を誰かに教えてもらえますか?編集モードでも表示モードでも、この画面のどこにもオプションが表示されません。
rebase --interactive
これらは、gitが試行するアクションのリストのようなものです。これを、競合を引き起こしている単一のスカッシュに減らし、ヘルパースクリプトの余分な複雑さをすべて回避できることを望んでいました。他の不足している情報は、競合が発生したときです-gitがスカッシュを形成するためにパッチを適用するとき、またはスカッシュを通過して次のパッチを適用しようとするとき?(そして、あなたのGIT_EDITOR kludgeで何も悪いことが起こらないと確信していますか?単純なテストケースに対する別の投票です。)
rebase -p
とにかく使用していませんが)