20200218のGitに関する記事は6件です。

一度gitにアップしてしまった物をgitignoreする。

最近の勉強で学んだ事を、ノート代わりにまとめていきます。
主に自分の学習の流れを振り返りで残す形なので色々、省いてます。
Webエンジニアの諸先輩方からアドバイスやご指摘を頂けたらありがたいです!

一度、git上にあげたものをignoreする

以前、robots.txtの内容・書き方を作成したんですが

robots.txtをStaging環境だけに反映し、本番環境には反映させないために一度、develop branchに上げた後、gitignore ファイルに追加する必要がありました!

master branchにも反映されてしまうのを防ぐために!
しかし、.gitignoreに記載したのに反映されず。

問題

一度gitにアップしたものを、.gitignoreに追加したことが原因

キャッシュにインデックスが残っている状況

解決方法

こちらの方の方法通りにしたら無事、gitignoreに正しく反映されました!
.gitignoreに記載したのに反映されない件

手順
1:.gitignore 編集
2:キャッシュを削除
3:commit & push

robots.txtのgitのキャッシュを削除

$ git rm -r --cached robots.txt  //ファイル指定してキャッシュ削除

これで、gitでは管理されなくなりmasterに影響を与えずに済みました!

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

Git rebase は使えなくてもいい。あとGit cherry-pick と Git merge --squash も

おことわり:あくまでも個人の意見です

Microsoft本社で6年、いくつかのプロダクトチームで開発してきて思ったことです。

Git のコマンドで要らないもの

Git rebase は要らない

いろいろと利点だと思える点もあるようですが、マージコミットが無くて済むとか、コミットグラフが読みやすくなるとか、そういうコミットグラフの質が「製品・サービスの価値」に深く関わるとは思えない、というのが理由です。プライベートなブランチ間でやるなら構わないけれど「チーム全体のルール」にしてしまうと逆に作業効率が落ちると思う。git rebase の作業をする時間があったら、次のタスクに移った方がいいと思う。実際使ってる人はほとんど見かけない(というか使ってても見えてないだけかもしれないけど)。少なくとも自分使わない。

Git cherry-pick は要らない

個人的には「百害あって一利なし」だと思います。一見便利そうだし実際便利かもしれませんが、開発のベストプラクティスというよりは「one-off(一度きり)のハック」だと感じます。例えば、緊急のバグを治す時に、開発ブランチから派生したホットフィックスブランチで治し、リリースブランチにチェリーピックする、という流れがありますが、ベストプラクティスは逆でリリースブランチから派生したホットフィックスブランチでそのバグだけを治し、リリースブランチにマージしてからさらに開発ブランチにもマージする、そうするとチェリーピックは要りません。

ある機能を限定的にリリースしたい場合、そもそも設計にフライティングの機能を入れて「露出していない」状態でリリースします。その後、フライティング設定で特定の機能を「露出」させると目的を達成できます。その機能のコミットが特定のブランチに含まれるかどうかが、ユーザがその機能にアクセスできるかどうかを制御してしまうのはブランチには荷が重すぎると思うのです。ベストプラクティスに近づけるためにもcherry-pickを使った裏技はチーム単位で非奨励とすべきだと個人的には思います。

Git merge --squash は要らない

コミット毎にメッセージを細かく残したくないというのが動機のひとつのようです。ですが仮にコミットグラフに無駄なコミットやコミットメッセージが多く残ったとして、それが数週間後、数か月後、数年後にどのぐらい問題になるかとういうと、大した問題にはなっていないと思うのです。昔はせっせとsquashしてたけど今は全くやらない、って人も多いのでは?どうせsquashするからと、雑なコミットをすることを助長するぐらいなら、見えるからこそ「キリのいいところでコミットする」という習慣を付ける方が大切だと思う。周りでもsquashをする・しないを気にする人はあんまりいないと思う。

これだけ分かってればいい Git のコマンド

Git clone

レポジトリのコピー(クローン)を作るのに絶対必要。僕の場合、同じリモートのレポジトリでも複数作ります。同時にいくつかのブランチで作業をするめることもあるので。その時は下のように、末尾に2、3、4、と数字を付けてクローンします。

git clone https://github.com/yoshiwatanabe/test.git test2

Git add

特に、. ワイルドカードを使って全てファイルをステージングエリア(インデックス)に移動するやり方

git add . 

を多用してます。

間違ってステージングに入れてしまったファイルは

git reset HEAD <ファイルのパス> 

でステージから引きずり下ろします。

Git commit

git commit -m "コミットの目的"

ほとんどこれで済ませます。

