新入社員の為の理解したら大体はGitで困らなくなるgitコマンドチート


始めに

こんにちは。
git、奥が深いですね。
ここに載ってるコマンドの意味を理解して使うことが出来れば恐らくあまりgitに困らなくなるんじゃないかな?
というチートシートを作成しました。
gitとは?という解説は載っていませんが、調べたらすぐ見つけられて有意義な記事はいっぱいありますので、今回は載せておりません。
参考程度に読んでみてください。

設定とか

gitに自分の名前とアドレスを登録(コミットする時のユーザーとアドレスを登録)

#### ユーザーとして登録全てのリポジトリに登録
$ git config --global user.email "you@example.com"
$ git config --global user.name "Your Name"

#### そのリポジトリに対して登録
$ git config user.email "you@example.com"
$ git config user.name "Your Name"
  • ~/.gitconfigにはこんな感じで入ってくる
[user] 
    name = sample-user 
    email = sample@gmail.com

WSL2環境下でgitを使う(Windows+WSL2限定)

  • 何も気にせずWSL2環境下でvscodeとかでgitを使おうとすると作業出来ないことがある
  • git statusすると以下のようなエラーが出ることがある
root:/home/hoge## git status 
fatal: detected dubious ownership in repository at '/home/hoge' 
To add an exception for this directory, call: 
        git config --global --add safe.directory /home/root/hoge
fatal: detected dubious ownership in repository
  • Git がリポジトリの所有権に関して安全でないと判断するとエラーがでる
  • リポジトリのファイルやディレクトリが予期しないユーザーやグループに属している場合に発生

以下で解決する

  1. VSCode を閉じる
  2. WSL のターミナルを開く
  3. Git の安全なディレクトリのリストに問題のディレクトリを追加
    • ターミナルで次のコマンドを実行します
    • $ git config –global –add safe.directory /home/hoge
    • これは、Git に /home/hoge ディレクトリが安全であると認識させ、所有権の警告を無視させる
  4. その後、VSCode を再び開き、ディレクトリを開いて変更を続ける
  5. この時点で、Git の差分が正しく表示されるはず

改行コードの設定(Windows向け)

## core.autocrlf を設定(例: windowsはtrue を指定推奨linuxはinput
#### コミットチェックアウトした際の改行コードの設定
git config --global core.autocrlf true

## core.eol を設定(例: lf をデフォルトに
#### 新しいファイルがリポジトリに追加されるときの改行コード
git config --global core.eol lf
  • autocrlf
    • true
      • リポジトリ内のファイルをコミットする際に CRLF から LF に変換
      • チェックアウトする際には LFCRLF に変換
    • input
      • リポジトリ内のファイルをコミットする際に CRLF から LF に変換
      • チェックアウトする際には変換を行わない
    • false
      • 改行コードの変換を行わない
      • ファイルの改行コードがそのまま保持される
  • eol
    • lf: リポジトリ内のすべてのテキスト ファイルの改行コードを LF に設定
    • crlf: リポジトリ内のすべてのテキスト ファイルの改行コードを CRLF に設定
  • ※基本、VScodeは、Gitの設定を尊重する
    • VScodeで新しいファイルを作成→Gitで管理していると、Gitの設定によって改行コードが変換される
  • ~/.gitconfigにはこんな感じで入ってくる
 [core] 
     eol = lf 
     autocrlf = true

シンボリックリンクの変換設定

  • Windowsはシンボリックリンクを認識できない
git config --global core.symlinks true

Git for Windowsでシンボリックリンクを扱えるようにする

Gitへ移行して、シンボリックリンクにはまったお話 (Usersにシンボリックリンク作成権限を付与するまで)

commitメッセージを扱うエディタをvimに指定

## そのユーザーに設定
$ git config --global core.editor "vim"

## そのリポジトリに設定
$ git config core.editor "vim"
そのリポジトリに対しての設定
#### そのリポジトリに対して設定
vi <リポジトリのディレクトリ>/.git/config
  • 以下入力する内容
 [core] 
     editor = vim
グローバルに設定
#### ユーザーの直下で
vi <リポジトリのディレクトリ>/.git/config
  • ~/.gitconfigにはこんな感じ
 [core] 
     editor = vim

