20200809のGitに関する記事は4件です。

git reset は 何をリセットするのか

git resetについて、わからないことが多かったので、まとめました。
中でも、よく使うコマンドである、以下について、実験的に調べたことをまとめました。
間違いなどがありましたら、ご指摘いただけるとありがたいです。

git reset [ --soft | --hard ] [ HEAD | HEAD^ ]

結論

結論から書くと、このような挙動となる。

git reset オプション HEAD

オプション コミットされたもの ステージングされたもの ワークツリーで変更されたもの ワークツリーで新規に追加されたもの
--soft 変化なし 変化なし 変化なし 変化なし
オプションなし 変化なし ワークツリーへ移動する。 変化なし 変化なし
--hard 変化なし 変更が削除される。 変更が削除される。 変化なし

git reset オプション HEAD^

オプション コミットされたもの ステージングされたもの ワークツリーで変更されたもの ワークツリーで新規に追加されたもの
--soft ステージングされた状態に戻る。 変化なし 変化なし 変化なし
オプションなし ワークツリーへ移動する。 ワークツリーへ移動する。 変化なし 変化なし
--hard 変更が削除される。 変更が削除される。 変更が削除される。 変化なし

言葉の説明

オプション( --soft と --hard )

どのくらいresetするかの度合いを決めるもの。
hard > オプションなし > --soft の順に、resetの度合いが大きい。
オプションをつけていない時は、--soft--hardの間みたいな挙動となる。言葉からイメージしやすい。

HEAD と HEAD^

HEAD最新のコミットの状態。
HEAD^最新から一個前のコミットの状態。

以下で、実際にコマンドをうって、git resetの挙動を確かめる。見るだけではよく理解できない箇所もあるかと思いますので、一緒にターミナルで実行してみてください。

ワークツリー、インデックス、ステージング

ワークツリーで、ファイルを変更したり新規に追加したりする。
git addをすると、ワークツリーで変更されたものがステージングされ、インデックスへ移動する。
git addをすると、ステージングされインデックスにあるものが、コミットされる。

準備

こちらの4つのファイルを準備する。
commit.txt: コミットされたもの
staging.txt: ステージングされたもの
modified.txt: ワークツリーで変更されたもの
untracked.txt: ワークツリーで新規に追加されたもの

コミットされたもの ステージングされたもの ワークツリー
コマンドを打つ前 commit.txt staging.txt modified.txt, untracked.txt

ここで、modified.txtは、新規に追加されたものではなく、変更を加えられたものにしたいため、予め準備のためにcommitしてから、変更を加える。

# modified.txt
touch modified.txt
git add modified.txt
git commit -m 'modified.txtをコミット'
echo 'modified.txtを変更する' > modified.txt

# commit.txt
touch commit.txt 
git add commit.txt
git commit -m 'commit.txtをコミット'

# staging.txt
touch staging.txt
git add staging.txt

# untracked.txt
touch untracked.txt

git statusして、状況を確認。

Changes to be committed:
  (use "git reset HEAD <file>..." to unstage)

        new file:   staging.txt

Changes not staged for commit:
  (use "git add <file>..." to update what will be committed)
  (use "git checkout -- <file>..." to discard changes in working directory)

        modified:   modified.txt

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

        untracked.txt

また、git logして、コミット状況を確認。

commit 875f4d280c450dcddfd3e799448c33cb07215854 (HEAD -> master)
Author: host <host@gmail.com>
Date:   Sun Aug 9 23:03:39 2020 +0900

    commit.txtをコミット

commit bb977083c0aa34911e9dd517f274b15378c64cfe
Author: host <host@gmail.com>
Date:   Sun Aug 9 23:03:15 2020 +0900

    modified.txtをコミット

この状況から、以下の6条件でのgit resetを行う。それぞれのコマンドを打つ前の状態は、上の状態に統一している。

git reset オプション HEAD

1. git reset --soft HEAD

これは何も変わらない。

コミットされたもの ステージングされたもの ワークツリー
コマンドを打つ前 commit.txt staging.txt modified.txt, untracked.txt
コマンドを打った後 commit.txt staging.txt modified.txt, untracked.txt
Changes to be committed:
  (use "git reset HEAD <file>..." to unstage)

        new file:   staging.txt

