MarkdownとBullet Journal

いわゆるプログラマーのつぶやき

【Git】stashで退避する範囲

git stashの有効範囲を調べる

以前の記事でも記載した様にGitは、fileを6つの状態で扱う。

programmingforever.hatenablog.com

そこで、その内ローカル側の5つの状態のfileをgit stashコマンドでどの様に退避するのかをまとめた。但しcommitはstashの対象にならないため実際は以下の2から5までの状態に置いた4つのfileの退避を確認する。

各shell scriptの状態

説明のために5つのfileをそれぞれ下記の状態にして動作を追う。

  1. a.sh:fileをcommitした状態
  2. b.sh:fileを変更してstagingした状態
  3. c.sh:fileを変更してstagingしていない状態
  4. d.sh:fileをGitがまだ追跡していない状態(新規file等)
  5. e.sh:fileをGitが無視する状態(.gitignoreで指定したfile)

コマンドで退避前の各fileの状態を確認

$ ls    
a.sh    b.sh    c.sh    d.sh    e.sh   # - 各fileが見える 
$ git status
On branch main
Changes to be committed:
  (use "git restore --staged <file>..." to unstage)
    modified:   b.sh     # - b.shはstaging中(変更あり)

Changes not staged for commit:
  (use "git add <file>..." to update what will be committed)
  (use "git restore <file>..." to discard changes in working directory)
    modified:   c.sh     # - c.shは変更あり 

Untracked files:
  (use "git add <file>..." to include in what will be committed)
    d.sh                 # - d.shはGit追跡対象外、e.shは無視なので見えない

$           

図で退避される範囲を確認

f:id:ProgrammingForEver:20210913111049j:plain

git stash

Gitの追跡対象かつ変更したfile及びfolderを作業ディレクトリとstagingから退避し、作業ディレクトリとstagingをcommt直後に戻す。

git stash popで退避を戻すとstaging状態が解除されている。またstagingしたfileを追加修正してstagingしていない場合、stagingしたfileは消失して追加修正したfileが残る。

  1. 退避する(commit直後のstaging状態に戻る)
  2. 退避する(commit直後の作業ディレクトリ状態に戻る)
  3. 退避しない
  4. 退避しない
$ git stash         # - 退避を実行 
Saved working directory and index state WIP on main: 80afbdd test1
$ ls  
a.sh    b.sh    c.sh    d.sh    e.sh     # - b.sh, c.shの内容は変更前に戻っている 
$ git status
On branch main
Untracked files:
  (use "git add <file>..." to include in what will be committed)
    d.sh            # - staging中のb.sh、変更&staging前のc.shが消えた

nothing added to commit but untracked files present (use "git add" to track)

$ git stash show    # - b.shとc.shが退避されているのが見える
 b.sh | 2 +-
 c.sh | 2 +-
 2 files changed, 2 insertions(+), 2 deletions(-)

$ git stash pop     # - 退避を元に戻すと・・ 
On branch main
Changes not staged for commit:
  (use "git add <file>..." to update what will be committed)
  (use "git restore <file>..." to discard changes in working directory)
    modified:   b.sh   # - stagingが解除されている点に注意 
    modified:   c.sh

Untracked files:
  (use "git add <file>..." to include in what will be committed)
    d.sh

no changes added to commit (use "git add" and/or "git commit -a")
Dropped refs/stash@{0} (ec403a9850501332a6bbc52a694c5473c97ba435)
$ git add b.sh      # - 必要に応じてstagingし直す 
$

git stash -k

-kオプションを付けると、Gitの追跡対象かつ変更したfile及びfolderを作業ディレクトリとstagingから退避し、作業ディレクトリはcommit直後に戻すが、staging状態は現状を維持する。

stagingしたfileを追加修正してstagingしていない場合は、stagingした内容と追加修正した内容が、git stash popで退避を戻す際にマージされるので対象fileを編集してconflictを解決する。

  1. 退避する(staging状態を維持する)
  2. 退避する(commit直後の作業ディレクトリ状態に戻る)
  3. 退避しない
  4. 退避しない
$ git stash -k         # - -kオプションを付けて実行
Saved working directory and index state WIP on main: 80afbdd test1
$ git status
On branch main
Changes to be committed:
  (use "git restore --staged <file>..." to unstage)
    modified:   b.sh   # - stagingのb.shが残っている 