たまーに、--amend で忘れものを届けますが、それはまだコミットを例えばGitHubにまだpushしてない時に限ります。

git commit --amend

でもこれは絶対に必要というわけではありません。新しいコミットで忘れ物を届ければいいだけです。

「コミットはちゃんと完全なものにして、あとからコミットで忘れた箇所を変更するのはやめて。まだpushしてないなら commit --amendして」って同僚・上司に言われる、みたいなシチュエーションだとしたら、それはその人が「妙にこだわってるだけ」で、まぁお国柄とかチームの文化にもよるでしょうが、私がいたMicrosoftのチームでコミットの完全さにこだわる人は見たことがないです。そんなことよりさっさと次の仕事に移った方がいいですから。

Git fetch

もっとも安全でなおかつ出来るだけ頻繁に実行すべきGitコマンド。

git fetch

手元にあるGitHubなどの中央レポジトリの状態を最新のものにしてくれます。

実は、このコマンドは中央レポジトリの最新の状態をダウンロードしてくるだけなのでこれだけではあまり意味がありません。私の作業ワークフローでは、このコマンドの後に git pull git merge git remote prune origin などが続きます(後述)

  • ネット環境がないキャンプ場で仕事する予定がある場合、同僚のトピックブランチも含めて完全に最新の状態で出発したい
  • 同僚のトピックブランチも見える状態になるので、だれがどのあたりのコードをいじってるか分かる
  • git pull は実は git fetchgit merge のショートカットだという理解を深める

といった利点があります。

どちらにしろ、手元のレポジトリが中央レポジトリの最新版であることは悪いことではないです。

Git pull

じつはgit fetch も裏でやってくれます。僕は癖でgit fetch を個別にやってから、git pullしますが、本当はgit fetchは要らないですね(以前は 「git fetch からの git merge」コンボで git pull そのものを使ってませんでした)

git pull

現在checkout中のローカルブランチを最新(=中央レポジトリでの該当ブランチの最新状態)のものにしてくれるんですが、その理由としてを2つのシチュエーションがあります。

シチュエーション1

トピックブランチで作業を続けていて、まだしばらく作業時間がかかりそうな時、合流予定の合流先ブランチ(例:master)を最新にして、それをgit mergeでトピックブランチに引っ張って来る場合。

この作業は大切です。なぜなら、自分のトピックブランチ(が含む合流予定先ブランチの内容)が遅れて居ればいるほど、同僚がすでに直したバグを再度治すというヘマ、同僚がすでにリファクターした便利な仕組みを見逃すヘマ、同僚がすでに削除してしまった古いコードのバグをお節介にも直して上げるヘマ、などが発生する確率が上がってしまうからです。

また頻繁にやるほど、コンフリクトが起こった場合の規模が小さくて済みます。

シチュエーション2

新しいタスクのためにコーディングを始める前、つまり新規トピックブランチを作成する直前に、出来るだけ最新の状態(中央レポジトリのそのブランチの最新のコミット)をスタート地点にするため。

Git merge

上の git pull のシチュエーション1の流れで、git merge を使う、というパターンが9割りですね。

たまに、同僚が進めている、完了間近のトピックブランチを自分の作業ブランチに取り込むためにgit mergeすることもあります。この場合、当然同僚が中央レポジトリにgit pushして該当ブランチを公開していることが前提になります。

Git checkout

2つのシチュエーションがあります

シチュエーション1

ブランチの間を行ったり来たりする、つまり作業ディレクトリをいろんなブランチの状態に切り替えるため。特に頻繁に使うのが作業中のトピックブランチを、合流予定ブランチ(例:master)に対して、最新のものにする一連の作業をする時。

git checkout master
git pull
git checkout topics/task2
git merge master

みたいな感じでcheckoutで移動します。

シチュエーション2

新規のトピックブランチを作成するとき。-b を指定して「新しいブランチを作って、そのブランチをチェックアウトする」という意味で

git checkout -b topics/task3

とやります。

Git push

git push

自分のトピックブランチを中央レポジトリにアップロードするために使います。私の一日の仕事は、git pushで終わることが多いです。中央レポジトリにpushすれば、クラウドストレージでバックアップされたことが確定するので、もしかりに自分のノートパソコンがどこかで水没してしまってもその日の作業内容は失われませんから。

最終的な目的ブランチ(例:master)へはpushではなく、プルリクエストを使います。プルリクエストはGitのコア機能ではないですが、一般的な方法です

Git remote prune origin

これも安全なGitコマンドの1つです。ブランチのお掃除に使います。

git remote prune origin

