仕組みから理解するgit入門 第四回

[第三回はこちら](https://qiita.com/JugglerShu@github/items/55c278bdc615ee5e8f51)

# 前回の課題の解説とポイント

## 課題1

### Bさん
Aさんの持っているリポジトリをclone

```
> git clone /path/to/RepoA RepoB   // Aさんのリポジトリをclone
> cd RepoB
```

### Aさん、Bさん共に
ブランチを作成して適当なコミットを2つ

```
> git checkout -b BranchA         // BさんならBranchB
> echo new file > file1.txt
> git add file1.txt
> git commit
> echo another file > file2.txt
> git add file2.txt
> git commit
```

### Bさん
Aさんの作業内容を取得してマージ

```
> git fetch origin BranchA       // BranchAを取ってくる。FETCH_HEADがそれを指す
> git merge FETCH_HEAD           // BranchB上で実行。 BranchBがM1を指す
```

### Aさん
Bさんの作業内容を取得してマージ。そこから更に2つコミットを作成。

```
> git fetch /path/to/RepoB BranchB      // RepoBのBranchBのコミットを取得
> git checkout FETCH_HEAD -b BranchA2   // M1をBranchA2ブランチを作成してcheckout
> echo work in BranchA2 > file1.txt
> git commit -a
> echo another work in BranchA2 > file2.txt
> git commit -a
```

### Bさん
同様にM1の先にコミットを作成。BranchBがM1を指しているのでそのまま作業、コミットを2つ作成。

```
> echo work in BranchB > WorkInB.txt
> git add WorkInB.txt
> git commit
> echo another work in BranchB > WorkInB.txt
> git commit -a
```

### Aさん
Bさんの作業内容をマージ

```
> git fetch /Path/to/RepoB BranchB
> git merge FETCH_HEAD                // BranchA2上で実行。BranchA2がM2を指す
```

### Bさん
Aさんの作業内容を取得

```
> git fetch origin BranchA2
> git checkout FETCH_HEAD -b BranchB2  // M2から作業を進めたい場合はブランチを作成してcheckout
```

## 課題2
実際にやってみると以下のようになります。

```
$ git fetch https://github.com/JugglerShu/dotfiles master
warning: no common commits
remote: Enumerating objects: 117, done.
remote: Total 117 (delta 0), reused 0 (delta 0), pack-reused 117
Receiving objects: 100% (117/117), 77.19 KiB | 264.00 KiB/s, done.
Resolving deltas: 100% (49/49), done.
From https://github.com/JugglerShu/dotfiles
 * branch            master     -> FETCH_HEAD
```

なんか、動作しているように見えますね。gitからするとコミットは、コミットでしかありません。`fetch`によってあるコミットを取ってこいと言われれば取ってきます。今回も取ってきました。ここで、

```
git checkout FETCH_HEAD
```

とすれば、実際に`https://github.com/JugglerShu/dotfiles`のmasterが指しているコミット内容がワーキングツリーに展開されます。

このとき、このリポジトリのコミットグラフは以下のような状態になっています。

![image.png](https://qiita-image-store.s3.amazonaws.com/0/5636/6d73b58f-5117-bded-1926-a4389cc3ae69.png)

上図のように、`dotfiles`リポジトリ内のmasterが指しているコミットをこちらのリポジトリ内に取り込みます。仮に`dotfiles`リポジトリが上図のように4つのコミットから構成されているとすると、`master`を取り込むには、そのParent及びすべての先祖のコミットが必要になるので、`C1`〜`C4`まですべてこちらに取り込みます。両リポジトリ間に共通するコミットはないので、2つの独立したコミットグラフが人るのリポジトリ間に存在するような形になります。

このようなリポジトリの形は比較的特殊な形ではありますが、時としてこのように完全に独立したものを一つのリポジトリで管理するようなこともありますし、できます。

# チーム開発その2

今回は前回に続いてチーム開発での操作についてやっていきます。

リモートリポジトリとローカルリポジトリでの同期、連携の続きです。前回は`git fetch`を用いてコミットを取得しました。

今回は`git push`と`git pull`いうコマンドを主に見ていきますが、あとで説明するように`git pull`は使わなくて大丈夫なので、`git push`だけ理解すれば大丈夫です。

`git push`や`git pull`はGitHubを使うといきなり出てくるので、なんとなくサーバーにコミットをアップロードする、ダウンロードするというような意味で利用している人もいますが、実際に起きることはそれだけではありません。そのため、これらのコマンドを使った結果、よくわからないコミットグラフの状況にローカルリポジトリもリモートリポジトリもしてしまうという状況に陥る人がいるのではないかと思います。

これらのコマンドを適切に利用するにはコミットグラフとそれに関係するブランチがどう更新されるかを理解しておく必要があります。

## git push
リポジトリ間のコミットのやりとりは、`git fetch`を用いて自分のリポジトリに必要なコミットを取り込むのが基本ですが、こちらからコミットを送信こともできます。それが`git push`です。もちろんこれをするには対象リポジトリへの書き込み権限がなくてはいけません。

通常のチーム開発では人のリポジトリへの書き込み権限があることはありません（あったら嫌ですよね）。
`git push`を使うのは他人のリポジトリへの書き込みではなく、自分で管理する2つ以上のリポジトリ間でやり取りする場合、または全員で共有しているリポジトリへコミットを送信する場合です。GitHubを利用している場合もこれに当たります。

ただし、`git push`を`git fetch`の逆の操作と考えるのはよくありません。
gitのhelpを読むとそれぞれの説明は以下のようになっています。

```
git-fetch - Download objects and refs from another repository
git-push  - Update remote refs along with associated objects
```

`git fetch`が**Download objects**であるというのに対して、`git push`は**Update remote refs**です。ここでrefsというのはブランチのことだと思ってもらえればよいです。つまり**リモートリポジトリに存在するブランチを更新する**のが`git push`です。

`git fetch`ではどちらのリポジトリもブランチが更新されることはありませんでしたが、`git push`はそうではありません。

具体的な操作を通して動作を見ていきたいと思います。

新しいリポジトリ(RepoA)を一つ作成し、それをクローン(RepoB)し、RepoBをローカルリポジトリ、RepoAをリモートリポジトリとします。(クローンしたRepoBがローカルであることに注意してください。)

```
$ mkdir RepoA
$ cd RepoA
$ git init
$ echo file1 > text1.txt
$ git add text1.txt
$ git commit                    // RepoAにコミットを一つ作成
$ git checkout --detach HEAD    // HEADにあるコミットを直接checkout (HEADはmasterではなくコミットを直接指す状態に）
$ cd ..
$ git clone RepoA RepoB         // RepoBをローカルとして利用
```

`git checkout --detach HEAD`の部分が特殊です。これはこの後このRepoAに対して`git push`しようとしたときに、masterをcheckoutしている(`HEAD`が`master`を指している)とそれができないのでmasterではないものをcheckoutしている状態にするためです。
![image.png](https://qiita-image-store.s3.amazonaws.com/0/5636/4af094d9-e49e-27f9-e475-e378f580d3ab.png)


git cloneするとなぜかRepoB側ではmasterがcheckoutされた状態になるようです。理屈を考えると不思議な動作ですがそうなるようです。

次に、RepoBでコミットをmaster上に一つ作成します。

```
$ echo edit file1 > text1.txt
$ git commit -a
```
![image.png](https://qiita-image-store.s3.amazonaws.com/0/5636/c14a8f7e-21ab-ad1d-d5a5-ac9caedcf668.png)


そして、このコミットを`git push`を用いてRepoBからRepoA側に送信します。

```
$ git push origin master:master         // RepoB内で実行
```

RepoBはRepoAからcloneしているので、リモートリポジトリ`origin`はRepoAを表しています。

![image.png](https://qiita-image-store.s3.amazonaws.com/0/5636/b2dd70aa-3333-f5d1-447d-df47e946d8c2.png)


`origin`が送信先(push先)リポジトリを示すことは理解できると思います。その後の引数`master:master`が少し特殊です。
`:`で区切られた前半は送信するべきこちら側のコミットを指定します。今回は`master`の指しているコミットを送信しようとしているので`master`を指定しています。
後半の`master`は、送信先の更新するべきブランチを示しています。この指定によりリモートリポジトリの`master`が今転送したコミットを指すように更新されるということになります。
この部分が`git fetch`とは大きく異なる部分です。`git fetch`はローカルもリモートもブランチが移動されることはありません。

このコマンドを言葉で表すなら

RepoBにある`master`の指すコミットをRepoAに送信し、そのコミットを指すようにRepoAの`master`を更新せよ

となります。

先程、一度`HEAD`を`master`から外したのは、このときHEADが`master`を指しているとそれができずにエラーになってしまうためです。RepoA側でcheckoutしている`master`が知らない間に移動していたら困ってしまうので。

いま、更に追加で以下のコマンドを実行したらどうなるでしょうか？

```
$ git push origin master:new_branch
```

リモート側で更新するべきブランチを`new_branch`にしていますが、そのようなブランチはRepoA内には存在しません。その場合は新しくブランチ作られます。

![image.png](https://qiita-image-store.s3.amazonaws.com/0/5636/6fcfa41d-373e-8dc1-abc9-b10cd6a54354.png)

今回もgitはまず、RepoB内で`master`の指すコミットをまずRepoAに送信しますが、すでに同じコミットがRepoA内に存在するのでコミットの転送は実際には起きません。そして、RepoA内で`new_branch`がそのコミットを指すように作られます。

逆に、RepoB内でmasterとは全く関係のないブランチを作成して、それをRepoAのmasterが指すように更新することもできます。

```
$ git checkout -b my_branch
$ echo new file > text2.txt
$ git add text2.txt
$ git commit
```

![image.png](https://qiita-image-store.s3.amazonaws.com/0/5636/670162fe-bd91-1791-ecf3-e9d34d811812.png)



```
$ git push origin my_branch:master
```

![image.png](https://qiita-image-store.s3.amazonaws.com/0/5636/99f59a7c-7107-6dd8-f4f2-41558dee7a84.png)



`git push`の動作はこのようになっているので、実行する際には今転送しようとしているこちらのコミットがリモート側のどのブランチで示されるべきかを考える必要があります。

ただし、現実的なシナリオでは両リポジトリ間で同じブランチ名を利用することが多いです。そのためコマンドとしては

```
$ git push RepoA master:master
```
のように`:`の両側が同一になることが多いです。この場合省略して

```
$ git push RepoA master        // == master:master
```
と書くことができます。 

(この説明は正確ではなく、省略した場合に`:`の両側が異なるように解釈される場合もありますが特殊な場合なので今は気にしなくて良いと思います。)


### Pushできないパターン

さて、このように`git push`はリモートリポジトリのブランチの位置を移動させるので、ある意味では危険です。素直に考えれば突然リモートのブランチが今までの履歴の流れとは別の場所を指し示すようなことにもなりかねません。

以下のようなシナリオを考えます。RepoBでmasterの流れとは全く別の流れを作って、それをRepoAのmasterにpushしてみます。

```
$ git checkout HEAD~2 -b my_branch2  // 最初のコミットをmy_branch2を作成しながらcheckout
$ echo another file > text3.txt
$ git add text3.txt
$ git commit                        // `master`とは別方向にコミットを進める
```

![image.png](https://qiita-image-store.s3.amazonaws.com/0/5636/00cb7541-e13d-9222-3b14-b36d56714273.png)


この状態で、このブランチをpushして、RepoAのmasterを更新してみます。さて、どうなるでしょうか？

```
$ git push origin my_branch2:master
To /home/shu/develop/RepoA
 ! [rejected]        my_branch2 -> master (non-fast-forward)
error: failed to push some refs to '/home/shu/develop/RepoA'
hint: Updates were rejected because a pushed branch tip is behind its remote
hint: counterpart. Check out this branch and 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.
```

![image.png](https://qiita-image-store.s3.amazonaws.com/0/5636/3a0461c4-db65-46c1-5ee1-89e5b09d8b4c.png)


コマンドの意味合いとしては上図のRepoA内に点線部分の`C4`のコミットができて、それを`master`が指すように更新されるはずです。
しかし、実際にはこのような操作はgitがエラーとして実行してくれません。RepoA内の`master`は、現在の位置から子供の方向にしか移動させることができないようになっています。このようにして、ある程度RepoA内での状態がおかしな状況になることを防いでくれています。

時としてどうしても今の流れとは別の場所にブランチを持っていきたい場合がありますが、その場合は`-f`オプションを付けることで可能です。

```
$ git push -f origin my_branch2:master
```

これによってもともとイメージしたような状態にRepoAがなります。通常の流れとは別の場所にブランチを持っていくことになるので、注意して使いましょう。（特にこの後に説明するリポジトリを共有する形で開発を進めている場合には基本やるべきではありません。）

## git pull

`git fetch`と似たようなコマンドに`git pull`があります。

**結論から言えば、`git pull`は使わなくていいです。むしろ、使わないでください。**

使う場合は以下をしっかり読んで完全に理解してから使ってください。使わない場合は読まなくていいです。

一言で説明すると

  `git pull` = `git fetch` + `git merge FETCH_HEAD`

です。

なので本来必要のないコマンドです。ただよく行うオペレーションなのでそのためのコマンドが用意されているというだけです。このコマンドは注意が必要で、それは後半の`git merge`の部分です。勝手にマージが実行されます。`git merge`はマージコミットを作成します。つまり、`git pull`は新たなコミットを作ります（場合によっては作らないこともありますが。）。さらに、現在作業しているブランチもその新たなコミットに移動させます。`git merge`は現在checkoutしているブランチ上で実行され、そこにマージされてしまうのです。

`git pull`はfetchしようとしているコミットが確実に自分の現在作業中のブランチにマージされても問題ないという自信のあるときしか使えません。筆者の場合しょっちゅうfetchすべきブランチを間違えたりするので、まずこのコマンドは使いません。fetchしてから確かに自分が思っていたコミットを取得したと確認してからmergeします。


## `git pull`と`git push`の省略形

よくgitの使い方で`git push`や`git pull`を引数無しで実行している例を見かけるかと思います。
しかし、これらは**リモートブランチ**,**アップストリーム**,**トラッキングブランチ**といういくつかのgitの機能を理解しておかないと正しく動きを把握できません。
ですので、個人的には省略形を使うのはおすすめしません。省略せずにきちんとコマンドを使ったほうが正しく使えます。

使うのであればそれらの概念を理解してからにしたほうが良いと思います。コマンドの引数が省略されている以上、省略されている部分がgitによって補完されるわけですが、それらが何になるのかが把握できないと思わぬ状態に陥ります。

この部分を説明するとかなり長くなるのと、知らなくてもなんとかなるのでここでは説明しません。
興味のある方は以下を見てみてください。
https://git-scm.com/book/ja/v2/Git-%E3%81%AE%E3%83%96%E3%83%A9%E3%83%B3%E3%83%81%E6%A9%9F%E8%83%BD-%E3%83%AA%E3%83%A2%E3%83%BC%E3%83%88%E3%83%96%E3%83%A9%E3%83%B3%E3%83%81

リモートブランチぐらいは知っておくと便利かもしれません。


## リポジトリの連携パターン

ここまでは2つのリポジトリを用いて一般的なコミットのやり取り、ブランチの更新の方法を見てきました。

あとはこれを応用して複数人で開発を進める場合にもお互いにコミットを交換したりブランチを更新するなどして進めればよいです。

一方でgitはある一定の仕組みを提供しているだけで自由度が高いためそうは言われてもどうしてよいのか分からない部分もあると思います。
きちんとgitの仕組みを理解していればどのような状況でも対応できるのですが、一定のパターンがあった方が最初は楽に進められるのは確かです。

ここでは代表的な2つの複数のリポジトリの連携パターンを紹介します。実際はここに示したパターンで使われているいくつかの要素を組み合わせて実際のプロジェクトの運用方法を構築することになると思います。

### パターン1 : 一つのリポジトリをみんなで共有
これはどちらかというとSubversionなどの中央管理型の仕組みに近い形でgitを運用する場合のパターンです。すべての人が一つのgitリポジトリに対して書き込み権限を持った状態で開発を進めていきます。

![image.png](https://qiita-image-store.s3.amazonaws.com/0/5636/de766a9e-df2e-9fef-43f9-6ab404f0e55e.png)


中央にリポジトリを作成し、それを全員がcloneします。通常は中央にSSHサーバーやGITサーバー（gitプロトコルで接続できる)などでアクセスしcloneします。

各自が自分の担当分をローカルリポジトリ上で開発しコミット、pushすることで中央のコミットグラフを成長させていきます。

ただし、全員がmaster上で作業してコミットを進めていくとそれぞれのコミットがローカルリポジトリ上で別の方向に進んでいき、pushできない状態になってしまいます。

そのため、masterは常にひとつの方向に進めるように全員がルールを守る必要があります。

例えば以下のようにします。

`git clone`して、別ブランチをmasterの位置で作成しcheckoutします。

![image.png](https://qiita-image-store.s3.amazonaws.com/0/5636/b15ee320-b5ce-0aed-505a-e0e013e89096.png)


別ブランチ上で必要な修正などを入れコミットを作成します。それと同時にリモートリポジトリでは誰かが`master`ブランチを更新したという状況を考えます。

![image.png](https://qiita-image-store.s3.amazonaws.com/0/5636/6dd1a904-ae43-b584-1cf5-58f51937165a.png)


`C2`をリモートリポジトリにpushしたいですがこのままではできません。そのためまずリモートから最新の`master`を取得し、ローカルの`master`を更新します。

![image.png](https://qiita-image-store.s3.amazonaws.com/0/5636/8a2658ff-f734-90c2-2050-183bd7142f41.png)


`C2`の変更を`master`に取り込みたいのでローカルで`C2`を`master`にマージします。

![image.png](https://qiita-image-store.s3.amazonaws.com/0/5636/4321dfc2-256c-8f73-efb2-a621df0f6907.png)

最後にできあがった`master`をリモートにpushします。

![image.png](https://qiita-image-store.s3.amazonaws.com/0/5636/c0ec8061-7826-c725-638b-825d381c4751.png)

(左右でグラフの形が異なるのに意味はありません。論理的なつながりが同じであれば同じコミットグラフになります。)

このようにするとmasterは常に一定方向に進むことになります。コミットグラフの枝分かれは常にローカルブランチでのみ発生します。

現実的な開発ではこの方法にも問題点はたくさん存在します。たとえば、中央リポジトリのmasterを誰でも更新できます。このルールは守ることが前提ですが守られないこともあるかもしれません。誰かの作成したコミットにバグが含まれていて、それをmasterが指すこともあるかもしれません。誰かが間違えたコマンドを実行すれば、たちまち全員の開発に影響を与えます。

そのため、この運用方法は少ない人数でそれぞれしっかりコミュニケーションが取れる状態でないと運用が難しいです。

このパターンを取りながらも、もう少し手軽にこの問題点を解決する方法としては、ブランチをマージする人を固定しておくという方法があります。開発を進める人はマージはせずに、常に自分の作成したブランチをリモートリポジトリ上にPushするようにします。それを見たマージ担当が者必要に応じてそれをmasterにマージしていきます。このようにすると、masterが先に進むのはマージ担当者がブランチをマージしたときのみになります。加えてブランチの名前付けの規則なども導入しておけば比較的混乱なく作業を進められると思います。

### パターン2 : それぞれが独立 階層型に管理

パターン1だと、中央のリポジトリに誰でも自由に変更を加えられるという問題があるので、それを改善するパターンを考えてみます。また、より大きなプロジェクトに対応できるように全体の管理を階層化してみます。
ここではパターン1に加えて２つのことを同時に変更しているので混乱しないようにしてください。どちらか一つだけでも運用に取り込むことはできます。

例として、開発全体を2つのチームに分け、それぞれが別々の部分を開発し、それを最終的に統合して一つのプロダクトを作成するような体制を考えます。それぞれのチームは3人おり、うち1人がリーダです。さら、開発全体をまとめる人が1人いるような体制を考えます。

この組織を表現するようにリポジトリを用意し、上位のリポジトリ管理者が下位リポジトリからコミットを吸い上げる(fetchする)形で運用していきます。

![image.png](https://qiita-image-store.s3.amazonaws.com/0/5636/ed73f5b5-ddb9-5baa-5d51-210664cc09ed.png)


下位リポジトリは定期的に上位リポジトリからコミットをfetchして開発してきます。重要な点は、それぞれのリポジトリにはそのリポジトリの所有者しか変更権限がないということでです。`git push`が存在しません。

全体をスムーズに運営するために以下のようなルールを決めておきます。

  - 下位リポジトリは上位リポジトリをcloneする
  - 下位リポジトリではmasterにはコミットを作成しない
  - 下位リポジトリでは定期的に上位masterをfetchしてくる
  - 下位リポジトリでコミットを進める場合にはmasterから新ブランチを作成して進める
  - 最終的にマージして良いコミットが出来上がったら上位リポジトリ管理者に伝えて上位リポジトリでマージしてもらう

この流れをリーダー(上位)、と開発者(下位)のペアで見てみます。

下位リポジトリは上位リポジトリをcloneしますし、ブランチを作成して作業を進めます。

![image.png](https://qiita-image-store.s3.amazonaws.com/0/5636/19646106-ed68-55fd-e909-f9e021233af4.png)

下位リポジトリでコミットを作成します。同時に上位リポジトリには別の下位リポジトリからの修正が取り込まれたという状況を考えます。

![image.png](https://qiita-image-store.s3.amazonaws.com/0/5636/4c316418-67aa-6c65-c543-9208c79c0967.png)

ここからが先程の共有パターンと少し変わるところです。下位リポジトリを持つ開発者はリーダーに対して`C2`が完成したので自分の`branch`を`master`に取り込んでほしいと伝えます。そして、まずリーダーはそれをfetchします。

![image.png](https://qiita-image-store.s3.amazonaws.com/0/5636/9dcf27f8-e73c-5304-c30d-a2970a5067e1.png)

リーダーは自分のリポジトリの取り込んだ`C2`の内容を確認し`master`に取り込んで良いかチェックします。大丈夫そうならマージします。

![image.png](https://qiita-image-store.s3.amazonaws.com/0/5636/5f9f0e46-732d-ecdb-ce6e-4e38441e63fa.png)

このようにすることで、上位リポジトリのmasterに入るコミットは常に上位の管理者が管理をすることになります。仮に下位リポジトリで誤ってmasterにコミットを作成したとしても、最上位リポジトリ管理者がそれをfetchしたりmergeしたりしない限り全体への影響はありません。

下位開発者がさらに開発を進めるには再度上位リポジトリの`master`をfetchし、そこにブランチを作成してから進めます。

![image.png](https://qiita-image-store.s3.amazonaws.com/0/5636/d00ab5b4-6ee8-cc0b-c6a2-ddfda2ba9d89.png)


この方法にもいくつか問題はあります。

1つ目は、それぞれのリポジトリがサーバーとして動作していないといけないという点です。通常は別マシン上でそれぞれが開発するはずなので、それぞれのマシンにSSHサーバーなりを立てて、上位や下位から通信できる状態にしておかないといけません。

もう一つは、上位にfetchすべきブランチを伝えなくては行けない点です。これはどうしようもないのですが、もう少しスマートな方法が欲しいものです。

そして、これらの問題を解決するものこそがGitHubになります。

次回はGitHubを用いて、このチーム開発の進め方を見ていきたいと思います。


## 課題

`git push`の使い方を理解するために二人でペアになり、一つのリポジトリを共有して開発を進めてみましょう。
二人をAさん、Bさんとします。一人で行う場合には一人二役で行ってください。

1. 二人で共有するリポジトリを作成しましょう。このリポジトリはAさん、Bさん、二人から書き込みができる必要があります。
   SSHサーバー上にリポジトリを作成する場合、二人で共通のSSHアカウントを利用することで一つのリポジトリに二人共書き込める状況を作れます。
   (ここでは簡単に、Aさんのホームディレクトリ内に適当なリポジトリを作成してAさんのアカウントを共有する形で問題ありません。)

   リポジトリを作成するには以下のコマンドを利用します。

```
$ mkdir Project1
$ cd Project1
$ git init --bare   // <----- オプションに注意
```

ここで作成したリポジトリを共有リポジトリと呼ぶことにします。

`git init --bare` が初めて見るオプションかと思います。これはこのリポジトリで基本的に直接ワーキングツリーを使って編集を行ったりしない場合に使います。今回はこのリポジトリはAさん、Bさんにcloneされて利用されるのでこのようにしていします。（このようにするとこのリポジトリいおいてはどのブランチもチェックアウトされていない状態が作れます。)


2. 次に、Aさん、Bさんともにそのリポジトリをcloneします。共有リポジトリと合わせて3つのリポジトリが出来上がります。

ここからは、あまり具体的にgitの操作を指示しません。代わりに実現したい開発上の作業を示しますので、それを実現してください。方法はたくさんあるので自由に実現してください。AさんとBさんのリポジトリ間はfetchやpushはしません。すべて共有リポジトリ経由でやり取りしてください。

3. Aさんはリポジトリに最初のファイルtextA.txtを作成します。これはBさんとも共有するべき内容なので共有リポジトリにpushします。そしてBさんに続きの開発を任せました。

4. Bさんは、Aさんの作成したtextA.txtに修正を入れる必要があるので、その修正を入れ共有リポジトリにpushします。

5. ここから、Aさん、Bさんは別々の作業に入ります。Aさんは、最新のtextA.txtに修正を入れていきます。一方Bさんは、textBを作成して自分の開発を進めます。

6. 二人の作業内容をマージし、共有リポジトリにpushしてください。共有リポジトリ上のmasterブランチがそのコミットを指すようにしてください。やり方はたくさんあります。