既存のリポジトリから新しいリポジトリへのコードの移行

  • 既存のリポジトリをベースに作業を進める際、自身のGitリポジトリを使用したい

新しいリポジトリへのプッシュ:

## 既存のリモートoriginを削除
git remote remove origin

## 新しいリモートリポジトリをoriginとして追加
git remote add origin 新しいリポジトリのURL

## ブランチを新しいリポジトリにプッシュ
git push -u origin ブランチ名

チェックアウト系

ローカル

自分がいるブランチを知る
$ git branch

ローカルとリモートの差を知る(現在のGitブランチの状況を知る)

$ git branch -vv
  • こんな感じで返ってくる
sample@sample-app01:~/app$ git branch -vv
* AAA-001 26895f2 [origin/AAA-001: behind 2] Merge pull request ##82 AAA-998 into AAA-686
  AAA-002 800a7b8 [origin/AAA-002] セッションを保存する為のディレクトリを生成するようにDockerfileに追記 
  master d406f30 [origin/master] Merge pull request ##80 AAA-999 into master
  • 米印の箇所は今いるブランチ
  • 最後のコミットは 26895f2 で、「Merge pull request ##82 AAA-998 into AAA-686」
  • このブランチは origin/AAA-001 ブランチをトラッキングしている
    • リモートブランチに対して2つのコミットで「behind」、遅れている。
    • aheadは進んでいることを表す

新しいブランチを作成(ローカル)

$ git branch <新しいブランチ名>

任意のブランチにチェックアウト (ローカル) ※あまり使わない・古いgitでも使える

$ git checkout <ブランチ名>

任意のブランチにチェックアウト(ローカル) ※使う・古いgitでは使えない

$ git switch <ブランチ名>

ブランチ作成+チェックアウト(ローカル) ※あまり使わない・古いgitでも使える)

$ git checkout -b <新しいブランチ名>
  • branchのb

ブランチ作成+チェックアウト(ローカル) ※使う・古いgitでは使えない

$ git switch -c <新しいブランチ名>
  • createのc

ブランチ削除(ローカル)

$ git branch -d <削除したいブランチ名>
  • マージされているかチェックもする
  • マージされていない場合、Gitは削除を拒否する

ブランチ削除 強制(ローカル)

$ git branch -D <削除したいブランチ名>
  • ブランチがマージされているかどうかに関わらず、ブランチを強制的に削除

headを過去に移動する

$ git checkout HEAD^
$ git checkout <commitのハッシュ>
$ git restore --source=HEAD^ 
$ git restore --source=<commitのハッシュ>
  • HEAD^は直前
  • restore は「結果的に同じになる」というだけ
    • 目的が違う
      • checkout:切り替え
      • restore :リセット
  • ※switchは出来ない

特定のcommitがどのブランチに属しているか確認する

$ git branch --contains HEAD
$ git branch --contains コミットのハッシュ

直前にいたブランチに切り替える

$ git switch -
$ git checkout -

リモート

チェックアウト出来るリモートのブランチを知る
$ git branch -r

#### 以下2行は同義
$ git branch -r | grep aaa
$ git branch -r --list '*aaa*'
  • remoteのr

fetchする

$ git fetch

リモートのブランチにチェックアウト ※あまり使わない・古いgitでも使える

$ git checkout -b [新しいローカルブランチ名] [リモート名]/[リモートブランチ名]

exa)
$ git fetch
$ git checkout -b feature/sample-111 origin/feature/sample-111
  • ローカルにすでに feature/sample-111 という名前のブランチが存在する場合、エラーを返す

リモートのブランチにチェックアウト ※使う・古いgitでは使えない

$ git switch -c [新しいローカルブランチ名] [リモート名]/[リモートブランチ名]

exa)
$ git fetch
$ git switch -c feature/sample-111 origin/feature/sample-111
  • ローカルにすでに feature/sample-111 という名前のブランチが存在する場合、エラーを返す

stash

スタッシュの作成

$ git stash save "スタッシュの名前"
  • saveオプションを付けないと
    • stash@{n}: WIP on [ブランチ名]: [コミットハッシュ] [コミットメッセージの一部]
      • “master” ブランチで最新のコミットメッセージが “Add new feature” であった場合、スタッシュのデフォルト名は以下のようになる
stash@{0}: WIP on master: 1a2b3c4 Add new feature