Untracked files:
  (use "git add <file>..." to include in what will be committed)
    d.sh  # - 変更&staging前のc.shが隠され、追跡外のd.shが見える 

$ git stash show    # - b.shとc.shが退避されているのが見える
 b.sh | 2 +-
 c.sh | 2 +-
 2 files changed, 2 insertions(+), 2 deletions(-)

$ git stash pop        # - 退避を元に戻すとstash前と同じ状態
On branch main
Changes to be committed:
  (use "git restore --staged <file>..." to unstage)
    modified:   b.sh

Changes not staged for commit:
  (use "git add <file>..." to update what will be committed)
  (use "git restore <file>..." to discard changes in working directory)
    modified:   c.sh

Untracked files:
  (use "git add <file>..." to include in what will be committed)
    d.sh

Dropped refs/stash@{0} (c976e74a49d3960940bd367e1da312d030cf75f9)
$

git stash -u

-uオプションを付けると、Gitの追跡対象かつ変更したfile及びfolderを作業ディレクトリとstagingから退避し、作業ディレクトリとstagingをcommt直後に戻す動作に加えて、

作業ディレクトリ内のGit追跡対象外のfile及びfolderも、作業ディレクトリとstaging内から退避して、popするまで作業ディレクトリから消失させる。但し.gitignoreで指定したfileは退避しない。空のfolderは削除されて戻らない。

  1. 退避する(commit直後のstaging状態に戻る)
  2. 退避する(commit直後の作業ディレクトリ状態に戻る)
  3. 退避する
  4. 退避しない
$ git stash -u            # - -uオプション付きで退避を実行 
Saved working directory and index state WIP on main: 80afbdd test1
$ ls  
a.sh    b.sh    c.sh    e.sh     # - Git追跡対象外fileのd.shが消えた 
$ git status
On branch main
nothing to commit, working tree clean  # - 何も変更がないと表示される
$ git stash pop           # - 退避を戻すと・・・
On branch main
Changes not staged for commit:
  (use "git add <file>..." to update what will be committed)
  (use "git restore <file>..." to discard changes in working directory)
    modified:   b.sh      # - stagingは外される 
    modified:   c.sh

Untracked files:
  (use "git add <file>..." to include in what will be committed)
    d.sh

no changes added to commit (use "git add" and/or "git commit -a")
Dropped refs/stash@{0} (11ee1ab69090b3360d2f19bf97b9a646f575fc15)

$ ls
a.sh    b.sh    c.sh    d.sh    e.sh   # - 消えたd.shが復活   
$ git add b.sh            # - 必要に応じてstagingし直す 
$

git stash -a

-aオプションを付けると、Gitの追跡対象かつ変更したfile及びfolderを作業ディレクトリとstagingから退避し、作業ディレクトリとstagingをcommt直後に戻す動作に加えて、

作業ディレクトリ内のGit追跡対象外やGitに無視する様に指定したfile及びfolderも、作業ディレクトリとstaging内から退避して、popするまで作業ディレクトリから消失させる。空のfolderは削除されて戻らない。

  1. 退避する(commit直後のstaging状態に戻る)
  2. 退避する(commit直後の作業ディレクトリ状態に戻る)
  3. 退避する
  4. 退避する
$ git stash -a           # - -aオプション付きで退避を実行 
Saved working directory and index state WIP on main: 80afbdd test1
$ ls  
a.sh    b.sh    c.sh     # - Git追跡対象外のd.shと無視指定のe.shが消えた 
$ git status
On branch main
nothing to commit, working tree clean  # - 何も変更がないと表示される
$ git stash pop          # - 退避を戻すと・・・
On branch main
Changes not staged for commit:
  (use "git add <file>..." to update what will be committed)
  (use "git restore <file>..." to discard changes in working directory)
    modified:   b.sh     # - stagingは外される 
    modified:   c.sh

Untracked files:
  (use "git add <file>..." to include in what will be committed)
    d.sh

no changes added to commit (use "git add" and/or "git commit -a")
Dropped refs/stash@{0} (11ee1ab69090b3360d2f19bf97b9a646f575fc15)

$ ls
a.sh    b.sh    c.sh    d.sh    e.sh   # - 消えたd.sh, e.shが復活   
$ git add b.sh          # - 必要に応じてstagingし直す 
$

git stash -- files

git stash -- filesで指定fileだけを退避出来る。

git stash -p

git stash -pでハンク単位で退避出来る。