92
106

【図解解説】これ1本でGitをマスターできるチュートリアル!【完全版】

Last updated at Posted at 2024-09-29

image.png

はじめに

こんにちは、Watanabe Jin(@Sicut_study)です。

今回は記事1本で初心者が必要な知識を全て学べるGitチュートリアルを紹介していきます。
世の中にはたくさんのGitに関する教材があります。しかし、真に良いと思える教材はありません。

もちろん私も4年前はGitという言葉を知らない状態から、書籍などで学習をしました。
しかし、書籍で知識を得たとしても実際にコマンドを使って実践的に学んだわけではなかったのでほとんど身になりませんでした。

私が思う世の中にあるGitの教材のイケてない点は2つです。
 

image.png

結局ほとんどの人が、教材ではなく実際に使ってみて使えるようになっているはずです。
書籍でやったことを全部ちゃんとできるようになった人はいないと考えています。

実際に利用するコマンドは限られている、たまに使うコマンドを紹介しとしても「この記事1本」で説明することができると思って完全版の記事を書くことにしました。

このハンズオンを最後まで行うことで、現場で問題なく利用できるスキルを身につけることが可能です。

動画で学びたい方へ

こちらの記事をテキストにより詳細に解説している動画を投稿しています。
初心者の方はぜひこちらをご活用ください。

おすすめ記事

 

他にも多くの1本で学べる完全版ハンズオンを投稿しています。よければご覧ください。

 

1. Gitとは?

Gitとは世界で最も人気のあるバージョン管理システムです。
バージョン管理システムとは、コードに加えられた変更をリポジトリと言われるデータベースにバージョンとして記録するシステムです。

変更履歴を管理して見られるようにすることで、どのような変更をなぜ加えたのかを確認が可能です。履歴をみることで「誰が」「どのような変更を」「なぜ加えたのか」を確認することができます。
 

バージョン管理をしていないとどうなるのでしょうか?
 
 
バージョン管理システムがないと、コードがまとまったフォルダをまるまるコピーして残しておく必要があります。
こんなファイルみたことないですか??👇

image.png

バージョン管理には「中央集中型システム」と「分散型システム」に分類が可能です。

image.png

中央集中型システムには、SubversionConcurrent Version Systemがあります。
中央集中型では中央のサーバーに接続して最新のコードを取得します。

欠点は単一障害点があります。 もしサーバーがオフラインになってしまったとするとバージョン管理ができくなってしまいます。

image.png

その欠点をカバーしたのが「分散型システム」です。
分散型システムにはGitMercurialなどがあります。

image.png

ユーザーそれぞれにリポジトリをもつため、他のリポジトリと同期することができます。
中央に主となるサーバーがないためオフラインになる心配もありません。

 
この中でも特にGitは世界中で最も利用されるバージョン管理システムとなります。
あなたがソフトウェアエンジニアを目指すのであれば、必須のスキルになります。
 

ハンズオンを全て行うことで実際に現場で利用するGitの知識を網羅することが可能です。

3. GitHubとは?

GitとGitHubは同じように扱われることもありますが、異なるものです。

GitHubはクラウド上でGitを使ってバージョン管理できるサービスのことを表します。

その他にもWebサービスならではのプロジェクト管理の機能を利用することも可能です。

image.png

「プルリクエスト」などはGitHubで利用できる一つの機能となります。

2. Gitのインストール

ハンズオンを行う前にGitをインストールしましょう。
それぞれのOSにあった方法(Windows, Mac)でインストールを行ってください。

ここではLinuxでのインストールを紹介します。

$ apt update
$ apt install git

❯ git version
git version 2.43.0

git versionとターミナルに入力してバージョンが表示されれば完了です。

3. Gitの初期設定

まずはGitとGitHubの初期設定を行っていきます。
バージョン管理には「誰が」「いつ」「どのような変更をしたか」を記録するためにユーザー情報を付与しています。
その情報を利用前に設定する必要があります。