スタッシュの一覧表示

$ git stash list
  • 表示されたリストの名前を変更することは出来ない
    • 一度スタッシュされたモノは名前を変更出来ない
      • applyして、drop、再度stashする以外できない
      • ※git stash -uで未追跡分もスタッシュ出来るが、未追跡分も含めてのスタッシュは、名前指定は出来ない

最新のスタッシュを適用

$ git stash apply

特定のスタッシュを適用

$ git stash apply stash@{n}
  • nに指定した番号のスタッシュを適用
  • ※{}記号も必要

スタッシュの削除

$ git stash drop stash@{n}

最新のスタッシュを適用して削除

$ git stash pop

未追跡ファイル(新規作成ファイル等)を含めてスタッシュ

$ git stash -u
  • 未追跡のファイルもスタッシュするが、名前の指定は出来ない
    • 未追跡のファイルを含めてスタッシュする場合は、名前を指定してスタッシュすることは出来ない

最新のスタッシュの変更内容を確認

$ git stash show

特定のスタッシュの変更内容を確認

$ git stash show -p stash@{n}

add系

どのファイルが変更されたかを確認

$ git status

未追跡ファイルの変更を確認

$ git status -u

add

-- ファイルを指定してadd
$ git add index.html

-- 全てadd
$ git add .
  • こんな感じになる
 #### git statusで変更分を把握 
 user@sample-project:~/current$ git status 
 On branch AAA-123 
 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.html 
     modified: index2.html 
 no changes added to commit (use "git add" and/or "git commit -a") 
 #### addする 
 user@sample-project:~/current$ git add index.html

addした分を、addしていない状態に変更する

-- ファイルを指定して
$ git restore --staged index.html

-- 全て
$ git restore --staged .
  • こんな感じになる
user@sample-project:~/current$ git status 
On branch AAA-123 
Changes to be committed: 
    (use "git restore --staged <file>..." to unstage) 
        modified: index.html 
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: index2.html 
user@sample-project:~/current$ 
user@sample-project:~/current$ 
user@sample-project:~/current$ git restore --staged index.html 
user@sample-project:~/current$ 
user@sample-project:~/current$ 
user@sample-project:~/current$ git status 
On branch AAA-123 
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.html 
        modified: index2.html

gitが古くてrestoreが出来ない場合

$ git checkout -- .
  • 上記で再現可能

addしていない、変更したファイルの変更分をリセット

#### ファイルを指定
$ git restore index.html

#### 全て
$ git restore .

#### 上記はデフォルトで以下のオプションが付いて実行されている
#### 現在のワークツリーの最新までリセット
$ git restore --worktree .

#### 同意義だが考え方が違う
###### restore --source=hogehoge その箇所までheadを戻す作業
$ git restore --source=HEAD
###### 最新のhead(現在のcommit)までheadが移動するから結果的にaddしていない変更したファイルの変更分をリセット
  • — worktreeは
    • 指定したファイルに対して最後のコミット (HEAD) の内容でワーキングツリーをリセット

gitが古くてrestoreが出来ない場合

$ git clean -f
  • 上記で再現可能

追跡していないファイルを削除

$ git clean -f 
  • オプションを付けないと、何も走らない

未追跡ファイルの一覧表示:

$ git clean -n

ディレクトリの削除

git clean -fd
  • -d オプションは、未追跡のディレクトリも削除

commit系

commit

$ git commit -m"サンプルコミット1"
  • messageの-m
    • -mつけなければ、Vimとかが起動して、メッセージを入れろと言われる

addとcommitを一緒にやる

$ git commit -a -m "変更をコミット"
$ git commit -all -m "変更をコミット"
$ git commit -am "変更をコミット"
  • addしていないものは全てaddしてcommitする

commitメッセージにエディタを使う

#### 何かしらaddされている状態で
$ git commit -e

直前のcommitのコメントを変更する

$ git commit --amend
  • コミットメッセージや変更内容を変更した場合、それは新しいコミットとして扱われる
  • 過去のコミットを直接変更するのではなく、新しいコミットが作成される
  • 修正前のモノは、通常の git log では表示されない
    • git log --reflogで見ることが出来る
      • リポジトリの reflog を表示
        • Reflog はコミットの歴史におけるブランチや HEAD などの参照の変更履歴を記録している

