Git004:Gitの作法　Gitの状態と使えるCommand一覧

### Gitはいろいろ行動を制限してくる
Programerの世界的にはめっさ便利なGit。
しかし、一般人からすると不親切極まりない挙動も結構あります。

Gitには状態があって、その状態の時にしか使えないCommandがあります。
CUIのgit commandは大量にあるし、GUIのGIT管理Softでさえ、今の状態ではこのコマンドが使えるよ・・・みたいになっていない。
結局gitの挙動をある程度理解しないといけないのが間口を狭めている原因だと思う。

### 基本の流れは・・・
```
⓪local repository無状態
  git clone <Remote Repository>でRemote RepositoryからlocalにCopy。
①Clone後/変更なし状態
　Fileを変更する。
②変更状態
　git add <File名>で変更したFileをStagingする。
③Staging状態
　git commit -m <Commit message> でStagingしたFileをCommitする。
④Commit後状態
  git push origin <Branch名>
  → ②へ戻る。
```
Gitのクセが強く、初心者にとって操作が分からなくなるのは、変更状態、Staging状態ではBranchの移動、Pullなどができなくなる事だろう。
Stashで一時保存すると変更なし状態になってBranchの移動ができる。

ここまでが基本の流れとして理解するべき部分です。

### 各状態で使えるコマンドをJSON形式でまとめました。
・カナ混じりですが、gitコマンドに使われる語は必ず英語で統一縛りでまとめてます。
・Commit後状態≒Clone後/変更なし状態　じゃん！とか変更状態とStaging状態のFileが同時に存在するんだよ！
　とか細かいツッコミはあるでしょうが、運用上は問題ないっしょということで。
・随時更新します。一部自動生成で作ったので使ったことないコマンドも有り。問題が有ったら教えて。