$ git config --global user.name "John Doe"
$ git config --global user.email johndoe@example.com

ここでは名前とメールアドレスを設定しました。globalとすることでPCのどこでGitを利用してもこのユーザー情報を付与することができます。

次にGitHubにあるクラウド上のリポジトリ(リモートリポジトリ)と、手元のリポジトリ(ローカルリポジトリ)を通信できるような設定をおこないます。

ここではSSH接続という方法で通信を行うことで、普段であれば必要なユーザー名、パスワード入力をしないでも簡単にローカルリポジトリとリモートリポジトリを同期できるようにしましょう。

 

まずはSSHで必要となる公開鍵秘密鍵を設定します。
公開鍵と秘密鍵はシンデレラのガラスの靴のような関係があります。

image.png

ガラスの靴(公開鍵)をGitHubに設定します。
そしてGitHubはアクセスが合ったときに、そのガラスの靴をはける人だけをシンデレラ(正しいユーザー)と認めてリクエストを許可します。

秘密鍵と公開鍵のペアが正しくない場合はリクエストが通らないようになっています。

まずは公開鍵と秘密鍵のペアを作成しましょう

$ cd ~/.ssh
$ ssh-keygen -t rsa
Generating public/private rsa key pair.
Enter file in which to save the key (/Users/(username)/.ssh/id_rsa):
Enter passphrase (empty for no passphrase):
Enter same passphrase again:

Enterキーを3回押せば公開鍵と秘密鍵が作成できます。

❯ ls ~/.ssh
authorized_keys  id_rsa  id_rsa.pub 

id_rsaが秘密鍵、id_rsa.pubが公開鍵にあたります。

公開鍵の内容をクリップボードにコピーします。

$ pbcopy < ~/.ssh/id_rsa.pub (Mac)
$ clip < ~/.ssh/id_rsa.pub (Windows)
$ cat ~/.ssh/id_rsa.pub | xsel --clipboard --input (Linux)

次にGitHubにアクセスします。
アカウントがまだない方は作成をしてください。

右上のアイコンをクリックするとメニューが開くので、Settingsをクリック

image.png

左メニューの「SSH and GPCG Keys」をクリック

image.png

「New SSH Key」をクリックして

Title : handson (なんでもよい)
Key : クリップボードの内容を貼り付け (Ctrl+v)

image.png

「Add SSH Key」をクリックしたら設定完了です。

$ ssh -T git@github.com
Hi jinwatanabe! You've successfully authenticated, but GitHub does not provide shell access.

このコマンドを実行してレスポンスが返ってきたら成功です。

4. リポジトリを作ろう

まずはローカルリポジトリを作りましょう。
この操作はGitを使ってプロジェクトを管理する場合に最初に必ず行う必要があります。

以下のコマンドを実行すればリポジトリを作成することが可能です。

$ mkdir git_handson
$ cd git_handson
$ git init
Initialized empty Git repository in /home/jinwatanabe/workspace/qiit/git_handson/.git/

リポジトリにすることで以降出てくるgit addgit commitなどのコマンドが利用できるようになります。

$ ls -la

合計 12
drwxrwxr-x 3 jinwatanabe jinwatanabe 4096  9月 28 11:03 .
drwxrwxr-x 3 jinwatanabe jinwatanabe 4096  9月 28 11:03 ..
drwxrwxr-x 7 jinwatanabe jinwatanabe 4096  9月 28 11:03 .git

.gitというディレクトリが作られました。
これは隠しファイルとなっているので画面から見ると表示されません

image.png

この.gitにプロジェクトのバージョン管理に関する情報が含まれています。
試しに.gitを削除してみましょう

rm -rf .git

❯ git status
fatal: not a git repository (or any of the parent directories): .git

git statusを実行するとgitレポジトリではないですと言われました。(git statusについては後で説明)

このあとのハンズオンのために再度リポジトリを作成しておきましょう