Changes not staged for commit:
  (use "git add <file>..." to update what will be committed)
  (use "git checkout -- <file>..." to discard changes in working directory)

        modified:   modified.txt

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

        untracked.txt

2. git reset HEAD

ステージングされていた、staging.txtがインデックスからワークツリーへ移動。

コミットされたもの ステージングされたもの ワークツリー
コマンドを打つ前 commit.txt staging.txt modified.txt, untracked.txt
コマンドを打った後 commit.txt modified.txt, untracked.txt, staging.txt
Changes not staged for commit:
  (use "git add <file>..." to update what will be committed)
  (use "git checkout -- <file>..." to discard changes in working directory)

        modified:   modified.txt

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

        staging.txt
        untracked.txt

3. git reset --hard HEAD

ステージングされていたstaging.txtの変更が削除される!!
ワークツリーのmodified.txtの変更が削除される!!
ただし、ワークツリーに新規追加されたuntracked.txtはそのまま残る。

コミットされたもの ステージングされたもの ワークツリー
コマンドを打つ前 commit.txt staging.txt modified.txt, untracked.txt
コマンドを打った後 commit.txt untracked.txt
Untracked files:
  (use "git add <file>..." to include in what will be committed)

        untracked.txt

git reset オプション HEAD^

1. git reset --soft HEAD^

コミットしたはずのcommit.txtが、ステージングされた状態に戻る。

コミットされたもの ステージングされたもの ワークツリー
コマンドを打つ前 commit.txt staging.txt modified.txt, untracked.txt
コマンドを打った後 staging.txt, commit.txt modified.txt, untracked.txt
Changes to be committed:
  (use "git reset HEAD <file>..." to unstage)

        new file:   commit.txt
        new file:   staging.txt

Changes not staged for commit:
  (use "git add <file>..." to update what will be committed)
  (use "git checkout -- <file>..." to discard changes in working directory)

        modified:   modified.txt

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

        untracked.txt

2. git reset HEAD^

コミットしたはずのcommit.txtが、ワークツリーへ移動。
ステージングされていた、staging.txtがインデックスからワークツリーへ移動。

コミットされたもの ステージングされたもの ワークツリー
コマンドを打つ前 commit.txt staging.txt modified.txt, untracked.txt
コマンドを打った後 modified.txt, untracked.txt, staging.txt, commit.txt
Changes not staged for commit:
  (use "git add <file>..." to update what will be committed)
  (use "git checkout -- <file>..." to discard changes in working directory)

        modified:   modified.txt

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

        commit.txt
        staging.txt
        untracked.txt

3. git reset --hard HEAD^

コミットしたはずのcommit.txtの変更が、削除される。
ステージングされていたstaging.txtの変更が削除される!!
ワークツリーのmodified.txtの変更が削除される!!
ただし、ワークツリーに新規追加されたuntrached.txtはそのまま残る。

コミットされたもの ステージングされたもの ワークツリー
コマンドを打つ前 commit.txt staging.txt modified.txt, untracked.txt
コマンドを打った後 untracked.txt
Untracked files:
  (use "git add <file>..." to include in what will be committed)

        untracked.txt
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

コマンドラインでGitを使いたいときに見直したい基礎コマンド一覧

序論

本稿は 元市役所職員がWEBプログラマに転職するまでのロードマップ の連載記事の一部です。

Environment

  • OS: Ubuntu 20.04
  • Shell: bash
  • Editor: VSCode

Setup

# Linuxbrew で git インストール
$ brew install git

# Git 設定
$ git config --global user.name '<username>' # 好きなユーザ名を設定
$ git config --global user.email '<mail@example.dev>' # 自分のメールアドレスを設定
$ git config --global core.editor 'code -w' # VSCodeをデフォルトエディターに(-w オプションをつけないとエディタの終了を待ってくれない)
$ git config --global core.autoCRLF false # 改行コードを勝手に修正するのを無効化
$ git config --global core.quotepath false # 日本語ファイル名等をquoteするのを無効化