直前のcommitのを内容を変更する

#### 直前のcommit内容に反映する為のコード編集を行った後
$ git add /index.html
$ git commit --amend -m "直前のコミットを変更する"
  • これで、新しいコミットが作成され、git logでは表示できなくなる
    • git log --reflogで見ることが出来る(直前のコマンド参照)
  • 上記のコマンド通りなら、直前のコミットのコメントも「直前のコミットを変更する」に変更される

直前のcommitを打ち消す

$ git reset --hard HEAD^
  • HEAD^は直前
  • --hardは変更差分が残らない(全部消す)
  • --soft変更差分が残る
  • デフォルトは --hard

push系

基本的な使い方

$ git push <リモート名> <ブランチ名>
$ git push origin master

トラッキングブランチのプッシュ

$ git push
  • ローカルブランチとリモートブランチがトラッキング関係にある場合、ブランチ名を省略

新しいブランチのプッシュ

$ git push -u origin new-feature
  • -u オプションを使ってトラッキングを設定

強制プッシュ

$ git push --f
$ git push --force
  • リモートを無理やりローカルの状態にする

ローカルを追跡対象にして新しいブランチをpush

$ git push --set-upstream origin develop

無理やりリモートを過去のローカルに合わせる

  • 扱いに注意する事!

1.どこまで過去に遡るかlogを見る

$ git log -n 30 --oneline --graph

遡りたいcommit idを控える

2.HEADを過去に移動して、そこまでコミットをリセットする

$ git reset --hard 123asdf

3.現在のHEADの状況をリモートに無理やり充てる

$ git push -f origin master

merge系

基本的な使い方

## masterブランチにAAA-001をマージ
$ git switch master
$ git merge --no-ff AAA-001 

-no-ff(基本はこれを使う) Non-Fast-Forward Merge

## masterブランチにAAA-001をマージ
$ git switch master
$ git merge --no-ff AAA-001 
  • 常にマージコミットを作成し、マージされたブランチの歴史を保持

そのままcommitを進めたみたいに(使わない)Fast-Forward Merge

## masterブランチにAAA-001をマージ
$ git switch master
$ git merge AAA-001 
  • マージされたブランチの履歴が直線的に見え、マージが明確に表示されない

pull系

基本的な使い方

#### fetchする
$ git fetch
#### リモートとローカルの差分を知る
$ git branch -vv
#### pullする
$ git pull
  • fetchとmergeを同時に行う

rebaseする****

$ git pull --rebase
  • これにより、リモートブランチの変更を現在のブランチの変更の前に配置する
  • 多大な差分があり、masterと差分を合わせたい時とかに便利

特定のリモートとブランチを指定

$ git pull origin AAA-002
  • 今いるブランチに、特定の機能(commit)を追加するときとかに使う

リビジョン範囲について

  • Gitにおける「リビジョン範囲(Revision Range)」とは、特定の二つのリビジョン(コミット、ブランチ、タグなど)間の差分や履歴を指定するための記法
  • .. または ... という記号を使用

A..B(二点間)

  • 「AからBまで」を意味 $ git log origin/A...origin/B
    • origin/A にはないが origin/B に存在するコミットを表示 $ git log HEAD..origin/master
      • 現在のブランチ(HEAD)にはないがリモートの master ブランチにあるコミットを表示

A…B(三点間)

  • AB の共通の祖先から分岐して、AB のいずれかに属するが、両方には属さないコミット $ git log origin/A...origin/B
    • 両方のブランチが共通の祖先からどのように異なる進化を遂げたかを確認
    • これは、共通しないコミットをそれぞれ表示

diff系

addされていないファイルの差分を確認(行ごとに確認)

$ git diff
  • こんな感じで表示される