$ git init

5. Gitワークフロー

ここからはGitでプロジェクトのバージョン管理をするときの一般的なフローを紹介してい行きます。
 

あなたは開発しているシステムに脆弱性がみつかり、ハッキングをされてしまっている状況だとします。
そこでコードを修正してリポジトリに反映させようとします。ここでリポジトリに対して永続的に保存するために行うのがコミット(Commit)です。
 

image.png

 
コミットをすることで、リポジトリに変更の履歴が残ります。
しかし、一部ファイルは履歴に含めたくない(commitしたくない)と考えることもあります。

 
image.png

そこでGitにはステージング(インデックス)というコミットしたファイルを仮でおいておく場所が存在します。

image.png

ステージングに追加するファイルをaddコマンドで選択することによって、コミットに履歴に追加したいファイルだけを含めることが可能です。

image.png

もしステージングに不要なファイルが含めてしまった場合は、ステージングから特定のファイルを外すことも可能です。

ここまでの流れはざっくりこんな感じになります。

image.png

コミットをすることによって、以下の情報が変更に対して付与されるため履歴を管理できるのです。

image.png

 
ローカルリポジトリにコミットができたら、次にGitHubにあるリモートリポジトリに変更を反映します。
リモートリポジトリに反映することでクラウドから他のメンバーは最新のコードを取得することが可能です。

 
image.png

ここまでの流れをgitコマンドで実行すると以下のようになります。

$ git add [ファイル名]
$ git commit -m "どのような変更をしたかのメッセージ"
$ git push

# リモートリポジトリの変更を取得する場合
$ git pull

それでは実際にやってみましょう。
現在ローカルのリポジトリはあるので、まずはリモートリポジトリをGitHubで作成しましょう。
GitHubにアクセスして、アイコンをクリックしてメニューを開き、「Your Repository」をクリックします。

image.png

右上の「New」をクリック

image.png

Repository nameに「gith_full_course」と入力して「Create Repository」をクリック

image.png

これでリモートリポジトリが完成しました。

image.png

次にローカルリポジトリとリモートリポジトリを同期させる設定をコマンドで実行します。
「Quick setup」の選択している2行のコマンドを実行します。

image.png

$ git branch -M main
$ git remote add origin git@github.com:jinwatanabe/git_full_course.git

git branch -M mainはmainという名前のブランチを作成しています。こちらは後ほど説明します。
最後のコマンドで実行した場所のリポジトリとリモートリポジトリを紐付けています。

それではまずはステージングエリアに追加するところをやっていきます。
VSCodeで作成したリポジトリを開いてください。

そしてindex.jsというファイルを作ります。

$ touch index.js

image.png

今回は適当なコードを書いてみます。以下をコピペして貼り付けてください。

index.js
console.log("Hello Git");

それでは、git statusコマンドで状態を確認してみましょう。

$ git status

ブランチ main

No commits yet

追跡されていないファイル:
  (use "git add <file>..." to include in what will be committed)
	index.js

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

git statusコマンドを使うと、のコマンドを実行すると、どの変更がステージング済みでどの変更がまだステージングされていないのか、どのファイルが Git の追跡対象外になっているのかが表示されます。

この場合、index.jsがまだステージングに追加されていないことがわかります。
それではステージングに変更を追加しましょう。

$ git add index.js
$ git status

ブランチ main

No commits yet

コミット予定の変更点:
  (use "git rm --cached <file>..." to unstage)
	new file:   index.js

index.jsがコミットされたことがわかります。
それでは複数ファイルを次はステージングに上げてみましょう

$ touch index2.js
$ touch index3.js
index2.js
console.log("Hello Git2");
index3.js
console.log("Hello Git3");
$ git status
ブランチ main

No commits yet

コミット予定の変更点:
  (use "git rm --cached <file>..." to unstage)
	new file:   index.js

追跡されていないファイル:
  (use "git add <file>..." to include in what will be committed)
	index2.js
	index3.js