からなずgit fetchからやります。これは安全なコマンドなので使ってみれば簡単に理解できます。

手元の中央レポジトリにあるブランチのうち、GitHubなどの中央レポジトリではすでに削除されてしまったブランチもあるかもしれません。というのも、開発者はトピックブランチの役目が終わったらそのブランチを削除してしまうことが一般的だからです。

このコマンドを使うことで、もう存在しない中央レポジトリのブランチを、手元の中央レポジトリでも消してくれます。

この後にgit branch -v でブランチをリスト表示すると

  dev/topics/integration    37f95b9f9 [gone] add integration test
  dev/topics/topic3         711e639e2 [gone] adds unit test for logout feature
  dev/master                e8468657b initial poc load test

というように、もう存在しないブランチをトラックしている手元のブランチが見えます。こういった場合、

git branch -d dev/topics/topic3

などでブランチを消してしまいます。

ブランチが

Git branch -v

上の例で挙げたように、すでに存在しない中央レポジトリのブランチをトラックしている手元のブランチが見えるようにするために使います。

Git branch -d

これも既出ですが、手元のブランチは出来るだけお掃除して数が増えすぎるのを防ぎます。

まとめ

私個人の作業ワークフローにおいて、必要としないGitコマンドと、頻繁に使うGitコマンドを紹介しました。

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

複数コミットをcherry-pick

1コミットをもってくる場合

branch-1のコミット履歴
$ git log --oneline
je903h92 commit 3
03843h90 commit 2
09459090 commit 1
87436843 first commit

たとえば、branch-2に1つのコミットをもっていきたい場合は、git cherry-pick {commit number}で解決できます。

$ git checkout branch-2
$ git log --oneline
349fi29u new commit

$ git cherry-pick je903h92 # commit 3をもってくる

$ git log --oneline
je903h92 commit 3 # コミットが追加されている
349fi29u new commit

複数コミットをもってくる場合

例えばcommit 1、commit 2、commit 3をbranch-2へもってくる場合は、git cherry-pick {start commit number}..{end commit number}を叩けばもってくることができます。
ですが、start commit numberの部分は、もってきたい始めのコミットの1つ前のコミット番号を指定しなくてはいけません。

$ git checkout branch-2
$ git log --oneline
349fi29u new commit

$ git cherry-pick 87436843..je903h92 # commit 1~3をもってくる

$ git log --oneline
je903h92 commit 3
03843h90 commit 2
09459090 commit 1
349fi29u new commit
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

Gitコマンド逆引き

備忘メモとして随時更新していきます

変更を一時退避
git stash save

*stash とは こっそりしまう、隠す、蓄える の意味。

退避したstashを確認
git stash list

stashを元に戻す
git stash apply (編集済み)

変更したファイル一覧
git stash show

スタッシュを全削除
git stash clear

最新のスタッシュを元に戻してからstashを削除
git stash pop

N番目のスタッシュを元に戻してからstashを削除
git stash pop stash@{N}

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

同じgit-hooksをリポジトリ個別指定で使えるようにするスクリプトを書いた

先日、globalなgit-hooksを設定して、すべてのリポジトリで共有のhooksを使うという記事で、git-hooksをグローバルに展開する方法を書きました。

今回は、それとは逆にRepositoryごとに個別にスクリプトを展開することが目的です。

グローバルなgit-hooksを用意したくないケース

基本的にはグローバルなgit-hooksの設定を用意すればいいですが、Repositoryごとに行うかどうかを変えたいということもあります。

例えば、会社のgitリポジトリにコミットする際に、git.emailが個人のものになっていないかチェックするスクリプトは、会社のRepositoryには適用したいですが、個人のRepositoryには適用したくないといった形です。

これを実現するために以下のスクリプトを書きました。

copy-git-hooks.sh
#!/bin/bash -eu

function echo_usage() {
  echo "usage: ${0} target_git-hooks_name target_git_dir_root_path"
  exit 1
}

