マージ済みのローカルブランチを一括削除する

プログラミングをしていて、作業ごとにブランチを作成しているので、ローカルブランチが溜まりがちです。

ChatGPTに毎回コマンドを聞くのも申し訳ないので、操作をまとめておきます。

マージ済みのブランチを確認する

この操作の肝になるのが、マージ済みのブランチを一覧表示することです。

$ git branch --merged

このコマンドではマージ済みのブランチを一覧表示できます。このコマンドでは現在のブランチも含まれており、現在のブランチを示す*がついています。

また、mainブランチも含まれている点に注意が必要です。

現在のブランチ、mainブランチを除く

現在のブランチを削除できないのでこれを除外します。また、mainブランチは削除されると困るのでこれも除外します。grep -vで除外できるのでこれを使って除外します。  

$ git branch --merged | grep -v "\*" | grep -v "main"

もし、mainブランチではなくmasterブランチであれば、

$ git branch --merged | grep -v "\*" | grep -v "master"

としてください。

マージ済みのブランチを削除する

マージ済みのブランチを削除するには、git branch -dを使用します。-Dを使用すると未マージのブランチを削除できてしまうので、-dを使う点に十分注意してください。

$ git branch -d <削除するブランチ名>

前述のマージ済みブランチのリストをgit branch -dに渡すにはxargsコマンドを使用します。

$ git branch --merged | grep -v "\*" | grep -v "main" | xargs -n 1 git branch -d

マージ済みのブランチは

$ git branch --merged
  bug/bad-request-when-exception-occurs
  bug/remove-pysqlite3-from-pyproject
  bug/update-readme-md
  doc/add-codacy-badge
  doc/update-doc-and-readme
  doc/update-document
  enhance/enhancing-the-way-router-is-set-up

のようにブランチ名だけがリストされ、このブランチ名をgit branch -dコマンドに渡せばいいので、-n 1(渡す標準入力は1つ)を指定しています。

まとめ

頻繁に使用するコマンドは忘れませんが、時々しか使わないコマンドは忘れがちです。ChatGPTなどに訪ねればすぐに答えを教えてくれるので、それほど困ることはありませんが、以下のようにコマンド化しておけばすぐに使えます。(コマンドを忘れるという可能性はありますが)

# Git Branch Clear
gbc() {
  git branch --merged | grep -v "\*" | grep -v "main" | xargs -n 1 git branch -d
}

ローカルブランチは容量を圧迫するような類いのものではありませんが、あまり溜まりすぎると探しにくくなったりするの、個人的には綺麗にしておきたいと思っています。

プルリクのマージ後に削除すればいいのですが、どうしても忘れてしまうので、思い立ったときに一括削除できるようにしておくくらいがちょうどいいと思います。

Gitで初回コミットを取り消す(git resetでエラーになる場合)

リポジトリを新規作成し、コミットしたところで.gitignoreファイルを作り忘れていることに気づくことはないでしょうか?

このような場合、直前のコミットを取り消そうとすると次のようなエラーが表示されます。

$ git reset --soft HEAD~1
fatal: ambiguous argument 'HEAD~1': unknown revision or path not in the working tree.
Use '--' to separate paths from revisions, like this:
'git <command> [<revision>...] -- [<file>...]'

このエラーは、取り消したいコミットの一つ前のコミットHEAD~1が存在しないことが原因で起きています。

初回コミットを取り消したい場合の方法について解説します。

ここで解説する方法の中には非常に強力な操作が含まれています。使い方を誤ると復旧困難な状態に陥る可能性がありますので、十分に注意してください。

もっとも簡単な方法

もっとも簡単に初回コミットを取り消す方法は、.gitディレクトリを削除することです。当然ながらgit initからやり直しになりますが、初回コミット時という状況に限定するのであれば、この方法がもっとも簡単かつおすすめです

$ rm -rf .git

初回コミットを取り消すコマンド

では、.gitディレクトリを削除せずに初回コミットを取り消す方法はないのでしょうか?

もちろん初回コミットを取り消すコマンドはあります。次のコマンドを実行することで、初回コミットを取り消すことができます。