それではindex2.jsとindex3.jsをステージングに追加します。
1つずつ丁寧に追加してもいいですが複数ファイルを追加するときはもっと便利な追加の仕方があります。

$ git add index2.js index3.js

or 

$ git add .

git addに続いて複数ファイルを指定するか、.を使うことではディレクトリ配下のステージング追加されていないファイルをすべて追加することが可能です。

git add .が実際には多く利用されます。

それでは、次にコミットして履歴を追加しましょう

$ git commit -m "初めてのコミット"
[main (root-commit) f073dd5] 初めてのコミット
 3 files changed, 2 insertions(+)
 create mode 100644 index.js
 create mode 100644 index2.js
 create mode 100644 index3.js

git_handson on  main via  v22.4.0 

$ git status
ブランチ main
nothing to commit, working tree clean

コミットが終わることで、git statusから表示がなくなりました。

それでは最後にローカルリポジトリとリモートリポジトリを同期させます。

$ git push origin main

Enumerating objects: 5, done.
Counting objects: 100% (5/5), done.
Delta compression using up to 12 threads
Compressing objects: 100% (2/2), done.
Writing objects: 100% (5/5), 363 bytes | 363.00 KiB/s, done.
Total 5 (delta 0), reused 0 (delta 0), pack-reused 0
To github.com:jinwatanabe/git_full_course.git
 * [new branch]      main -> main

origin mainはオリジンがリモートリポジトリのことを指しており、リモートリポジトリのmainブランチに対して、ローカルの変更を反映させるというコマンドです。
異なるブランチにpushする場合はmainの部分が変わります (あとで説明します)

先ほど作成したGitHubのリポジトリをみるとローカルリポジトリの内容が同期していることがわかります。

image.png

6. コミットは細かくする

コミットはステージングにある変更を履歴に含めますが、なるべく細かくステージングに入れてコミットすることをおすすめします。
 

image.png

細かいコミットにしておけばピンポイントで取り消したいコミットをなくすことが可能です。(revert)
もし全部のコミットが1つにまとまっている場合、修正の一部だけを取り消すというのが難しくなります。

バグ修正中にタイポを見つけたら同じコミットに含めるのではなく、それぞれ別にしてメッセージも意味のあるものにするのが大切です。

コミットメッセージはそれぞれのコミットが何を行ったのか伝えるためにも大切です。

7. ステージングの変更を消す

index1.jsの内容を少し変更します。

index1.js
console.log("change");

変更を確認してみましょう。git diffが使えます。

$ git status
ブランチ 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:   index.js

$ git diff
diff --git a/index.js b/index.js
index bb8ec33..5e022a9 100644
--- a/index.js
+++ b/index.js
@@ -1 +1 @@
-console.log("Hello Git");
+console.log("change");

履歴に保存されているindex1.jsとの差分を表示してくれます。
それではステージングに持っていきます。

$ git add .
$ git status

ブランチ main
コミット予定の変更点:
  (use "git restore --staged <file>..." to unstage)
	modified:   index.js

index.jsの修正が間違えていたので、ステージングから戻してみます。

$ git resotre --staged index1.js
ブランチ 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:   index.js

git restore --stagedで戻すことができます。

では、index1.jsに加えた変更ももとに戻したいと思います。

$ git checkout index.js

checkoutすることによって修正ももとに戻ります。

image.png

では新しいファイルをつくりましょう

$ touch index4.js
$ git status

ブランチ main
追跡されていないファイル:
  (use "git add <file>..." to include in what will be committed)
	index4.js

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

ここでファイルを取り消すためにcheckoutしてみましょう

$ git checkout index4.js
$ git status

ブランチ main
追跡されていないファイル:
  (use "git add <file>..." to include in what will be committed)
	index4.js

新規追加されたファイルはcheckoutではもとに戻せません。
ファイルを削除すると戻すことができます