``` JSON: JSON形式
{
  "Git local repository無状態": [
    {
      "操作": "$ git clone https://github.com/XXXX/XXXXXX.git",
      "遷移先": "Clone後/変更なし状態",
      "説明": "指定されたrepositoryをlocalにcloneします。cloneが成功すると、local repositoryが作成され、初期状態に遷移します。"
    }
  ],
  "Clone後/変更なし状態": [
    {
      "操作": "file変更",
      "遷移先": "変更状態",
      "説明": "作業ツリーでfileが変更された場合にこの状態に遷移します。変更されたfileはまだstagingされていません。"
    },
    {
      "操作": "$ git pull, $ git fetch",
      "遷移先": "Clone後/変更なし状態",
      "説明": "Remote Repositoryから最新の変更を取得し、local repositoryを更新します。作業ツリーに変更がない限り、変更なしの状態が維持されます。"
    },
    {
      "操作": "$ git checkout <Branch名>",
      "遷移先": "Clone後/変更なし状態",
      "説明": "指定したbranchに切り替えます。作業ツリーに変更がない場合、状態は維持されます。"
    },
    {
      "操作": "$ git merge <Branch名>",
      "遷移先": ["Clone後/変更なし状態", "変更状態"],
      "説明": "branchからのすべてのCommitの変更込みでmergeします。競合がなければ、変更なしの状態が維持されます。"
    },
    {
      "操作": "$ git merge --no-ff <Branch名> -m <comment>",
      "遷移先": ["Clone後/変更なし状態", "変更状態"],
      "説明": "branchからの最終的な変更をcommitの内容を含めずmergeします。主にMainのBranchにmergeする時に使います。競合がなければ、変更なしの状態が維持されます。"
    },
    {
      "操作": "$ git merge <Branch名> --allow-unrelated-histories -X <theirs/ours>",
      "遷移先": ["Clone後/変更なし状態", "変更状態"],
      "説明": "他のリモートリポジトリの内容を取り込みたい場合、git remote add other-repo https://github.com/example/other-repo.gitのようにリモートリポジトリを追加してから本コマンドを実行します。
      
　　　　　--allow-unrelated-histories: 無関係な履歴を許可してマージします。
　　　　　-X theirs: マージコンフリクトが発生した場合、相手のブランチの内容を優先します。
　　　　　-X ours: マージコンフリクトが発生した場合、自分のブランチの内容を優先します。
      "
    },
    {
      "操作": "$ git merge --abort",
      "遷移先": "Clone後/変更なし状態",
      "説明": "mergeの途中でエラーが発生した場合、mergeを中止し、状態を元に戻します。"
    },
    {
      "操作": "$ git branch <Branch名>",
      "遷移先": "Clone後/変更なし状態",
      "説明": "新しいbranchを作成します。作成後も現在の状態が維持されます。"
    },
    {
      "操作": "$ git checkout <Branch名>",
      "遷移先": "Clone後/変更なし状態",
      "説明": "既存のbranchに切り替えます。作業ツリーに変更がなければ、変更なしの状態に戻ります。"
    },
    {
      "操作": "$ git checkout -b <Branch名>",
      "遷移先": "Clone後/変更なし状態",
      "説明": "新しいbranchを作成し、同時にそのbranchに切り替えます。"
    },
    {
      "操作": "$ git branch -m <古いBranch名> <新しいBranch名>",
      "遷移先": "Clone後/変更なし状態",
      "説明": "既存のbranch名を新しい名前に変更します。状態は維持されます。"
    },
    {
      "操作": "$ git branch -d <Branch名>",
      "遷移先": "Clone後/変更なし状態",
      "説明": "指定したlocalbranchを削除します。状態は維持されます。"
    },
    {
      "操作": "$ git push -u origin <localのBranch名>",
      "遷移先": "Clone後/変更なし状態",
      "説明": "localの新しいbranchをremote にpushし、defaultで追跡するよう設定します。"
    },
    {
      "操作": "$ git branch -r",
      "遷移先": "Clone後/変更なし状態",
      "説明": "Remote Repositoryのbranch一覧を表示します。状態は維持されます。"
    },
    {
      "操作": "$ git pull --rebase",
      "遷移先": "Clone後/変更なし状態",
      "説明": "Remote Repositoryからの変更をrebase方式で取り込みます。"
    },
    {
      "操作": "$ git rebase <Branch名>",
      "遷移先": "Clone後/変更なし状態",
      "説明": "現在のbranchのBaseを指定したbranchに変更します。"
    },
    {
      "操作": "$ git reset <Commitのハッシュ値>",
      "説明": "指定したCommitまでのCommitを取り消し、作業ツリーもその状態に戻します。履歴自体が消える",
      "遷移先": "変更状態"
    },
    {
      "操作": "$ git revert <Commitのハッシュ値>",
      "説明": "指定したCommitの変更を打ち消す新しいCommitを作成します。resetに打ち消した履歴が残るような挙動",
      "遷移先": "Clone後/変更なし状態"
    }
  ],
  "変更状態": [
    {
      "操作": "file変更",
      "遷移先": "変更状態",
      "説明": "作業ツリーでfileが変更された場合にこの状態に遷移します。変更されたfileはまだstagingされていません。"
    },
    {
      "操作": "$ git add <File名>",
      "遷移先": "Staging状態",
      "説明": "変更されたfileをstaging エリアに追加します。fileがstagingされると、Staging状態に進みます。"
    },
    {
      "操作": "$ git checkout HEAD <File名>",
      "遷移先": "変更状態",
      "説明": "指定したfileを最後のCommitの状態に戻します。変更状態が維持されます。"
    },
    {
      "操作": "$ git reset HEAD <File名>",
      "遷移先": "変更状態",
      "説明": "staging エリアからfileを取り消し、作業ツリーでの変更を維持します。"
    },
    {
      "操作": "$ git stash save",
      "遷移先": "Clone後/変更なし状態",
      "説明": "現在の変更をstashし、一時的に退避させます。作業ツリーがクリーンになり、変更なしの状態に戻ります。"
    },
    {
      "操作": "$ git stash apply <stash名>",
      "遷移先": "変更状態",
      "説明": "stashした変更を作業ツリーに再適用します。"
    },
    {
      "操作": "$ git stash drop <stash名>",
      "遷移先": "Clone後/変更なし状態",
      "説明": "指定したstashを削除します。"
    },
    {
      "操作": "$ git stash clear",
      "遷移先": "Clone後/変更なし状態",
      "説明": "すべてのstashを削除し、クリーンな状態にします。"
    },
    {
      "操作": "$ git rm -f <File名>",
      "遷移先": "変更状態",
      "説明": "指定したfileを削除し、削除されたfileが変更状態に追加されます。"
    },
    {
      "操作": "$ git mv <元のFile名> <変えたいFile名>",
      "説明": "fileの名前を変更します。",
      "遷移先": "変更状態"
    }
  ],
  "Staging状態": [
    {
      "操作": "$ git commit -m <Commit message> ",
      "遷移先": "Commit後状態",
      "説明": "stagingされたfileをrepositoryにCommitし、履歴に追加します。Commit後の状態に遷移します。"
    },
    {
      "操作": "$ git reset HEAD <file名>",
      "遷移先": "変更状態",
      "説明": "staging エリアから指定fileを取り消し、変更状態に戻します。"
    }
  ],
  "Commit後状態": [
    {
      "操作": "$ git commit --amend -m <新しいCommit message>",
      "説明": "直前のCommitに新たにStagingしたFileの変更を加える場合に使用します。-mの引数を加えるとCommit messageの修正を含めることができます。",
      "遷移先": "Commit後状態"
    },
    {
      "操作": "$ git push origin <Branch名>",
      "遷移先": "Clone後/変更なし状態",
      "説明": "localのCommitをRemote Repositoryにpushします。"
    },
    {
      "操作": "$ git push -f",
      "説明": "Remote Repositoryに強制的にpushします。remote branchをlocalの状態で上書きします。",
      "遷移先": "Clone後/変更なし状態"
    },
    {
      "操作": "$ git pull",
      "遷移先": "Clone後/変更なし状態",
      "説明": "Remote Repositoryの最新の変更を取り込みます。"
    },
    {
      "操作": "$ git log",
      "遷移先": "Commit後状態",
      "説明": "Commit履歴を表示します。"
    }
  ]
}


```
あとは、元々command lineツールであり、引数で様々な機能を実現しているせいか、 細かい動作を実現するGUIが無い気がする。この辺もいい感じのGUI作って欲しいもんです。

```
##こんな感じのコマンド
git merge --no-ff <Branch名> -m "Version 0.00a Merge <Branch名>"
git reset <Commitのハッシュ値>#これくらいはGUIで実装して欲しいんだけど！
```