user@sample-project:~/current$ git diff 
diff --git a/index.html b/index2.html 
index 07af7e0..0703ac0 100644 
--- a/index.html 
+++ b/index2.html 
@@ -277,7 +277,7 @@ function onPlayerStateChange(event) { 
    <div class="bg-text2"> 
        <p>変更1</p> 
-       <p>変更2</p> 
+       <p>変更3</p> 
@@ -338,7 +338,7 @@ function onPlayerStateChange(event) {
 }  
 +<p>pepepepe</p> 
 </div>
 
 </div>
  • index.htmlについて差分
    • 07af7e0..0703ac0
      • 07af7e0から0703ac0の間での差分を表示(リビジョンについての解説を参照)
    • — a/index.htmlが変更前で、+++ b/index2.htmlが変更後
    • @@ -277,7 +277,7 @@
      • 277から7行表示

addされていないファイルの差分を確認(単語ごとに確認)

$ git diff --color-words
$ git diff -w
  • こんな感じで表示される
    • 縦でなく、横に表示される同じ行で変更があった場合、機能する
user@sample-project:~/current$ git diff --color-words 
diff --git a/index.html b/index2.html 
index 07af7e0..0703ac0 100644 
--- a/index.html 
+++ b/index2.html 
@@ -276,8 +276,8 @@ function onPlayerStateChange(event) { 
<div id="max_width2">
<div class="bg-text2"> 
    <p>変更1</p> 
    <p>変更2</p><p>変更ddddd1</p> 
    <p>変更3</p> 
    
@@ -338,7 +338,7 @@ function onPlayerStateChange(event) { 
} 
<p>pepepepe</p> 
</div>

</div>

addされているファイルの差分を確認(行ごとに確認)

$ git diff --cached

addされているファイルの差分を確認(単語ごとに確認)

$ git diff --cached --color-words

トラッキングしていないファイルをdiffで見る

  • 出来ない
  • cat とかで見るしかない
$ cat sample.sh
sample_proj@sample-app01:~/proj/sample-app01$ git status
On branch master
Your branch is up to date with 'origin/master'.

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

nothing added to commit but untracked files present (use "git add" to track)
sample_proj@sample-app01:~/proj/sample-app01$ cat sample.sh

コミット履歴(log)

現在のブランチのコミット履歴を表示

基本

$ git log
  • コミット履歴が長い場合は、ページごとに表示される
  • q キーを押して終了

一行表示

$ git log --oneline
  • これは各コミットを一行で簡潔に表示

特定の数のコミットのみを表示

$ git log -n <>
  • 例:git log -n 5 は最新の5つのコミットを表示

グラフとして表示

$ git log --graph
  • ブランチとマージの履歴を視覚的なグラフとして表示

グラフと1行表示を組み合わせる

$ git log --graph --oneline 

他ブランチのログを見る

$ git log --graph --oneline -n 5 sample-222

特定のファイルやディレクトリの履歴を表示する

$ git log -p <ファイルまたはディレクトリ>

Aブランチには存在しないがBブランチに存在するコミットを表示

$ git log origin/A..origin/B
$ git log --oneline origin/A..origin/B
  • origin/A ブランチには存在しないが origin/B ブランチに存在するコミットを表示
    • つまり
      • origin/A ブランチの最終コミットから origin/B ブランチの最終コミットまでの間に行われたコミットをリストアップ
      • origin/B の観点から見た origin/A との差分

Aブランチ、又はBブランチにだけ存在するコミットを表示

$ git log origin/A...origin/B
$ git log --oneline origin/A...origin/B
  • このコマンドは、origin/Aorigin/B の共通の祖先から分岐した後、どちらか一方のブランチにだけ存在するコミットを表示
    • つまり
      • 両方のブランチが共通の祖先からどのように異なる進化を遂げたかを確認
      • これは、共通しないコミットをそれぞれ表示

チェリーピック

  • あるブランチの特定のコミットを別のブランチに適用する
  • 全体のブランチをマージするのではなく、特定の変更だけを取り込みたい場合

基本的な使い方

commitを残したくないとき

$ git cherry-pick --no-commit コミットハッシュ
  • 指定されたコミットの内容を適用するが、自動で新しいコミットを作成しない
  • 手動で変更を確認してからコミットすることができる

commitを残す

$ git cherry-pick コミットハッシュ

複数のコミットを選択してチェリーピック

$ git cherry-pick コミットハッシュ1 コミットハッシュ2

コミットの範囲を選択してチェリーピック

$ git cherry-pick 開始コミットハッシュ..終了コミットハッシュ

チェリーピックのキャンセル

$ git cherry-pick --abort
  • チェリーピック操作をキャンセルし、ブランチを操作前の状態に戻す

コンフリクトの解決後の続行

$ git cherry-pick --continue
  • コンフリクトを解決した後、チェリーピックを続行する