$ git update-ref -d HEAD

取り消し後、変更はステージングエリアに残ります。ステージングエリアにある変更をワーキングディレクトリに戻す場合は、

$ git reset

で、ステージングエリアにあるすべての変更をワーキングディレクトリに戻すか、

$ git reset node_modules

で、特定のファイルまたはディレクトリのみをワーキングディレクトリに戻してください。

git update-ref -d HEADとはどんなコマンドなのか?

git update-ref -dは指定した参照(ref)を削除するコマンドです。ここではHEADという参照を指定していますので、HEAD参照が削除され、何もコミットしていない状態まで戻されますので、初回コミットが取り消されることになります。

git update-ref -dリポジトリの履歴を変更する非常に強力な操作です。使い方を誤ると復旧が困難な状態に陥る場合がありますので、十分に注意して使用してください。不安な場合は前述のもっとも簡単な方法を実施してください。

(おまけ)初回コミット以外のコミットの取り消す

おまけになりますが、git resetコマンドを使用した初回コミット以外のコミットを取り消す方法について確認しておきます。

取り消した変更をステージングエリアに保持

次のコマンドは、直前のコミットを取り消し、そのコミットの変更をステージングエリアに残します。

$ git reset --soft HEAD~1

取り消した変更をワーキングディレクトリに保持

次のコマンドは、直前のコミットを取り消し、その変更をワーキングディレクトリに残しますが、ステージングエリアには残しません。--mixed オプションはデフォルトなので、--mixed は省略可能です。

$ git reset --mixed HEAD~1

変更を完全に取り消し

次のコマンドは、直前のコミットを取り消し、そのコミットの変更を完全に取り消します。

$ git reset --hard HEAD~1

(おまけ)ステージングエリアの変更を取り消す

すでに説明済みですが、ステージングエリアの変更を取り消す方法についても確認します。

ステージングエリアにあるすべてのファイルやディレクトリを戻す

ステージングエリアにあるすべてのファイルやディレクトリをワーキングディレクトリに戻す場合は、次のコマンドを実行します。

$ git reset

ステージングエリアにある特定のファイルまたはディレクトリを戻す

ステージングエリアにある特定のファイルまたはディレクトリをワーキングディレクトリに戻す場合は、次のコマンドを実行します。

$ git reset node_modules

まとめ

初回コミットを取り消す方法について解説しましたが、使用タイミングを誤ると復旧不可能な事態に陥るリスクがあので注意が必要です。

ステージングエリアに上げたあとに過不足がないことをレビューすることが大切です。ステージングエリアに上げる、ステージングエリアからワーキングディレクトリに戻すという操作は安全に実施できる操作ですし、ステージングエリアと直前のコミットとの差分は、git diff --cachedまたはgit diff --stagedで比較できますので、積極的に活用してレビューを行ってください。

giコマンドで.gitignoreを作成しよう

リポジトリ管理のツールとして、Gitはデファクトスタンダードととも言えるツールですが、その利用に際して特に重要なのが.gitignoreファイルの適切な設定です。このファイルはGitリポジトリで無視するべきファイルやディレクトリを指定し、不要なファイルがリポジトリに追加されるのを防ぎます。しかし、多様な開発環境や言語に対応するための.gitignoreファイルを一から作成するのは意外と手間がかかるものです。そこで役立つのが、Toptalによって提供されるgitignore.ioサービスと、それを利用したgiコマンドです。gitignore.ioは、さまざまな開発環境や言語に合わせた.gitignoreテンプレートを提供し、giコマンドを通じてこれらのテンプレートを簡単に取得し、利用することができます。

この記事では、giコマンドを使用して、効率的かつ正確に.gitignoreファイルを作成する方法を紹介します。

giコマンドのインストール

gitignore.ioのコマンドラインツールのページにアクセスして、インストール用のコマンドをコピーします。

本記事ではzshを使用している場合のコマンドを使用します。

$ echo "function gi() { curl -sLw \"\\\n\" https://www.toptal.com/developers/gitignore/api/\$@ ;}" >> \
~/.zshrc && source ~/.zshrc