$ rm -rf index4.js
$ git status

ブランチ main
nothing to commit, working tree clean

ちなみにcheckoutはaddと同じく.や複数ファイル選択もできます。

8. 特定のファイルやでディレクトリをgitの管理外にする

次に特定のファイルやディレクトリをgitの管理対象外にするgit rmコマンドを紹介します。

まずは1つ秘密の情報が載っているファイルをcommitします。

$ touch secret.txt
secret
秘密の情報
$ git add .
git_handson on  main [+] via  v22.4.0 

$ git commit -m "色々開発した"
[main 9f13ec2] 色々開発した
 2 files changed, 2 insertions(+), 1 deletion(-)
 create mode 100644 secret.txt
$ git push origin main

GitHubのリポジトリにsecret.txtが追加されました

image.png

しかし気づきます。このファイルはGitHubにアップロードしてはいけないファイルだということに。
そこでsecret.txtをgitの管理外に戻したいと思います。

$ git rm --cached secret.txt 
❯ git status
ブランチ main
コミット予定の変更点:
  (use "git restore --staged <file>..." to unstage)
	deleted:    secret.txt

追跡されていないファイル:
  (use "git add <file>..." to include in what will be committed)
	secret.txt

git rm --cached [ファイル名]でgitの対象外にできます。
もしファイルも削除したい場合はgit rm [ファイル名]で対象から外してファイル削除まで可能です。

いまのままでは追跡されていないファイルにsecret.txtがあり、addしてしまう可能性がありますので、ここにも表示されないようにgitから完全に対象にならないよう設定してきます。

そこで利用するのが.gitignoreです。

$ touch .gitignore

このファイルにgitの管理対象にしたいファイルやディレクトリを選択することができます

.gitignore
secret.txt

VSCodeをみるとsecret.txtのファイルが削除されたことに成ります。
これはgitで管理から削除されてなくなったことを表しています。

image.png

では、pushまでやってきます。

$ git add . // .gitingnoreファイルをステージングへ
$ git commit -m "秘密のファイルを削除"
$ git push origin main

GitHubからsecret.txtが消えました

image.png

ここで注意が必要なのは一度Pushしてしまうとクラウドに履歴が残ってしまうため、完全に削除することは不可能です。シークレットな情報をクラウドにあげてしまうと、誰かに見つかってしまった場合悪用されることに繋がります。AWSのシークレットキーが流出した場合はAWSのリソースを気づかないうちに使われて高額請求につながることがあります。秘密の情報は.gitignoreに追加するのを忘れないでください。

それでは次にディレクトリごとgitの管理外に設定したいと思います。

$ mkdir log
$ touch log/log1.txt
$ touch log/log2.txt

そしてGitHubにpushします。

$ git add .
$ git commit -m "logを追加"
$ git push origin main

ログがGitHubに追加されました。

image.png

しかし思いました。ログを管理する必要はないのでバージョン管理から外したい。
そこでlogディレクトリをそのまま管理外にしてみます。

$ git rm --cached log
fatal: not removing 'log' recursively without -r

しかし上手く行きません。ディレクトリの中身も含めてgitの対象外にする場合は-rをつける必要があります。

$ git rm --cached -r log
rm 'log/log1.txt'
rm 'log/log2.txt'

上手く行きました。では.gitignorelogディレクトリを設定しておきましょう

.gitignore
secret.txt
log

logディレクトリが薄くグレーアウトしています。これはgitの管理から外れていることを意味しています。

image.png

それでは現在の状態をクラウドに反映してlogディレクトリを消しましょう

$ git add .
$ git commit -m "logを削除"
$ git push origin main

image.png

GitHubからも消すことができました。

9. 履歴を確認する

時々過去にどんなコミットを行ったのか見たくなることがあります。
私達はこのハンズオンで最初にどんなコミットを行ったか覚えていますか?

そこで利用できるのがgit logコマンドです。