Gitとは何か

  • 分散型バージョン管理システムの一つで、もともとLinuxのソースコードを効果的に管理するために開発された
  • ファイルの状態を好きなときに更新履歴として保存しておくことができる
    • 一度編集したファイルを過去の状態に戻したり、編集箇所の差分を表示したりすることができる
  • GitHub や GitLab などの Gitサーバを利用すると、複数人でファイルの共有・編集などを行うことができる
  • 複数人で同じファイルを別々に編集した場合、「コンフリクト」という形で警告メッセージが表示されるため、知らない間に他人の編集内容を上書きしてしまう失敗が起こらない

基本コマンド

リポジトリの作成

  • リポジトリ
    • ファイル、プログラム、設定情報等の「保管場所」のこと
    • Gitでは、バージョン管理する上で必要な変更履歴等を保存しておく場所のことを言う
    • リポジトリを作ることで Git によるバージョン管理が可能となる
  • ローカルリポジトリとリモートリポジトリ
    • ローカルリポジトリとは、自身のPC上で作成した Git リポジトリのこと
    • リモートリポジトリとは、GitHub や GitLab など、サーバ上に保管されている Git リポジトリのこと
    • 基本的にリモートリポジトリは複数人で作業する場合に利用することが多い
      • 複数人開発の基本的な流れ
        1. 各個人がローカルリポジトリで作業履歴を記録
        2. リモートリポジトリにローカルリポジトリの記録を push(アップロード)
        3. 各個人がリモートリポジトリから最新のコードをローカルリポジトリに pull(ダウンロード)
        4. 1 に戻って、それぞれ作業する
$ git init
  • カレントディレクトリをGitのリポジトリ(データ倉庫)にする
  • .git ディレクトリが作成される
  • カレントディレクトリがそのまま作業ディレクトリになる
    • git init <ディレクトリ名> で特定のディレクトリをリポジトリにすることも可能

リポジトリのクローン

$ git clone <クローン元リポジトリ> [クローン先ディレクトリ]
  • クローン元リポジトリをクローン先ディレクトリ(指定しない場合はカレントディレクトリに同名ディレクトリを作成)にコピーする
  • リモートリポジトリをローカルにダウンロードする場合に使われることが多い
# 例: GitHub から hogehoge/example.git というリポジトリをダウンロード
$ git clone https://github.com/hogehoge/example.git
# => カレントディレクトリに example ディレクトリが作成され、example.git の中身がクローンされる

# 例: 上記リポジトリを /usr/local/src/example/ にダウンロードしたい場合
$ git clone https://github.com/hogehoge/example.git /usr/local/src/example

Gitの設定

$ git config --global <設定名> <設定値>
  • --global を省略した場合(もしくは --local を指定した場合)は、現在のリポジトリでのみ有効な設定となる
  • gitのglobal設定は ~\.gitconfig ファイルに保存されている
  • 基本的な設定値は「Setup」の項に記載した通り

設定値の確認・削除

# 設定値の確認
$ git config [--global] <確認したい設定の名前>

# 全設定の一覧表示
$ git config [--global] --list

# 設定値の削除
$ git config [--global] --unset <削除したい設定の名前>

ステージングへの追加

  • ステージング
    • 一般的には動作の最終チェック等を行うための場のこと
    • Git においては、作業記録を保存(コミット)する対象のファイルを置いておく場所のこと
    • ステージングがあることにより、1つのコミットに含める変更内容をファイル単位で細かく制御できる
# 対象のファイル or ディレクトリを作業記録保存(コミット)の対象に追加する
$ git add <ファイル or ディレクトリ>

# 変更のあったすべてのファイル・ディレクトリをステージングに追加
$ git add --all

ステージングに登録した内容を取り消す

# 対象のファイル・ディレクトリ(省略した場合はすべて)をステージングから下ろす
## コミット対象から外すだけで、変更内容まで消されることはない
$ git reset [ファイル・ディレクトリ]

# 最後の作業記録(コミット)の状態までファイル・ディレクトリを戻したい場合は --hard を指定する
$ git reset --hard [ファイル・ディレクトリ]

コミットする

  • コミット
    • ステージングに上げられている変更内容を記録すること
    • コミットすることで初めて作業履歴を辿れるようになる
