14
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

リンクアンドモチベーションAdvent Calendar 2024

Day 3

「git switch 」でエラー発生!stashで未コミットの変更を守る

Last updated at Posted at 2024-12-03

はじめに

こんにちは!リンクアンドモチベーションの宮田です!昨日ぶりです。
枠が空いていたのでいただきました🙇‍♂️

本記事はリンクアンドモチベーション Advent Calendar 2024の3日目を担当しています。🎄

git switch main
error: Your local changes to the following files would be overwritten
by checkout:
    
Please commit your changes or stash them before you switch branches.
Aborting

このエラーに出会ったのがこの記事を書くきっかけです。
このエラーはなんだ?ということで、調べてみると、

現在のブランチに未コミットの変更がある状態で別のブランチに切り替えようとした際に表示されるエラーで、Gitが「現在の変更が失われる可能性があるので処理を中止した」と警告している状況だとわかりました。

では、この状況で、変更を保持したまま、別のブランチにチェックアウトしたい場合はどうしたらいいのでしょうか。

この記事が、僕と同じエラーに出会った一人でも多くの方のお役に立つことを願っております。

【前提】ブランチ切替時の注意点

変更を保持する方法を知る前に、ブランチ切り替え時に知っておきたいことを確認しておきます。

まずはこの記事を確認すると良さそうです。

今回僕が出会ったのエラーは
移動先のブランチよりも進んだ変更(コミット済)がある+未コミットの変更がある」状態で、ブランチを移動しようとしたため起こったものでした。

変更があってもエラーが発生せずに移動できる場合もあります。(上の記事にあるもう一つのパターン)

ただここで注意が必要です。

例えば、あるブランチで作業している時に、緊急で別の作業が入ってしまったというとき、作業中のブランチ上にまだコミットしていない変更内容などが含まれている状態でブランチを切り替えると、その変更は切り替えた先のブランチに適用されてしまいます。

コミットしてない変更は移動先のブランチに反映される

だからと言って、作業途中の中途半端な状態でコミットをしてしまうと、コミットログが汚くなってしまいますし、どこまでやったか、作業のログがわかりにくくなってしまいます。

それでは困りますね。

とにかく、エラー発生の有無に関わらず、ブランチを移動するときに現在のブランチの状態を保持し、他のブランチに影響させないようにするための手段が欲しいです!

stash(スタッシュ)

そんな時に使えるのが、変更を一時的に退避させて保管する「stash(スタッシュ)」です。スタッシュは「こっそり隠す」という意味があり、作業内容を一時的にコミットせずに保管する機能です。

以下でstashの使い方を確認していきます。

git stash save "○○" -u

スタッシュを作成したいときはこのコマンドを使用します。
git stash saveの後に続けて、スタッシュの名前を指定します。名前は省略できますが、その代わりに自動でコミットIDやコミットメッセージを使った名前が付加されます。

-u: これはまだステージングされていない変更も含めてstashするというオプションです。

git stash save "作業途中" -u

Saved working directory and index state On branchD: 作業途中

この時点で未コミット、未ステージングの変更は全てスタッシュの中に保管されVScodeの画面上からは消えます。

git stash list

作成したスタッシュの一覧化して確認できるコマンドです。

git stash list

stash@{1}: On branchD: 作業途中
stash@{2}: On main: 保存

こんな感じで出てきます。

git stash apply

作成したスタッシュを適用する場合は、このコマンドです。

git stash apply  # 直前に作成したスタッシュを適用
git stash apply "stash@{n}" # 指定した番号のスタッシュが適用される

git stash applyをすると、git stash saveしたときの状況を復元することが出来ます。

git stash drop

作成したスタッシュを削除するコマンドです。
一度スタッシュを作成すると適用後も残り続けます。

stash@{0}: On main: Change 20
stash@{1}: On main: Change 19
stash@{2}: On main: Change 18
...
stash@{18}: On main: Change 2
stash@{19}: On main: Change 1

直前のスタッシュを削除したいときは git stash dropを使います。

git stash drop
git stash list

#直前のスタッシュが削除される
stash@{1}: On main: Change 19
stash@{2}: On main: Change 18
...
stash@{18}: On main: Change 2
stash@{19}: On main: Change 1

指定したいときは、applyと同様です

git stash drop "stash@{n}" # 指定した番号のスタッシュが削除される

git stash clear

もう全部使いません!一個一個消してたら日が暮れるよの場合は git stash clearで一括削除できます。

git stash clear

git stash list
# なにも表示されない

使うときには慎重になった方がよさそうですね。

これらのstashコマンドを使って適切にブランチごとの変更を管理していきたいです。

git pullのエラーでも使える!!

ちなみにこの

git stash → git stash apply

実はリモートリポジトリからpullしたいときにも使えます。例えば、自分のローカルでの変更をpushしようとしたとき、リモートが既に更新されていて、ローカルが遅れた状態になっていると、「一度最新の状態をpullしなさいという」エラーがでます。

 git push
 
 ! [rejected]        branchc -> branchc (non-fast-forward)
error: failed to push some refs to 'https://github.com/ShoyaMiyata/GitGit.git'
hint: Updates were rejected because the tip of your current branch is behind
hint: its remote counterpart. If you want to integrate the remote changes,
hint: use 'git pull' before pushing again.
hint: See the 'Note about fast-forwards' in 'git push --help' for details.

そこでgit pullを試みようとすると、つぎは
今のローカルの変更が上書きされちゃうよ。リモートの変更をマージする前にcommitするかstashしてね」というエラーが出ます。

git pull       
From https://github.com/ShoyaMiyata/GitGit
 * [new branch]      branchc    -> origin/branchc
 * [new branch]      brancha    -> origin/brancha
error: Your local changes to the following files would be overwritten by merge:
        ABC.rb
Please commit your changes or stash them before you merge.
Aborting

そこで、スタッシュの登場です。

  1. ローカルの変更をstash saveで一時的に避難させておいて、
  2. pullでリモートの状況と同期させた後に
  3. stash applyで変更を復活させ、リモートよりもローカルの方が進んでいる状況を作り出して、
  4. git pushする

という流れができます

おまけ gitignore

stashで変更履歴の保持について理解してきましたが、ここで変更履歴を残さない方法を紹介します。

  • 自分の環境だけの変更なのに、いちいち変更を追跡されてめんどくさい。
  • 一生コミットすることないのに、数字だけ生き残っていらっしゃる
    image.png
    ☝こんな具合に

そんな時には、gitignoreが使えます。変更を無視して、変更履歴に表示する追跡対象から除外してくれる機能です。

実装手順

  1. .gitignoreファイルを作成
    image.png
  2. .gitignoreファイルをステージングしてコミット
  3. .gitignoreファイルに無視させたいファイル名やパスを記述
    image.png
  4. 無視させたいファイルを確認
    image.png
    色が薄くなっています。この状態だとlog.txtに変更を加えても変更履歴が追跡されることはありません。
    ちなみに.gitignoreファイルを作成する前の変更履歴は残ってしまうので、別途対応が必要です。

最後に

Gitのブランチ切り替え時に未コミット変更でエラーが発生する原因と解決策を解説しました。解決法としてgit stashで変更を一時退避し、作業を保護する方法を紹介しました。

内容に不備などありましたら、ご指摘ください。
最後までお読みいただきありがとうございました!


ぜひこちらの記事も併せてご覧になってください

参考文献

図解! Git & GitHubのツボとコツがゼッタイにわかる本[第2版]

はじめてでもできる GitとGitHubの教科書

14
1
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
14
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?