git　ブランチとリポジトリの理解（備忘録）

gitをなんとなーく使ってきて1年が経とうとして、いまだにaddとcommitがそれぞれ何をしているのか説明できなかったり、pushしてもなぜかエラーが起きてしまうなどの苦戦していたので、一度しっかりgitを学びました。

# 目次
- [リポジトリとブランチ](https://qiita.com/ymzkjpx/items/00ff664da60c37458aaa#git%E3%81%AE%E3%83%95%E3%82%A1%E3%82%A4%E3%83%AB%E7%AE%A1%E7%90%86%E3%81%AE%E4%BB%95%E7%B5%84%E3%81%BF)
    - [リポジトリ](https://qiita.com/ymzkjpx/items/00ff664da60c37458aaa#git%E3%81%AE%E3%83%95%E3%82%A1%E3%82%A4%E3%83%AB%E7%AE%A1%E7%90%86%E3%81%AE%E4%BB%95%E7%B5%84%E3%81%BF)
    - [ブランチ](https://qiita.com/AnRi1202/items/c1cdc8d212f8c87525d7#%E3%83%96%E3%83%A9%E3%83%B3%E3%83%81%E7%B0%A1%E5%8D%98%E4%B8%80%E9%80%A3%E3%81%AE%E4%BD%9C%E6%A5%AD%E3%81%AE%E6%B5%81%E3%82%8C--%E6%AD%A3%E7%A2%BA%E3%82%B3%E3%83%9F%E3%83%83%E3%83%88%E3%82%AA%E3%83%96%E3%82%B8%E3%82%A7%E3%82%AF%E3%83%88%E3%81%B8%E3%81%AE%E3%83%9D%E3%82%A4%E3%83%B3%E3%82%BF)

<br>

- [リポジトリとブランチの作り方](https://qiita.com/AnRi1202/items/c1cdc8d212f8c87525d7#%E3%83%AA%E3%83%9D%E3%82%B8%E3%83%88%E3%83%AA%E3%81%A8%E3%83%96%E3%83%A9%E3%83%B3%E3%83%81%E3%81%AE%E4%BD%9C%E3%82%8A%E6%96%B9)
    - [ローカルリポジトリの作り方(init)](https://qiita.com/AnRi1202/items/c1cdc8d212f8c87525d7#%E3%83%AD%E3%83%BC%E3%82%AB%E3%83%AB%E3%83%AA%E3%83%9D%E3%82%B8%E3%83%88%E3%83%AA%E3%81%AE%E4%BD%9C%E3%82%8A%E6%96%B9)
    - [リモートリポジトリの作り方(github)](https://qiita.com/AnRi1202/items/c1cdc8d212f8c87525d7#%E3%83%AA%E3%83%A2%E3%83%BC%E3%83%88%E3%83%AA%E3%83%9D%E3%82%B8%E3%83%88%E3%83%AA%E3%81%AE%E4%BD%9C%E3%82%8A%E6%96%B9)
    - [ローカルブランチの作り方(checkout)](https://qiita.com/AnRi1202/items/c1cdc8d212f8c87525d7#%E3%83%AA%E3%83%A2%E3%83%BC%E3%83%88%E3%83%AA%E3%83%9D%E3%82%B8%E3%83%88%E3%83%AA%E3%81%AE%E4%BD%9C%E3%82%8A%E6%96%B9)
    - [リモートブランチとリモート追跡ブランチの作り方(?)](https://qiita.com/AnRi1202/items/c1cdc8d212f8c87525d7#%E3%83%AA%E3%83%A2%E3%83%BC%E3%83%88%E3%83%96%E3%83%A9%E3%83%B3%E3%83%81%E3%81%A8%E3%83%AA%E3%83%A2%E3%83%BC%E3%83%88%E8%BF%BD%E8%B7%A1%E3%83%96%E3%83%A9%E3%83%B3%E3%83%81%E3%81%AE%E4%BD%9C%E3%82%8A%E6%96%B9)

<br>

- [ブランチの確認方法(branch)](https://qiita.com/AnRi1202/items/c1cdc8d212f8c87525d7#%E3%83%AA%E3%83%A2%E3%83%BC%E3%83%88%E3%83%96%E3%83%A9%E3%83%B3%E3%83%81%E3%81%A8%E3%83%AA%E3%83%A2%E3%83%BC%E3%83%88%E8%BF%BD%E8%B7%A1%E3%83%96%E3%83%A9%E3%83%B3%E3%83%81%E3%81%AE%E4%BD%9C%E3%82%8A%E6%96%B9)
    - [ローカルブランチの確認方法](https://qiita.com/AnRi1202/items/c1cdc8d212f8c87525d7#%E3%83%AD%E3%83%BC%E3%82%AB%E3%83%AB%E3%83%96%E3%83%A9%E3%83%B3%E3%83%81%E3%81%AE%E7%A2%BA%E8%AA%8D%E6%96%B9%E6%B3%95)
    - [リモート追跡ブランチの確認方法(-r)](https://qiita.com/AnRi1202/items/c1cdc8d212f8c87525d7#%E3%83%AA%E3%83%A2%E3%83%BC%E3%83%88%E8%BF%BD%E8%B7%A1%E3%83%96%E3%83%A9%E3%83%B3%E3%83%81%E3%81%AE%E7%A2%BA%E8%AA%8D%E6%96%B9%E6%B3%95)

<br>

- [リポジトリとブランチの接続](https://qiita.com/AnRi1202/items/c1cdc8d212f8c87525d7#%E3%83%AA%E3%83%9D%E3%82%B8%E3%83%88%E3%83%AA%E3%81%A8%E3%83%96%E3%83%A9%E3%83%B3%E3%83%81%E3%81%AE%E5%90%8C%E6%9C%9F)
    - [リモートリポジトリとローカルリポジトリの接続(remote)](https://qiita.com/AnRi1202/items/c1cdc8d212f8c87525d7#%E3%83%AA%E3%83%A2%E3%83%BC%E3%83%88%E3%83%AA%E3%83%9D%E3%82%B8%E3%83%88%E3%83%AA%E3%81%A8%E3%83%AD%E3%83%BC%E3%82%AB%E3%83%AB%E3%83%AA%E3%83%9D%E3%82%B8%E3%83%88%E3%83%AA%E3%81%AE%E6%8E%A5%E7%B6%9Aremote)
    - [ローカルブランチをリモートブランチに接続(push)](https://qiita.com/AnRi1202/items/c1cdc8d212f8c87525d7#%E3%83%AA%E3%83%A2%E3%83%BC%E3%83%88%E3%83%AA%E3%83%9D%E3%82%B8%E3%83%88%E3%83%AA%E3%81%A8%E3%83%AD%E3%83%BC%E3%82%AB%E3%83%AB%E3%83%AA%E3%83%9D%E3%82%B8%E3%83%88%E3%83%AA%E3%81%AE%E6%8E%A5%E7%B6%9Aremote)
    - [リモートブランチを、リモート追跡ブランチやローカルブランチへの接続](https://qiita.com/AnRi1202/items/c1cdc8d212f8c87525d7#%E3%83%AA%E3%83%A2%E3%83%BC%E3%83%88%E3%83%96%E3%83%A9%E3%83%B3%E3%83%81%E3%82%92%E3%83%AA%E3%83%A2%E3%83%BC%E3%83%88%E8%BF%BD%E8%B7%A1%E3%83%96%E3%83%A9%E3%83%B3%E3%83%81%E3%82%84%E3%83%AD%E3%83%BC%E3%82%AB%E3%83%AB%E3%83%96%E3%83%A9%E3%83%B3%E3%83%81%E3%81%B8%E3%81%AE%E6%8E%A5%E7%B6%9A)

<br>

- [次にやること](https://qiita.com/AnRi1202/items/c1cdc8d212f8c87525d7#%E6%AC%A1%E3%81%AB%E3%82%84%E3%82%8B%E3%81%93%E3%81%A8)


# リポジトリとブランチ
## リポジトリ
**変更履歴や更新者の情報も含めた一塊のフォルダ群、というイメージ**
- **リモートリポジトリ**
github上で確認できるリポジトリ

    
- **ローカルリポジトリ**
vscodeでもなんでも、自分のパソコンで見れるリポジトリ。git initやgit cloneをすることで.gitフォルダが入り、そこに変更履歴などの情報が入っています。さらにローカルリポジトリは
    - **working tree**
    - **index**
という二つのフォルダに分けられます。(厳密には違う気がしますがイメージです)
    
<br>
リモートが遠くのという意味だからどこかのサーバーに保存されているイメージ。ローカルは現地という意味だから手元のパソコン。
(以前ローカルポジトリのことをリモートリポジトリと言って恥ずかしい思いをしたので細かく説明してます。自分が基準で考える)

<br><br><br>


### working treeとindexについて
ワーキングツリーとは、手元で作業しているファイル群、ディレクトリのことです。リポジトリとは状態の履歴なども含めていましたが、ワーキングツリーとはまさにvscodeなどのエディタで見ているファイルたちのことです。
indexは
```bash
git add <ファイル名>
```
をしたファイルが入っているフォルダです。この動作のことをステージングといいます。下の方々の記事がとても分かりやすいです。
```bash
git status
```
statusコマンドでは、赤い表示が最新のcommit状態との差分があるファイルを示します。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3787219/a39ad525-ee02-8b4a-6307-6d8e0bead385.png)


緑色の表示がstagingされているファイルを示します。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3787219/0915086c-2713-ee90-346e-0c7e74814de8.png)


```bash
git diff
```
indexは清書用のファイル群、もしくはリモートに出荷する前のファイル群のようなイメージです。

https://qiita.com/sparklingbaby/items/e749249d366c7487bbbf

https://backlog.com/ja/git-tutorial/intro/04/

ローカルで変更したものをいきなりリモートに反映させればいいじゃないかと考えるのも自然です。そこでローカルリポジトリがワーキングツリーとindexに分かれているメリットを考えました。

- 一度に作業しても,ファイルごとにaddをしてcommitすれば変更履歴を詳細に書ける
    - commitだけだと一度更新したら更新内容を小分けにできない
- ```git status```で状況を細かく把握できる
    - コミットの手前の段階まで把握できます。
- ```git restore```が使える(多分ほぼ使わない)

つまり、出荷する際に荷物にラベル(=コミットのメッセージ)を貼ることで、荷物を受け取る人も荷物の内容がわかるのです。
この記事を書く前まで自分はほとんど```git add .```ばかり使っていたのですが、これでは「私の荷物10ファイルです。中身の確認お願いします！」と言っているようなものです。しっかりと「これは果物、これはお皿、これは電化製品」というように小分けにしていく親切さを実現するためにステージングがあると理解しています。
つまり、少しできたらcommitをする、という人にとってはステージングは不要なのかもしれません。一方で一度に作業をしたうえで最後にまとめて```git add .```をする人はaddをする前に一度立ち止まって、addするファイルを整理して複数commitにすると良いかもしれません。

<br><br><br>


## ブランチ(簡単：一連の作業の流れ / 正確：コミットオブジェクトへのポインタ)
ブランチとは、作業を複数に分岐できるものくらいのイメージでしたが、実際はコミットオブジェクトのポインタであるという理解をしてgit logの見方などがクリアになりました.コミットをする際にコミットの情報が記載されたオブジェクト(情報群のイメージ)が.gitの中に生成されます。その情報群をさすのがブランチなのです。下の方の記事でとても詳しく解説しています

https://qiita.com/ymzkjpx/items/00ff664da60c37458aaa#git%E3%81%AE%E3%83%95%E3%82%A1%E3%82%A4%E3%83%AB%E7%AE%A1%E7%90%86%E3%81%AE%E4%BB%95%E7%B5%84%E3%81%BF

ポインタと聞いてぞくっとする方はc言語で躓いた経験があるかもしれません。僕は下の方の記事で理解度が上がりましたので参考までに。

https://monozukuri-c.com/langc-pointer-extreme/



- **ローカルブランチ**(mainやfeature/hoge)
    ローカルリポジトリに存在するローカルリポジトリの作業の分岐
- **リモートブランチ**(origin)
    リモートリポジトリに存在するローカルリポジトリの作業の分岐
- **リモート追跡ブランチ**(origin/hoge)
    **ローカルリポジトリ**に存在する**リモートリポジトリ**の作業の分岐

ブランチはなぜか三つあることが意味も分からずgitを使い続けていましたが,そうするとfetchやmerge,origin/mainなどが理解しにくくなります。

リモートのリポジトリは複数人が作業しているので時々刻々と変化していきます。googleドライブのように変化がすぐに手元に反映されるのならば、ローカルとリモートのブランチの二つでいいのですが、gitの場合は違います。
gitではリモート追跡ブランチという第三のブランチを手元に置き、自分の適切なタイミングでリモートの最新情報をローカルに持ってくるイメージです。そうすれば逐一オンライン環境で最新のデータを引き抜き続ける必要もないのです。イメージとしてはリモート追跡ブランチはローカルにあるのです。
<br><br><br>

# リポジトリとブランチの作り方
### ローカルリポジトリの作り方
``` bash
git init
```
.gitフォルダができて,git statusなどgitコマンドが打てるようになる

<br>

### リモートリポジトリの作り方
自分はgithubで作ってます。[gitbucket](https://freelance.shiftinc.jp/column/bitbucket)というものや[コマンド](https://eng-entrance.com/git-remote)で作る方法もあるらしいです。



<br>


### ローカルブランチの作り方
initで始めた場合はcommitをした段階でデフォルトの名前(git ver2.28.0以降ならmain configで変更できるらしいです)のブランチができます。なぜコミットしてからなのかというと,ブランチとはコミットオブジェクトへのポインタであるからです。先ほども紹介した「[HEADとは何者なのか](https://qiita.com/ymzkjpx/items/00ff664da60c37458aaa)」が本当にわかりやすいです。

それ以外の場合には
``` bash
git checkout -b <新しく作るブランチ名>
git checkout <すでに存在するブランチ名>
git switch <ブランチ名>       #最近はこれが推奨されているらしいです
```
<br>

### リモートブランチとリモート追跡ブランチの作り方(?)
これらは自ら作るというよりはpullやpushをする中でできていくイメージです。
<br><br><br>


# ブランチの確認方法
### ローカルブランチの確認方法
``` bash
git branch
```
### リモート追跡ブランチの確認方法
``` bash
git branch -r #リモート追跡の「*r*emote」のr
```

### リモートブランチの確認方法
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3787219/6a3e4d43-f667-5967-31d6-ebf8845dc500.png)
githubならmainと書かれている分岐マークのあるところをクリック。

<br><br>

<details open><summary>その他のコード</summary>

```git branch -a```:ローカルとリモート追跡を表示　
```git branch -d```:ローカルの削除
```git push origin --delete <branch名>```:リモートの削除)

</details>

<br><br>



# リポジトリとブランチの同期

gitに登場するキャラをまとめたところですが、これらの接続方法について考えていきたくなるでしょう。

### リモートリポジトリとローカルリポジトリの接続(remote)
``` bash
git remote add <ローカルリポジトリでのリモートリポジトリの呼び名> <リモートリポジトリのurl>
```
addの次に長ったらしく書いているのは,いわゆるoriginです。リモートリポジトリを手元で扱いたいときに毎回urlやリポジトリ名で呼んでいたら長ったらしいので、originと命名しちゃっているんです。複数のリモートリポジトリを扱いたいときにはorigin以外の別の名前でリモートリポジトリを登録することもできるらしいです。(gitはまだまだ初心者なので、どのようなときに必要になってくるのか、実践で使ったことはないです...一応[こんな](https://ja.stackoverflow.com/questions/42216/%E9%81%95%E3%81%86git%E3%81%AEurl%E3%81%AB%E3%83%97%E3%83%AD%E3%83%80%E3%82%AF%E3%83%88%E3%82%92push%E3%81%97%E3%81%9F%E3%81%84)記事はありました)

<br><br>






<br><br>

### ローカルブランチをリモートブランチに接続(push)
``` bash
git push origin <ローカルブランチ名>
```
これは接続というより、ローカルからリモートに押し付けるイメージです。リモートに存在しないブランチ名のブランチをpushすると、リモートに新しくブランチが生成されます。二回目以降はリモートと同じ名前のbranchをpushすればリモートも更新されます。

(参考：迂闊にブランチ名を変えたりしているとdetached HEADになりました。この原因については勉強中です。実際は名前で紐づけでもなさそうです)

<br><br>

### リモートブランチを、リモート追跡ブランチやローカルブランチへの接続
#### clone
``` bash
git clone <リモートのurl>
```
この場合、リモートリポジトリにあるmainブランチがローカルのmainブランチとして複製されます。```git branch```と```git branch -r```を見るとわかるのですが,リモート追跡ブランチにはリモートのブランチが反映されているのですがローカルブランチにはmainのみが存在します。

<details><summary>参考までにgit branch -aの結果</summary>

``` bash
test$ git branch -a
* main
  remotes/origin/feature/test
  remotes/origin/feature/test2
  remotes/origin/main
  remotes/origin/master
```

</details>

<br>

#### pull
```bash
git pull origin <リモートブランチ名>
```
基本的にmainのブランチにいるときにmainをプルして,feature/hogeのブランチにいるときはfeature/hogeをpullすると覚えましょう。このようにすればリモートの最新状態をローカルにまで一気に持ってこれます。混乱せずにとりあえず使ってみたい場合はpullの理解はこれくらいでいいのかと思います。


<br>




更に理解を深める場合や、fetchやmergeについても理解をしたい場合には次の文章を読んでください。

若干ややこしいのですが、pullするときの引数は**リモート**のブランチ名で、そのブランチを引き継ぐのは今いるローカルのブランチです。例えば
```
* feature/test
main
```
という状態で```git pull origin main```をするとfeature/testがリモートの状態を引き継ぎます。一方でローカルブランチは更新されません。


pushの場合の引数は**ローカル**のブランチ名ですので、仮に上のようなcheckout、すなわちfeature/testにいる状態で```git push origin main```をするとローカルのmainブランチのコミット状況をリモートのmainブランチに飛ばします。




<br><br><br>
# 次にやること
ここまでリポジトリとブランチの大まかなイメージとコマンドについて説明してきました。

ここまでを読むと次のような疑問や問題がわいてくると思います。
- ローカルである程度作業していてリモートの状態を追加したいときにpullしてもうまく結合できない(=競合)のではないか？→error: Your local changes to the following files would be overwritten by merge:というエラーが出ます
- リモートのmainで作業を進めてコミットまでしたのにpushしようとしたら別の人がpushをして競合してしまう。困ったからpullをして最新の状態をリモートにpullしても競合が起きてしまう
    <details><summary>pushによる競合のエラー</summary>

    ```
     ! [rejected]        main -> main (fetch first)
    error: failed to push some refs to 'github.com:your-rep'
    hint: Updates were rejected because the remote contains work that you do
    hint: not have locally. This is usually caused by another repository pushing
    hint: to the same ref. You may want to first integrate the remote changes
    hint: (e.g., 'git pull ...') before pushing again.
    hint: See the 'Note about fast-forwards' in 'git push --help' for details.
    ```
    
    </details>
    <details><summary>pullによる競合のエラー</summary>

    ```
     * branch            main       -> FETCH_HEAD
    hint: You have divergent branches and need to specify how to reconcile them.
    hint: You can do so by running one of the following commands sometime before
    hint: your next pull:
    hint: 
    hint:   git config pull.rebase false  # merge (the default strategy)
    hint:   git config pull.rebase true   # rebase
    hint:   git config pull.ff only       # fast-forward only
    hint: 
    hint: You can replace "git config" with "git config --global" to set a default
    hint: preference for all repositories. You can also pass --rebase, --no-rebase,
    hint: or --ff-only on the command line to override the configured default per
    hint: invocation.
    fatal: Need to specify how to reconcile divergent branches.
    ```
    
    </details>

<br><br><br>


これらの問題についても知りたい方は以下のものを勉強していくとよいと思います。
- ```git log```の使い方
    コミットを時系列でみることができます
    
- fast-fowardとnon-fast-forward
    コミットツリーが別々に伸びって言っている場合の結合方法
    - [Gitのfetch, merge, pullって何やってるの？](https://qiita.com/tonnsama/items/ed94c0d91064d0df756a)
    - [ブランチの統合｜サル先生のGit入門](https://backlog.com/ja/git-tutorial/stepup/04/)
- blobファイル、ツリーオブジェクト、コミットオブジェクトについて

https://qiita.com/ymzkjpx/items/00ff664da60c37458aaa#git%E3%81%AE%E3%83%95%E3%82%A1%E3%82%A4%E3%83%AB%E7%AE%A1%E7%90%86%E3%81%AE%E4%BB%95%E7%B5%84%E3%81%BF



- そのほかgitのコマンド一覧について

https://qiita.com/kamihork/items/36992c14c70b7477f40e