$ git commit
# => git config core.editor で設定したエディタが立ち上がらる
# => コミットメッセージ(作業記録の内容に関するコメント)を記述するとコミットされる

# エディタを立ち上げずに一行のコミットメッセージを指定して即時コミットする場合
$ git commit -m '<コミットメッセージ>'

現在の状態を確認

# 変更状態を確認
## ファイル・ディレクトリを省略した場合は全ての変更状態を取得
## - 赤文字: ステージングに上げられていないが、変更されているファイル・ディレクトリ
## - 緑文字: ステージングに上げられているファイル・ディレクトリ(次のコミットで変更内容が保存されるもの)
$ git status [ファイル・ディレクトリ]

# 変更内容の差分を確認
## ファイル・ディレクトリを省略した場合は全ての変更差分を取得
$ git diff [ファイル・ディレクトリ]
  • コミットする前に必ず状態を確認しておく癖をつけると良い
  • 状態を確認することで、作業記録に一緒につけておきたかった変更がステージングに上げられていないことが分かったり、まだ記録するつもりのなかった変更がコミットされることを防ぐことができる

コミットログの確認

$ git log
$ git log -n <表示件数>  # 表示件数を指定
$ git log --oneline  # 1コミット1行で表示
$ git log --grep="<検索パターン>"  # コミットコメントで検索
$ git log <ファイル>  # 特定のファイルのコミットログだけ確認
$ git log --graph  # グラフ形式で表示
  • コミットログは、コマンドで確認するよりも GUI の Git クライアントを使った方が見やすい
  • エディタに VSCode を使っている場合は、Git Graph プラグインがオススメ
    • VSCode > F1 キー > Git Graph: View Git Graph から以下のようなコミットログを確認することができる

git-graph.png

ファイル削除

$ git rm <削除するファイル・ディレクトリ>
  • リポジトリの管理からファイルを削除する
  • 作業ディレクトリからも物理的にファイルが削除される

特定のリビジョン(作業履歴)に戻る

$ git checkout <コミットハッシュ> [ファイル・ディレクトリ]
  • ファイルの状態を、指定したコミットハッシュの時点まで戻す
  • ファイル・ディレクトリを指定した場合は、指定したファイル・ディレクトリのみ特定のリビジョンに戻せる
  • コミットハッシュは git log で確認

過去のコミットを打ち消す

$ git revert <コミットハッシュ>

# mergeコミットを打ち消したい場合
$ git revert -m 1 <mergeコミットハッシュ>
  • 過去のコミットを削除するのではなく、打ち消す形で新規にコミットを行う
    • そのため、打ち消した内容を修正してもう一度コミットした場合は revertコミットに対して revertコミットする必要がある
    • 作業が非常に複雑化するため極力使わない
      • 例えば、何らかの feature ブランチで revert を行い、revert の revert を行った状態で develop, master にした場合、develop, master それぞれのブランチでも revert の revert が必要になる
      • これは複数人で開発を行っていると事故の元になるため、避けるべき事案である

現在の変更内容を取り消す

# ファイル・ディレクトリを指定
$ git checkout HEAD <ファイル・ディレクトリ>

# 全ファイル一括で取り消す
$ git reset --hard
  • 上記コマンドは、リモートリポジトリに push する前の段階で使うべきコマンド
  • リモートリポジトリに push してしまった後は、revert で過去のコミットを打ち消すしかない
    • reset を行うと変更履歴が通常と異なる状態になり、リモートリポジトリに保管されている履歴と異なる履歴とみなされてしまうため
    • リモートリポジトリに対する強い編集権限がある場合は、--force オプションで強制 push 可能なため、revert するよりは reset => 強制 push した方が良い場合も多い

リポジトリに登録されていないファイルを削除

# 削除されるファイルを確認
$ git clean -n

# 登録されていないファイルを全削除
$ git clean -f

ブランチの作成

  • ブランチ
    • 複数人で並行して作業する際に、履歴の流れを分岐して記録するための仕組み
    • 履歴の本流は master ブランチ
      • 最初に git init でリポジトリを作った段階で、自動的に master ブランチに作業履歴が記録される状態になっている
    • 分岐したブランチは他のブランチとマージすることで一つのブランチにまとめ直すことが可能
    • ブランチの運用方法については git-flow.md を参照