$ git log
commit 536c9467b8a1781cd7bfd00bc760909841923593 (HEAD -> main, origin/main)
Author: jinwatanabe <jin.watanabe.6g@gmail.com>
Date:   Sat Sep 28 18:18:29 2024 +0900

    logを消した

commit 607cbb242a63cb32fe2b26ba49b5a607e18d8a12
Author: jinwatanabe <jin.watanabe.6g@gmail.com>
Date:   Sat Sep 28 18:14:14 2024 +0900

    ログ追加

commit 7c25e8c12330e7e53f6f7ba75d7ebbbc9ecdde7b
Author: jinwatanabe <jin.watanabe.6g@gmail.com>
Date:   Sat Sep 28 18:09:44 2024 +0900

    秘密のファイルを削除

commit 9f13ec22333fb03aa593ca1582012a40241755d9
Author: jinwatanabe <jin.watanabe.6g@gmail.com>
Date:   Sat Sep 28 17:58:01 2024 +0900

    色々開発した

このように過去のコミットを一覧で見ることが可能です。(:qで戻ることができます。jで上、kで下を表示します)
詳細を見る場合はgit log -p [コミットID]でみれます。

$ git log -p 9f13ec22333fb03aa593ca1582012a40241755d9

commit 9f13ec22333fb03aa593ca1582012a40241755d9
Author: jinwatanabe <jin.watanabe.6g@gmail.com>
Date:   Sat Sep 28 17:58:01 2024 +0900

    色々開発した

diff --git a/index.js b/index.js
index bb8ec33..5e022a9 100644
--- a/index.js
+++ b/index.js
@@ -1 +1 @@
-console.log("Hello Git");
+console.log("change");
diff --git a/secret.txt b/secret.txt
new file mode 100644
index 0000000..ccae75b
--- /dev/null

私はgitコマンドとは別にtigというライブラリをいれています。
このライブラリを入れてtig と打つだけで、リポジトリのログを簡単に見ることができるのでおすすめです。

image.png

10. コンフリクトの解消

リモートリポジトリに変更を加えられるのは私だけでなくチームのメンバーもできます。
今回はチームのメンバーの誰かが修正をしたとして、GitHubの画面上でコード編集をしてみます。

index1.jsを開いて、右上の鉛筆マークをクリックします

image.png

index.js
function greet() {
  console.log("Hello from the main branch!");
}

このように変更して、右上の緑のボタン「Commit changes...」をクリックします。

image.png

Commit messageに「チームの誰かが変更」としてCommit changesボタンを押します。
ここはローカルでgitコマンドを叩いているのと変わりません。

image.png

この操作はチームの誰かがやっていると仮定して、私達もindex.jsに修正をしていたとします。

index.js
function greet() {
  console.log("Hello from the local branch!");
}

それでは私達の修正をリモートリポジトリに反映したいと思います。

$ git add .
$ git commit -m "私達の修正"
$ git push origin main

To github.com:jinwatanabe/git_full_course.git
 ! [rejected]        main -> main (fetch first)
error: failed to push some refs to 'github.com:jinwatanabe/git_full_course.git'
hint: Updates were rejected because the remote contains work that you do not
hint: have locally. This is usually caused by another repository pushing to
hint: the same ref. If you want to integrate the remote changes, use
hint: 'git pull' before pushing again.
hint: See the 'Note about fast-forwards' in 'git push --help' for details.

git pushでエラーが発生しました。
リモートリポジトリが私達の手元にあるものとバージョンが変わったので、まずはリモートリポジトリの最新バージョンを手元に取得してくれと言われました。

image.png

そこでまずはpullコマンドでリモートリポジトリの最新のコードを手元に持ってきます。

$ git pull -r origin main
From github.com:jinwatanabe/git_full_course
 * branch            main       -> FETCH_HEAD