if [ $# -ne 2 ]; then
  echo_usage
fi

target_script=$1
target_dir=$2

GIT_ROOT=$(git rev-parse --show-superproject-working-tree --show-toplevel | head -1)
SCRIPT_DIR="${GIT_ROOT}/git-hooks"
if [ ! -e "${SCRIPT_DIR}/${target_script}" ]; then
  echo "${SCRIPT_DIR}/${target_script} not found."
  echo ""
  echo "ls ${SCRIPT_DIR}/*"
  ls ${SCRIPT_DIR}/*
  echo ""
  echo_usage
fi

if [ ! -d "${target_dir}/.git" ]; then
  echo "${target_dir} is not git root dir."
  echo ""
  echo_usage
fi

script_name=$(echo ${target_script} | cut -d "." -f 1)
script_type=$(echo ${target_script} | cut -d "." -f 2)

# まだ対象のhooksファイルがない場合、自動生成
if [ ! -e "${target_dir}/.git/hooks/${script_type}" ]; then
  echo '#!/bin/bash' >>"${target_dir}/.git/hooks/${script_type}"
  echo "" >>"${target_dir}/.git/hooks/${script_type}"
  chmod 700 "${target_dir}/.git/hooks/${script_type}"
fi

ln -s "${SCRIPT_DIR}/${target_script}" "${target_dir}/.git/hooks/__${script_name}"

echo "source \$(dirname \${BASH_SOURCE})/__${script_name}" >>"${target_dir}/.git/hooks/${script_type}"

使い方

以下のようなディレクトリ構成でスクリプトを用意します。

.
├── README.md
├── git-hooks
│   └── personal_address_not_confirm.pre-commit
└── script
    └── copy-git-hooks.sh

ここでgit-hooksディレクトリには、スクリプトの名前.git-hookのアクション名という命名規則で、スクリプトのテンプレートを用意しておきます。

たとえば、先程例にあげた「会社のgitリポジトリにコミットする際に、git.emailが個人のものになっていないかチェックするスクリプト」であれば、以下のようになります。

personal_address_not_confirm.pre-commit
#!/bin/bash

# personal_address_not_confirm
## git configをチェックして、user.emailが個人アドレスになっていないか確認

COMPANY_DOMAIN="example.com"
git config user.email | grep -i ${COMPANY_DOMAIN} > /dev/null
if [ $? -ne 0 ]; then
  echo "git user.email is $(git config user.email)."
  echo "It is not a company email address."
  exit 1
fi

これをスクリプトを使って、gitリポジトリに展開するときは、以下のコマンドを実行します。

./script/copy-git-hooks.sh personal_address_not_confirm.pre-commit /path/to/target-git-repository

これを実行することで、ファイル拡張子から自動的にアクション名を取得、.git/hooks/以下にスクリプトを配置します。
.git/hooks/にファイルが存在しない場合は、自動作成も行います。

また、配置されるスクリプトは、__${スクリプト名}という命名で.git/hooks/以下にシンボリックリンクを貼った上で、各アクションのスクリプトからsoruceで呼び出す形になっています。

たとえば、上記のコマンドで personal_address_not_confirm.pre-commit を展開した場合、 /path/to/target-git-repository/.git/hooks/pre-commitには以下が書き込まれます。

#!/bin/bash

source $(dirname ${BASH_SOURCE})/__personal_address_not_confirm

そして、__personal_address_not_confirmは、personal_address_not_confirm.pre-commitへのシンボリックリンクになっています。

$ ls -la /path/to/target-git-repository/.git/hooks/
drwxr-xr-x  16 user  staff   512  2 18 05:56 ./
drwxr-xr-x  12 user  staff   384  2 18 05:33 ../
lrwxr-xr-x   1 user  staff    92  2 18 05:56 __personal_address_not_confirm@ -> /path/to/script_dir/git-hooks/personal_address_not_confirm.pre-commit
-rwx------   1 user  staff    67  2 18 05:56 pre-commit*
(以下略)

これにより、git-hooksスクリプトを機能ごとに分割・一括管理した上で、Repositoryごとに展開できるようになりました。

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

Github CLI使ってみた[コマンド一覧]

前書き

最近出てきたCLIでGithubが扱えるソフトウェアGithub CLIを使ってみました。

いままでたくさんCLIツールはでていたのですが
https://qiita.com/ryuichi1208/items/45fd2cdd865097a7ad3d
公式出のツールは2つめ?っぽいです。(hubが最初?)

この記事ではプルリクエストをPRと表記するときがあります
コマンド→解説の構成です

この記事でやっていること

  • Github CLIのコマンドの挙動網羅

この記事でやらないこと

  • GithubCLIのインストール法の解説(公式に書いてあります)
  • 既存のCLIソフトウェア(hub等)との比較

記事本体

GithubCLIで現在できること

  • PRの作成
  • PRの一覧表示
  • PRのステータス表示
  • PRのページをブラウザで開く
  • PR対象ブランチへのチェックアウト
  • issueの作成
  • issueの一覧表示
  • issueのステータス表示
  • issueのページをブラウザで開く

今回全部試してみたので書いていきます。

プルリクエストの操作

PRの作成

Github CLIのプルリクエスト関連操作をまとめています

$gh pr create
> Creating pull request for ブランチ名 into [Base Branch名] in ユーザー名/リポジトリ名

現在のGitブランチを認識し、そのブランチからBase branch(github側で設定)へのPRとして作成されます

$gh pr create

Creating pull request for ブランチ名 into [Base Branch名] in ユーザー名/リポジトリ名

? Title READMEの開発項目のissue移行に際してのREADME修正
? Body [(e) to launch nano, enter to skip]

eキーを押すとnanoエディタが開き、本文部分のMarkdown記法での入力が可能です。
(ちなみにnanoエディタは書き終わったらCtrl + Oで保存→Enter(本来はここでファイル名を入力.Github CLIは勝手にやるので触らないのが吉?)→Ctrl + Xで閉じる)です
image.png
2019/02/18追記
PRのテンプレート(PULL_REQUEST_TEMPLATE.md)とかあると自動で読み込んでくれます!

$ gh pr create

Creating pull request for ブランチ名 into [Base Branch名] in ユーザー名/リポジトリ名

? Title fff
? Body <Received>
? What's next?  [Use arrows to move, type to filter]
> Preview in browser
  Submit
  Cancel

Preview in blowserを選ぶと、Submit前のPRページに飛んでプレビューできます(ラベルとかレビュワーはここで設定する)

Submitはプレビューせずにそのまま送信される

PRの一覧表示

gh pr list

で可能。現在出ているPRを、そのブランチと一緒にリスティングされる

PRのステータス表示

gh pr status

/*以下出力*/
Relevant pull requests in YaCpotato/project_manager

Current branch
  #17  READMEの開発項目の移行に際してのRE... [update/readme]

Created by you
  #17  READMEの開発項目の移行に際してのRE... [update/readme]

Requesting a code review from you
  You have no pull requests to review

現在のブランチと、PRが出ていたらそれも出してくれる。あとは
* 他ブランチの自分が作ったPR
* コードレビューをリクエストされたPR
の3種類が見れる

PRのページをブラウザで開く

gh pr view [PR番号(#12みたいな数字)]
gh pr view #17

このコマンドを打つと対象PRをブラウザで開いてくれる

PR対象ブランチへのチェックアウト

gh pr checkout [PR番号(#12みたいな数字)]
gh pr checkout #17

そのPRが出されているブランチにチェックアウトする。

issueの操作

Github CLIのissue関連操作をまとめています

issueの作成

gh issue create
/*以下出力*/
Creating issue in YaCpotato/project_manager

? Title カレンダーインポートモーダルの実装
? Body <Received>
? What's next?  [Use arrows to move, type to filter]
  Preview in browser
> Submit
  Cancel

ほぼPRのcreateコマンドと一緒

issueの一覧表示

gh issue list
/*以下出力*/
Issues for ユーザー名/リポジトリ名

#16  ガントチャートのレイアウトをガ?...                                
#15  イメージ画像をアップロードでき?...                                
#14  カレンダーインポートモーダルの?...                                
#13  共有カレンダーテンプレートの実装                                   
#12  ログイン済みGoogleアカウントから?...                            

こちらは特にPRのような種類わけはない模様

issueのステータス表示

gh issue status
/*以下出力*/
Relevant issues in ユーザー名/リポジトリ名

Issues assigned to you
  #15 イメージ画像をアップロードできるようにする about 40 minutes ago

Issues mentioning you
  #16 ガントチャートのレイアウトをガチる about 41 minutes ago

Issues opened by you
  #15 イメージ画像をアップロードできるようにする about 40 minutes ago
  #16 ガントチャートのレイアウトをガチる about 41 minutes ago
  #14 カレンダーインポートモーダルの実装 about 53 minutes ago
  #13 共有カレンダーテンプレートの実装 about 57 minutes ago
  #12 ログイン済みGoogleアカウントからのカレンダー取得 about 59 minutes ago
  • アサインされているissue
  • メンションされているissue
  • 自分が開いたissue の3種類に分かれてリスト表示されます。

issueのページをブラウザで開く

gh issue view [issue番号]

PR版とほぼ同じ。対象issueをブラウザで開く

最後に

個人的に便利!と思った点は
gh pr checkout でPRが出されているブランチにチェックアウトできること
PRページからブランチ名コピーしてチェックアウトするのめんどくさいので
gh pr statusもしくは listからのgh pr view PR番号
上記とPRのレビュー時にすぐにブラウザに飛べる

当方Github用のCLIは初めてだったので既存のものと比較ができなくて残念です。この記事がどなたかの比較の際の参考になれば幸いです。

終わります。
よかったらTwitterフォローしてください

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