$ git branch <ブランチ名>

# ブランチを作る場合、大抵そのブランチで作業を行いたいはずなので
# 以下のコマンドで、ブランチの作成と切り替えを同時に行うことが多い
$ git checkout -b <ブランチ名>

存在するブランチの確認

$ git branch
* master
  develop
  • -v オプションを付けると、ブランチのハッシュやコミットコメントも確認可能
  • -a オプションをつけると、リモートブランチも確認可能

ブランチの切り替え

# 対象のブランチのHEAD(最新状態)に切り替え
$ git checkout <ブランチ名>

# 新規ブランチを作成して切り替え
$ git checkout -b <ブランチ名>

# 新規ブランチをリモートブランチと同期して切り替え
$ git checkout -b <ブランチ名> <リモートリポジトリ名>/<ブランチ名>

ブランチのマージ

$ git merge <マージするブランチ名>
  • 現在作業しているブランチに対象のブランチをマージする
    • そのため、マージしたいブランチに一度 checkout してから merge を行う必要がある
  • 競合(コンフリクト)が発生した場合は、競合を解決してから git add => git commit する

ブランチの削除

$ git branch -d <ブランチ名>
  • マージしていないコミットがある場合はエラーになるため、マージしてから削除すること
    • もしくは --force オプションをつければ強制削除も可能
    • 強制削除した場合、そのブランチで行われた全ての作業履歴が失われるため要注意

タグの作成

# 名前だけのタグ(軽量タグ)を作成
$ git tag <タグ名>

# コメント付きのタグ(注釈付きタグ)を作成
$ git tag -a <タグ名> -m "<コメント>"
  • タグをつけることで重要なコミット(作業記録)を検索しやすくなる
  • 一般的には、プログラムをリリースする際に、バージョンをタグにして記録することが多い

タグの確認

# 登録タグ一覧確認
$ git tag

# 指定タグの詳細表示
$ git show <タグ名>

タグの削除

$ git tag -d <タグ名>

リモートリポジトリの登録

$ git remote add <認識名> <リモートリポジトリURL>
  • GitHub や GitLab 等のWeb上のリポジトリを登録する
  • リモートリポジトリを登録することで、そのリポジトリにローカルの作業履歴を push(アップロード)することができるようになる
  • 通常リモートリポジトリは1つしか使わないため、認識名は慣例的に origin を使うことが多い
    • git clone でリポジトリをクローンした場合、クローン元のリポジトリパス(URL)が origin という認識名で登録されている

登録されているリモートリポジトリを確認

$ git remote  # -v オプションを付けると詳細を確認できる

登録されているリモートリポジトリから最新のコードを取得

# 認識名を指定するとリモートリポジトリとして登録されているものの中から該当の認識名のリモートリポジトリのコードのみ取得可能
# ブランチ名を指定すると、指定ブランチの最新コードのみ取得可能
$ git pull [認識名] [ブランチ名]

登録されているリモートリポジトリにローカルリポジトリの作業記録を反映

$ git push <認識名> <ブランチ名>

# -u で指定認識名をデフォルトの push 先に登録しつつ push 可能
$ git push -u <認識名> <ブランチ名>
# => 以降は git push のみでリモートリポジトリに push できるようになる

# リモートリポジトリに全てのブランチの作業記録を push する場合
$ git push --all <認識名>

# リモートリポジトリのブランチを削除する場合
$ git push --delete <認識名> <削除するブランチ名>

リモートリポジトリの登録削除

$ git remote remove <認識名>

.gitignore

  • .gitignore
    • Git リポジトリで管理したくないファイルを指定する設定ファイル
    • 個人情報や機密情報を含むファイルなどは記録を残すとセキュリティ上良くないため、gitignore する必要がある
    • ライブラリなど、外部からダウンロードして使うようなファイルも Git 管理しない方が良い
    • その他、Git 管理するには巨大すぎるデータファイルなども gitignore の対象である
  • Web開発上の注意点:
    • 基本的にエンジニア以外の人間が追加・編集する可能性のあるファイルは全て gitignore しておく必要がある
      • Git による巻き戻りが発生する可能性があり、余計なトラブルの原因になる
      • Web開発を行う場合は、ファイルの責任所在を明確にしたうえで契約を結ぶべきである