実行しても特に何もメッセージは出ませんがコマンドのインストールは完了しています。実行するためにはcurlコマンドが必要ですのでインストールしていない場合は別途インストールしてください。

giコマンドの確認

まずはgiコマンドの使い方を確認していきましょう。オプションなしでgiコマンドを表示するとヘルプを確認できます。

$ gi
  list    - lists the operating systems, programming languages and IDE input types
  :types: - creates .gitignore files for types of operating systems, programming languages or IDEs

少しわかりづらいですが、listサブコマンドを使用すると使用可能なタイプな一覧が表示されます。ただし、かなり量があるのご注意ください。

$ gi list
1c,1c-bitrix,a-frame,actionscript,ada
adobe,advancedinstaller,adventuregamestudio,agda,al
・・・
yarn,yeoman,yii,yii2,zendframework
zephir,zig,zsh,zukencr8000

数が多いので、grepコマンドを併用するとよいでしょう。

$ gi list | grep node
modelsim,modx,momentics,monodevelop,mplabx
ninja,node,nodechakratimetraveldebug,nohup,notepadpp

Node.jsの.gitignoreはnodeというタイプで指定することがわかります。

$ gi list | grep visualstudiocode
virtualenv,virtuoso,visualbasic,visualstudio,visualstudiocode

VSCodeの.gitignorevscodeではなくvisualstudiocodeだということもわかりました。

giコマンドで.gitignoreを作成する

では、実際に.gitignoreを作成してみます。ここでは、Node.jsのプロジェクトを作成し、VSCodeでコーディングするとします。

使用するタイプはnodevisualstudiocodeの2つになり、複数選択する場合はカンマ区切り(間にはスペースを入れない)でタイプを並べます。また、コマンド自体は標準出力に表示するだけですので、ファイルにリダイレクトしてファイル化します。

$ gi node,visualstudiocode > .gitignore

生成された.gitignoreファイルの中身は以下のようになります。

# Created by https://www.toptal.com/developers/gitignore/api/node,visualstudiocode
# Edit at https://www.toptal.com/developers/gitignore?templates=node,visualstudiocode

### Node ###
# Logs
logs
*.log
npm-debug.log*
yarn-debug.log*
yarn-error.log*
lerna-debug.log*
.pnpm-debug.log*

# Diagnostic reports (https://nodejs.org/api/report.html)
report.[0-9]*.[0-9]*.[0-9]*.[0-9]*.json

# Runtime data
pids
*.pid
*.seed
*.pid.lock

# Directory for instrumented libs generated by jscoverage/JSCover
lib-cov

# Coverage directory used by tools like istanbul
coverage
*.lcov

# nyc test coverage
.nyc_output

# Grunt intermediate storage (https://gruntjs.com/creating-plugins#storing-task-files)
.grunt

# Bower dependency directory (https://bower.io/)
bower_components

# node-waf configuration
.lock-wscript

# Compiled binary addons (https://nodejs.org/api/addons.html)
build/Release

# Dependency directories
node_modules/
jspm_packages/

# Snowpack dependency directory (https://snowpack.dev/)
web_modules/

# TypeScript cache
*.tsbuildinfo

# Optional npm cache directory
.npm

# Optional eslint cache
.eslintcache

# Optional stylelint cache
.stylelintcache

# Microbundle cache
.rpt2_cache/
.rts2_cache_cjs/
.rts2_cache_es/
.rts2_cache_umd/

# Optional REPL history
.node_repl_history

# Output of 'npm pack'
*.tgz

# Yarn Integrity file
.yarn-integrity

# dotenv environment variable files
.env
.env.development.local
.env.test.local
.env.production.local
.env.local

# parcel-bundler cache (https://parceljs.org/)
.cache
.parcel-cache

# Next.js build output
.next
out

# Nuxt.js build / generate output
.nuxt
dist

# Gatsby files
.cache/
# Comment in the public line in if your project uses Gatsby and not Next.js
# https://nextjs.org/blog/next-9-1#public-directory-support
# public

# vuepress build output
.vuepress/dist

