この記事はプログラミング学習者がアプリ開発中に躓いた内容を備忘録として記事におこしたものです。内容に不備などあればご指摘頂けると助かります。
失敗談1:mainブランチが消えてしまった
Github上にリモートリポジトリを新規作成し、ローカルでも対応するリポジトリを作成しました。
git initしてgitによる管理をスタート
その後にgit checkout -b branchAとしてmainブランチから移動して作品を作っていたのですが、
途中でmainブランチに戻ろうと思って、git checkout main と実行したところ、
error: pathspec 'main' did not match any file(s) known to git
というエラーが発生してしまいました。
git branchをしてもブランチは何も表示されませんでした。
原因としてはgit init した後にgit cloneでリモートリポジトリの内容を複製していなかった事が挙げられます。
対処法として以下のコマンドを実行しました。
git fetch origin でリモートリポジトリの内容を取得
git checkout -b main origin/main でリモートリポジトリのmainブランチの内容を元にローカルリポジトリにmainブランチを作って移動する
ここで元々いたbranchAがmainブランチに変わってしまい、リポジトリ内のファイル類もリモートリポジトリの内容とbranchAの内容が混ざってしまいました。
ここでgit branch -m main branchA でmainブランチを branchAに書き換えました。
その後に再度下記のコマンドを実行
git fetch origin
git checkout -b main origin/main
ここでgit branch を実行するとmainとbranchAの2つのブランチが出現して望んでいた内容になりました。
ただし、ここで作成されたmainとbranchAが完全に同期してしまいました。
例えば、mainブランチでgit stash -u を実行してコミットできる内容を一時的に退避すると、branchAでも同じようにgit stasu -u を実行された状態になってしまいました。
この問題に対して、
git checkout branchA-backupとして、新しいブランチを作成した後に
git stash pop stash@{0}で一時退避していたファイルを復帰させました。
git add .
git commit -m "コミットメッセージ"
git push -u origin branchA
と、一度リモートリポジトリにPushしてコミット歴を作りました。
-uオプションではローカルリポジトリのbranchAとリモートリポジトリのbranchAの間にトラッキング関係を作ります。
この処理をすることで、ローカルリポジトリ内のmainブランチとbranchAの中身が区別されるようになりました。
冒頭にも記載しましたが、この問題の根本的な原因は初期段階でgit cloneを実行していなかったことです。
git cloneをしなかった経緯ですが、リモートリポジトリを空の状態で作ったので、git cloneしてデータを継承する必要性を感じなかったことが挙げられます。
今後の学習に活かしていきたいと思います。
失敗談2:リモートリポジトリのmainブランチに直接Pushしてしまった。
これはうっかりやってしまったのですが、うっかりやってしまったにしては大きなミスだと認識しています。
ちょっとした成果物を完成させて、PRを通してコードレビューを受ける為にリモートリポジトリへPushする時の話です。
通常であればリモートリポジトリのmainブランチへは直接Pushせずに開発用の別ブランチを作成して、そこからリモートリポジトリへ同じ名前でPushして、Pull Requestを作成し、レビューを受けてからmainブランチにMergeするというのが基本的な流れです。
mainブランチへ直接Pushしてしまうということは内容が間違っていたり、不具合の可能性を孕んでいてもお構いなしにMergeしてしまうことを意味しており、とても危険な行為です。
今回の場合、リモートリポジトリは空の状態でしたので、コンフリクトなどは発生しないのですが、複数人で行なっている開発案件などで同じ行為をしたことを想像するとゾッとします。
以下はmainブランチへPushしてしまった後に実行した内容です。
mainブランチ
git update-ref -d HEAD 初回コミットの内容を取り消す
git rm --cached ファイル名 リモートリポジトリのmainブランチにPushしてしまった内容を削除する
※ --cachedをつけることでリモートリポジトリのファイルだけを削除する。
このオプションが無い場合はローカルリポジトリの同名ファイルも削除してしまうので注意が必要
git add .
git commit コミットメッセージ
git push origin main Pushまですることで削除の操作をリモートリポジトリに反映できる
git stash -u ローカルリポジトリのmainブランチにあるファイル類を一時退避
git checkout -b calender
git add .
git commit -m コミットメッセージ
git push origin calender リモートリポジトリにcalenderブランチを作り、Pushする
ここでリモートリポジトリのmainブランチへcalenderブランチからPull Requestを出そうとしましたが、下記のエラーメッセージが出ました。
There isn’t anything to compare.
main and calender are entirely different commit histories.
mainブランチとcalenderブランチは全く異なるものなので、比較できません。という内容
※この時、リモートリポジトリのmainブランチは空の状態でした。
この時、以下のコマンドを実行することで、ローカルリポジトリの各ブランチとリモートリポジトリの各ブランチの関連状況を確認しました。
ローカルリポジトリのcalenderブランチはリモートリポジトリと関連付けできていないことが下のコマンド結果から確認することができます。
git branch -vv
* calender d0a8d39 first commit
main fd4745e [origin/main] Remove files from remote repository
次に下記のコマンドを実行することでリモートリポジトリとローカルリポジトリのcalenderブランチを関連づけることにしました。
git branch --set-upstream-to=origin/calender calender
この後、関連付けの確認をしたところ、意図した通りに設定することができました。
git branch -vv
* calender d0a8d39 [origin/calender] first commit
main fd4745e [origin/main] Remove files from remote repository
ただし、これらのコマンドを実行してもエラーは変わらず表示されてしまいました。
There isn’t anything to compare.
main and calender are entirely different commit histories.
calenderブランチに対して関連付けを行いましたが、状況は改善されないままです。
ここでエラー文からmainブランチとcalenderブランチの履歴が完全に異なっていることが原因と考えました。
次に以下の順番でコマンドを実行しました。
git checkout main
git pull origin main
2行目の--allow-unrelated-histories
オプションは共通の祖先を持たないブランチ同士のマージを可能にします。これにより独立して開始された2つのプロジェクトの履歴をマージすることができます。
gitは指定されたブランチ(下の例ではmain)の履歴と現在のブランチ(calender)の履歴を比較します。
共通の祖先がない場合でも両方の履歴を組み合わせて新しいマージコミットを作成します。
git checkout calender
git merge main --allow-unrelated-histroies
この後に、
git push origin calender
を実行しました。特にファイルは変更していなかったので、git addとgit commitは未実施。
上記のコマンドを実行したところ、mainとcalenderの間でコードの比較ができるようになり、Pull Requestをオープンできるようになりました。
そう言えば、この問題でも初期段階でgit cloneを実行していなかったような...
上記2つの失敗談ではリモートリポジトリを作成しても中身は空で後から中身を作り上げていくという状況でした。今まではローカルリポジトリの中に重要なデータが入っていることも多く、git clone
するのが当たり前のよう作業していましたが、今回のようにリモートリポジトリが空だとgit clone
の必要性を感じず、実行を省いてしまう結果となってしまいました。
これは言い訳ですね。
今回の教訓を受けて、git clone
の実行を怠らないようにしたいと思います。