基本

  • .gitignore ファイルを使うと無視する(Git の管理対象外とする)ファイル・ディレクトリを指定できる
  • .gitignore は複数のディレクトリに置くことができる
    • .gitignore は、自身の階層以下のパスに置かれたファイル・ディレクトリに対してのみ効果を発揮する
    • 深い階層の .gitignore に書かれた指定の方が優先順位が高い(後に解釈される)
  • .gitignore 内の記述は上の行から順に以下のように解釈される
    • 先頭に / を含まない行(file など)
      • .gitignore 以下の階層における全サブディレクトリ下にある指定名のファイル・ディレクトリを無視する
    • 末尾以外に / を含む行(/file, /path/to/file, path/to/file など)
      • .gitignore が置いてあるディレクトリをカレントディレクトリとする相対パスで指定されるファイル・ディレクトリを無視する
    • 末尾のみ / を含む行(directory/ など)
      • .gitignore 以下の階層における全サブディレクトリ下にあるこの名前のディレクトリを無視する
    • 末尾以外にも末尾にも / を含む行(/directory/, /path/to/directory/, path/to/directory/ など)
      • .gitignore が置いてあるディレクトリをカレントディレクトリとする相対パスで指定されるディレクトリを無視する
    • ! で始まる行(!/path/to/file など)
      • ! 以降のパターン文字列が示すファイル・ディレクトリを無視しない
      • 前の無視指定を上書きする
      • 以降の無視指定に上書きされうる
    • 空行 or # で始まる行
      • 解釈されない

以下のようなディレクトリ構成の場合、.gitignorefileとだけ書くと、filedirectory/file も共に無視されることに注意!

./
|_ .git/
|_ .gitignore
|_ file
|_ directory/
    |_ file

.gitignore と同ディレクトリにある file のみを無視したい場合は、/fileと書く必要がある

なお、Gitリポジトリのルート、あるいはOSのルートからの絶対パス指定をする方法はない

.gitignore は自身と同じか下の階層のファイル・ディレクトリにしか影響を及ぼさない

ワイルドカード

.out という拡張子のファイルをまとめて無視したい場合 *.out のように記述できる

このようなワイルドカードの類には以下のようなものがある

  • *
    • / 以外の0文字以上の文字列にマッチ
    • シェルのパス名展開で使われる * と同じ意味
  • ?
    • / 以外の1文字にマッチ
    • シェルのパス名展開で使われる ? と同じ意味
  • [0-9] など
    • / 以外の指定した1文字にマッチ
    • シェルのパス名展開で使われる [0-9] などと同じ意味
  • **
    • 0個以上のファイル・ディレクトリにマッチ
    • 例:
      • /a/**: /a, /a/x, /a/x/y などにマッチ
      • /**/b: /b, /x/b, /x/y/b などにマッチ
      • /a/**/b: /a/b, /a/x/b, /a/x/y/b などにマッチ
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

Android StudioのTool BarにGit Pushボタンを追加

Android Studio(4.0.1)のToolBarで、
Gitボタン欄にPushボタンが表示されていなかったので追加した方法をメモ。
スクリーンショット 2020-08-09 20.50.44.png

Preferencesを開く

Android Studio>Preferences
スクリーンショット 2020-08-09 21.02.09.png

VcsNavBarToolbarActionsで、Pushボタンを追加したい箇所を選択する

Appearance & Behavior>Menus and Toolbars>
Navigation Bar Toolbar>NavBarVcsGroup>
VcsNavBarToolbarActions
スクリーンショット 2020-08-09 20.49.05.png

Add ActionでPushを追加

Main menu>VCS>Git
スクリーンショット 2020-08-09 20.50.02.png

VcsNavBarToolbarActionsに、Pushが追加されました

スクリーンショット 2020-08-09 20.50.21.png

無事、Pushボタンが追加されました。

スクリーンショット 2020-08-09 20.51.09.png

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

Git+Github使い方

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む