Auto-merging index.js
CONFLICT (content): Merge conflict in index.js
error: 9e3ead0を適用できませんでした... 私達の修正
hint: Resolve all conflicts manually, mark them as resolved with
hint: "git add/rm <conflicted_files>", then run "git rebase --continue".
hint: You can instead skip this commit: run "git rebase --skip".
hint: To abort and get back to the state before "git rebase", run "git rebase --abort".
Could not apply 9e3ead0... 私達の修正

するとCONFLICT (content): Merge conflict in index.jsという文章が出ました。
これこそがコンフリクトという現象です。VSCodeでindex.jsをみます。

image.png

誰かが修正したコードと私が修正したコードがかぶってしまっているために、gitではどちらが正しい修正なのか判断ができずにコンフリクトが発生しました。

image.png

この場合手元でコンフリクトの解消をおこな必要があります。
正しいコードを今回は私達のコードの方として、リモートのほうのコードを消しましょう

「Accept Current Change」をクリックすることで私達の修正を採用できます。

それではリモートリポジトリにpushまで行いましょう。

$ git add .
$ git commit -m "修正"

$ git status
interactive rebase in progress; onto 8e508ca
Last command done (1 command done):
   pick 34782ce test
No commands remaining.
You are currently editing a commit while rebasing branch 'main' on '8e508ca'.
  (use "git commit --amend" to amend the current commit)
  (use "git rebase --continue" once you are satisfied with your changes)

nothing to commit, working tree clean

git statusをみるとYou are currently editing a commit while rebasing branch 'main' on '8e508ca'.とでています。

rebaseに関しては後で説明しますのでここは以下のコマンドでrebaseを終わらせます

$ git rebase --continue
$ git push origin main

無事修正を反映することができました!

11. ブランチを作ってプルリクを作ろう

gitにはブランチという履歴を分岐する機能があります。
これまでにできているmainブランチというのが中心のブランチでそこから派生してブランチを作ることになります。

image.png

例えば、コミットCの地点でfeatureブランチを作るとします。
ここのブランチで機能Aの開発をしたとします。(コミットD, コミットE)

mainブランチでは別の作業が行われていて、コミットF、コミットGが作られました。
このときfeatureブランチの機能A開発で大きなバグが起きたとします。

image.png

しかし、ブランチが別れていればmainブランチに影響は起きません。リリースも問題なくできます。
最終的にはmainブランチに、featureブランチの内容をマージ(合わせる)ことで機能Aをmainブランチに取り込むことが可能です。

image.png

それでは実際にブランチを作成してみましょう。

$ git branch
* main

$ git branch -M feature
$ git branch
* feature

これでfeatureブランチをはやして見ているブランチを切り替えることができました
ちなみにmainブランチに戻りたい場合は、git switch mainで可能です。

それではfeatureブランチで追加の開発を行います。

index.js
function greet() {
  console.log("Hello from the main branch!");
}

greet();

関数を呼び出すようにしてみました。
それではこのブランチの変更をGitHubに反映させましょう

$ git add .
$ git commit -m "関数を呼び出した"
$ git push origin feature

ここでのポイントはpush時にfeatureブランチに対してpushしていることです。
こうすることでmainブランチに影響を与えずに開発ができます。

image.png

mainをクリックするとfeatureが表示されるようになりました。
ではこの修正をmainブランチにマージするためにプルリクエストを作ります。

「Compare & pull request」をクリックします。
プルリクエストのタイトルに概要を書きます。ここでは「関数の呼び出しを追加しました」とします。
その下のフォームに実装の詳細などを本来書いておきますが、省略します。

もう一つポイントは、その上にあるmain←featureです。
これはfeatureブランチをmainブランチに取り込むことを表しています。

プルリクを作成するために「Create pull request」をクリックします。

image.png

そしたら「Merge pull request」→「Confirm Merge」をクリックします。

image.png

もうブランチは不要なので「Delete branch」をクリックして消しておきます。

image.png

それでは実際にmainに変更が取り込まれたかを確認します。