# vuepress v2.x temp and cache directory
.temp

# Docusaurus cache and generated files
.docusaurus

# Serverless directories
.serverless/

# FuseBox cache
.fusebox/

# DynamoDB Local files
.dynamodb/

# TernJS port file
.tern-port

# Stores VSCode versions used for testing VSCode extensions
.vscode-test

# yarn v2
.yarn/cache
.yarn/unplugged
.yarn/build-state.yml
.yarn/install-state.gz
.pnp.*

### Node Patch ###
# Serverless Webpack directories
.webpack/

# Optional stylelint cache

# SvelteKit build / generate output
.svelte-kit

### VisualStudioCode ###
.vscode/*
!.vscode/settings.json
!.vscode/tasks.json
!.vscode/launch.json
!.vscode/extensions.json
!.vscode/*.code-snippets

# Local History for Visual Studio Code
.history/

# Built Visual Studio Code Extensions
*.vsix

### VisualStudioCode Patch ###
# Ignore all local history of files
.history
.ionide

# End of https://www.toptal.com/developers/gitignore/api/node,visualstudiocode

まとめ

Githubのgithub/gitignoreリポジトリから対象の.gitignoreを探したり、gitignore.ioを使うのもよいですが、giコマンドを使って.gitignoreを生成する方が簡単に利用できて便利です。また、コマンドということはシェルスクリプトへの組み込みなど様々な使い道があるのもよい点です。

giコマンドを用いることで、テンプレートからプロジェクトに必要な情報をすばやく設定でき、開発の手間を大幅に削減することができます。ぜひ、giコマンドを活用してよりスムーズな開発を実現してみてください。

[Git]ファイルをステージングエリアに追加する(git add)

Gitでファイルをステージングエリア(インデックス)に追加する方法を解説します。

ファイル名を指定して追加する

一番オーソドックスな方法は、追加したいファイルをgit addコマンドで指定する方法です。

$ git add test.txt

ファイルをまとめて追加する

変更をまとめて追加したい場合は、ファイル名の代わりに.を指定するとまとめて追加できます。

$ git add .

-Aオプションを使っても同様のことができます。

$ git add -A

ワイルドカードを指定して追加する

特定の拡張子のファイルや特定のフォルダ(ディレクトリ)にあるファイルをまとめて追加したい場合は、ワイルドカードを使うと便利です。

$ git add *.java
$ git add src/*

Gitで管理しているファイルだけをまとめて追加する

git add .の場合、Gitで管理しているファイルも管理していないファイルもまとめて追加されます。Gitで管理しているファイルだけを追加したい場合は-uオプションを使います。

$ git add -u

Gitを使い始めるときに行う設定(git config)

Gitをインストールした後など、使い始めるときに行う2つの設定について解説します。

ユーザー名を設定する

使い始める前に行う設定の1つ目はユーザー名の設定です。

git config --global user.name "Taro Yamada"

user.nameユーザー名を表します。一般的には本名をローマ字で書くのが一般的ですが、ハンドル名やニックネーム等を使用しても構いません。

仕事で使う場合は、組織やプロジェクトでのルールに従ってください。

氏名をユーザー名に設定する場合、姓と名の間に半角スペースを含むため、ユーザー名全体を「”」(ダブルクォーテーション)で囲みます。スペースを含まない場合は「”」(ダブルクォーテーション)で囲む必要はありません。

メールアドレスを設定する

使い始める前に行う設定のもう一つは、メールアドレスの設定です。

git config --global user.email taro.yamada@example.com

user.emailメールアドレスを表します。

使用可能なメールを使用することが強く推奨されるため、個人開発の場合は個人のメールアドレス、仕事での開発の場合は組織で使用されているメールアドレスを使用してください。

メールアドレスにはスペースを含むことがないので「”」(ダブルクォーテーション)は必要ありません。

設定を確認する

現在の設定を確認するには、-lオプションを使います。

前述の設定を行ったあとに、設定を確認すると以下のような結果になります。

$ git config --global -l

user.name=Taro Yamada
user.email=taro.yamada@example.com

ユーザー名とメールアドレスは何に使うの?

設定したユーザー名とメールアドレスはどこに使われるのでしょうか?

設定したユーザー名とメールアドレスは、コミットログのAuthorに使用されます。
前述の設定を行ったうえでファイルをコミットして、ログでコミットログを確認すると以下のようになります。

$ git log       
commit daa1b044d5794411dd25e9f404a4f96a0b4d1006 (HEAD -> main)
Author: Taro Yamada 
Date:   Sat Mar 12 20:45:39 2022 +0900

    add test.txt

Author欄に先ほど設定したユーザー名とメールアドレスが設定されていることが分かります。

プロジェクト固有の設定を行いたい場合は?

すでに説明した設定はグローバル設定(--global)となっています。

例えば、

在宅勤務で自宅のPCをしており、普段は個人で開発していますが、仕事でも使うことになりました。
個人で開発する際のユーザー名とメールアドレスはグローバル設定として登録済みです。仕事では会社のメールアドレスを使う必要があります。

この場合、ローカル設定を使うことで解決できます。

まずは現在のグローバル設定を確認します。

$ git config --global -l

user.name=Taro Yamada
user.email=taro.yamada@example.com

次に仕事で使うプロジェクト(ここでは「user_service」)に移動して、再度設定を確認します。

$ cd user_service
$ git config --global -l

user.name=Taro Yamada
user.email=taro.yamada@example.com

当然ですが、設定は変わりません。
ここではローカル設定(--local)を行います。

まずは設定を行います。

$ git config --local user.name t-yamada
$ git config --local user.email t-yamada@kaisha.com

先ほどとの違いは、--global--localになっただけです。

では、設定を確認してみましょう。設定の確認も同様に--localオプションを使用します。

$ git config --local -l
core.repositoryformatversion=0
core.filemode=false
core.bare=false
core.logallrefupdates=true
core.symlinks=false
core.ignorecase=true
user.name=t-yamada
user.email=t-yamada@kaisha.com

少し余計な設定が出力されていますが、一番下にuser.nameuser.emailが出力されており、設定値は--localオプションを使用して設定したものになっています。

では適当なファイルをコミットして、コミットログを確認してみます。

$ touch test.txt
$ git add test.txt
$ git commit -m 'add test.txt'
[main (root-commit) 11eecab] add test.txt
 1 file changed, 0 insertions(+), 0 deletions(-)
 create mode 100644 test.txt
$ git log 
commit 11eecab9335ca6e43e4efc6c2a43f37fb7be41b3 (HEAD -> main)
Author: t-yamada 
Date:   Sat Mar 12 21:55:04 2022 +0900

    add test.txt

ファイルの追加やコミットのオプションは特に変えていませんが、確かに--localで設定したユーザー名、メールアドレスで記録されています。

このように複数の環境を使い分ける場合はローカル設定を活用してください。

Gitリポジトリの初期化を行う(git init)

Gitでファイル管理を始めるために初期化を行う方法を解説します。

Gitリポジトリの初期化を行う

では、フォルダ/ディレクトリ(以降はフォルダと表記)を作成し、そこに空のリポジトリを作成する手順を見てみましょう。

まずは、フォルダを作成し、その中に移動します。

$ mkdir test
$ cd test
$ ls -a
./  ../

隠しファイルも含めて表示し、空のフォルダであることがわかります。

次にgit initコマンドを実行します。

$ git init
Initialized empty Git repository in /home/taro/test/.git/

空のGitリポジトリを初期化した旨のメッセージが出力されています。では、再度フォルダの中がどうなっているか確認してみます。

$ ls -a
./  ../  .git/

先ほどまではなかった.gitという隠しフォルダが作成されていることがわかります。

これでGitリポジトリの初期化が完了し、gitコマンドが使えるようになります。

オプションはあるが使用することはほとんどない

実はgit initには、オプションがあります。

ですが、オプションを使用することはほとんどないと言っていいので、気にする必要はありません。実用上は、

Gitリポジトリの初期化を行いたいフォルダへ移動して、git initを実行する

とだけ理解しておけば充分です。

モバイルバージョンを終了