$ git switch main
$ git pull -r origin main

remote: Enumerating objects: 1, done.
remote: Counting objects: 100% (1/1), done.
remote: Total 1 (delta 0), reused 0 (delta 0), pack-reused 0 (from 0)
Unpacking objects: 100% (1/1), 961 bytes | 961.00 KiB/s, done.
From github.com:jinwatanabe/git_full_course
   ae5b6e4..b999746  main       -> origin/main
Updating ae5b6e4..b999746
Fast-forward
 index.js | 6 ++----
 1 file changed, 2 insertions(+), 4 deletions(-)

無事反映することができました。
プルリクを活用することで大人数での開発も簡単に行うことが可能です。
またブランチをあえて作らない開発方式も存在しており、それを「トランクベース開発」と呼びます。

12. コミットをなかったことにする

ここでとある問題が発生して、先程マージしたコミットを取り消さないといけなくなりました。
コミットを取り消すものとしてrevertresetの2つがあります。

revert

リバートは対象のコミットを取り消すコミットを作成することでなかったことにします。
取り消したいコミット自体はちゃんと残り続けるのがポイントです。

image.png

実行のコマンドを紹介します。

$ git revert [コミットID]

reset

resetはコミット自体をなかったことにします。履歴が消えてしまうため1度消してしまうと後戻りができません。

$ git reset --hard [コミットID]

image.png

前回のコミットを取り消す

取り消し方には2通りありますが、基本的にはrevertを利用するようにしましょう

まずは適当なコミットを作成します。

index.js
function greet() {
  console.log("Hello from the main branch!");
}

greet();
greet();
$ git add .
$ git commit -m "不要なコミット"


$ git log
commit 1638301f2d59a47c256f53641064fbfe4454e9d9 (HEAD -> main)
Author: jinwatanabe <jin.watanabe.6g@gmail.com>
Date:   Sat Sep 28 19:38:28 2024 +0900

    不要なコミット

$ git revert [git logでみた最新のコミットID]

image.png

すると、直前のコミットを取り消すコミットのメッセージをどうするかを聞かれるので、
「Ctrl + X」で抜けます。(nanoエディタが開きます)

取り消しのコミットの詳細をみてみると、great()をなくすような変更が確認できます。

image.png

image.png

コードもしっかり戻っています。

13. マージとリベース

先程マージの挙動を解説しました。

image.png

これに似た仕組みにリベースがあります。

image.png

このようなブランチの状況だった時に、featureブランチgit rebase mainとすると以下のようになります。

image.png

ここでmainブランチとfeatureブランチがコンフリクトを起こした場合は、ステージングに修正を反映させたら、コミットではなくgit rebase --continueを実行します。

image.png

mergerebaseの違いは、コミットを作るか作らないかの差があります。
mergeであれば、2つを合わせるためのコミットをわざわざ作成していました。(作成したプルリクにcommitメッセージを書いていたのはそのためです)

image.png

git pull -rというのは、git pullをして持ってきた最新の情報をrebaseでブランチに取り込むということを表していました。

おわりに

今回は業務でよく使うコマンドから、使う回数は少ないけど必ず利用するコマンドを一通り紹介しました。
この記事をすべて行って理解することができれば仕事は安心して行うことが可能です。

使いながら1回理解しておいて、Gitを使う中で忘れてしまった時にこの記事に戻ってきていただけると良いかなと思います。

より詳細に説明した動画も用意していますのでご覧ください!

ここまで読んでいただけた方はいいねとストックよろしくお願いします。
@Sicut_study をフォローいただけるととてもうれしく思います。

また明日の記事でお会いしましょう!

JISOUのメンバー募集中!

プログラミングコーチングJISOUでは、新たなメンバーを募集しています。
日本一のアウトプットコミュニティでキャリアアップしませんか?

興味のある方は、ぜひホームページからお気軽にご連絡ください!
▼▼▼

92
106
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
92
106