- 投稿日:2019-07-11T16:08:44+09:00
[Git] ファイル単位でstashする
〜ローカルリポジトリで作業中〜
ワイ 「よ〜し作業終わったしcommitするゾ!」On branch master 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: fuga.py modified: hoge.py no changes added to commit (use "git add" and/or "git commit -a")
ワイ 「branch切り替えるのを忘れてmasterを変更してもうた・・・」
ワイ 「featureブランチに変更を移したい。。。」
git stash
そんな時に使えるのが
git stash
ファイルを一時的に退避させることができる。
もちろんbranch間の移動も可能なので無理やり汚いcommitをする必要もない。$ git stash Saved working directory and index state WIP on master: e1c4afb [feat] hoge.py fuga.py $ git status On branch master nothing to commit, working tree clean $ git stash list stash@{0}: WIP on master: e1c4afb [feat] hoge.py fuga.pyこんな感じで変更が退避されて
$ git stash list
で確認することができる
他のbranchに適用させたい時は以下のようにする$ git checkout feature/hogefuga Switched to branch 'feature/hogefuga' $ git status On branch feature/hogefuga nothing to commit, working tree clean $ git stash pop On branch feature/hogefuga 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: fuga.py modified: hoge.py no changes added to commit (use "git add" and/or "git commit -a") Dropped refs/stash@{0} (0706e9eb4284f2fcd1bb6ac6a049beb0e52ffdb6)おけまる!
ファイル単位でstashしたい
特定のファイルだけ別のbranchに移動させたいという場合もあるだろう。
$ git stash
だけだと変更の及んだ全てのファイルがstashされてしまう。
ファイル単位でstashするには以下のようにする。// 退避する時 $ git stash push -- <filepath> // 戻す時(番号はstash番号) $ git stash pop stash@{0}実際にやってみたのが以下
$ git branch develop feature/hogefuga // ここにfuga.pyを移動 feature/hogehogefugafuga * master // hoge.py fuga.py$ git stash push -- hoge.py Saved working directory and index state WIP on master: e1c4afb [feat] hoge.py fuga.py $ git stash push -- fuga.py Saved working directory and index state WIP on master: e1c4afb [feat] hoge.py fuga.py $ git stash list stash@{0}: WIP on master: e1c4afb [feat] hoge.py fuga.py stash@{1}: WIP on master: e1c4afb [feat] hoge.py fuga.py $ git checkout feature/hogefuga Switched to branch 'feature/hogefuga' $ git stash pop stash@{0} # fuga.py On branch feature/hogefuga 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: fuga.py no changes added to commit (use "git add" and/or "git commit -a") Dropped stash@{0} (3c71ae19147fc1ef56a748df9fe849471f933956)できた!
終わりに
stash自体まだまだ便利なオプションとかあるのでそこは各自で調べてもらえると嬉しいです。
快適なgitライフを送りましょう!
- 投稿日:2019-07-11T15:54:27+09:00
Gitコマンド
書いてあること
- よく使うGitコマンドの利用方法
- Git初期設定
環境
- CentOS Linux release 7.6.1810 (Core)
- Git 2.22.0
事前準備
初期設定
設定ファイル(.gitconfig)は各ユーザーのホームディレクトリに作成される
設定確認
bash$ git config --listよく使う設定
bash#ユーザー名、メールアドレスを登録 $ git config --global user.name $ git config --global user.email #カラー設定 $ git config --global color.ui auto $ git config --global color.diff auto $ git config --global color.status auto $ git config --global color.branch auto #Push方式 $ git config --global push.default simple #ファイル名の大文字・小文字を区別 $ git config --global core.ignorecase false #UTF8問題対策 $ git config --global core.precomposeunicode true #日本語ファイルの文字化け防止 $ git config --global core.quotepath false #エディタをvimに設定 $ git config --global core.editor 'vim -c "set fenc=utf=8"'Gitコマンド
共通・準備
ローカルリポジトリ初期化
bash$ git init
ローカルリポジトリ状況確認
bash$ git status
変更履歴を確認
bash#デフォルト $ git log #ログを1行で表示 $ git log --oneline #ログをグラフ表示 $ git log --graphコミット
インデックスにファイルを追加
bash#ファイル指定 $ git add <ファイル名> #ディレクトリ指定 $ git add <ディレクトリ>コミット
bash$ git commit -m "コメント"プッシュ
リモートリポジトリの確認
bash$ git remote -vリモートリポジトリを登録
bash$ git remote add <name> <URL> $ git remote add origin https://・・・リモートリポジトリのURLを変更
bash$ git remote set-url <name> <URL>
リモートリポジトリ名を変更
bash$ git remote rename <old-name> <new-name>
リモートリポジトリを削除
bash$ git remote rm <name>プッシュ
bash$ git push -u <アドレス> <ブランチ> $ git push -u origin masterクローン
クローン
bash$ git clone <URL> <ディレクトリ名>
プッシュ
bash#クローンしたリポジトリではアドレス、ブランチを省略可能 $ git pushプル
プル
bash$ git pull <アドレス> <ブランチ> $ git pull origin masterブランチ
一覧を確認
bash$ git branch
ブランチを追加
bash$ git branch <ブランチ>
チェックアウト(切り替え)
bash$ git checkout <ブランチ>
ブランチのマージ
bash#masterとマージ $ git checkout master $ git merge <ブランチ>ブランチを削除
bash$ git branch -d <ブランチ>タグ
タグの確認
bash$ git tag
タグの確認(コメント付き)
bash$ git tag -n軽量タグを追加
bash$ git tag <タグ>
コメント付きタグを追加
bash$ git tag -am "コメント" <タグ>タグを削除
bash$ git tag -d <タグ>参考
Gitをインストールしたら真っ先にやっておくべき初期設定
最低限しておくといいgitconfigの設定
gitで便利なエイリアス達
サルでもわかるGit入門
- 投稿日:2019-07-11T15:24:04+09:00
チームにVSCode利用者が多い場合は、Gitリポジトリにsettings.jsonをコミットしよう
概要
チームでVSCodeを使うエンジニアが多い場合には、VSCodeの設定ファイルをリポジトリに乗せることが得策であるお話です。
チーム開発で起こる問題
フォーマットのばらつき
チーム内のエンジニアはもちろん別々の人間なので、書くコードは人それぞれです。
ある程度ルールを統一したからと言っても、どこかで必ず差異が生じてきます。
これらは、コードレビュー時に目視で確認することもありますが、細かすぎる作業なので極力避けたいものです。具体例
- イコールの位置揃え
- 文字列を
''
で囲むか、""
で囲むか。- メソッド定義の中括弧は改行してから書くかどうか
規約の不認識
こちらもある程度ルールを決めていても、必ずばらつきが出てきます。
物によっては、レビュー者も規約内で不認識の部分があり、規約に沿っていないコードがマージされてしまうことが多かったりします。
レビューでは気づきますが、ビジネスロジックのコアな部分ではないので、できればあまり時間を割きたくない部分です。具体例
- 1行は何文字までOKか
- プロパティのアクセス修飾子どうするか
- メソッド名はキャメルケースかスネークケースか
ルールを決めるだけではまだ足りない
ここで、これらをプロジェクト内でルールとして決めたりすることが多かったりします。
しかし、ここでルールを決めただけだと、下記の問題が生じたりします。
- コード規約やフォーマットの種類をキャッチアップする時間が必要
- 運用していても、意識し続けない限り、どこかで崩れる
- これらをチェックするレビューの時間が勿体無い
解決策
そんな時には、エディターにお任せしてしまいましょう。
特に、VSCodeの場合は、エディター内での設定ファイルを共有することができるので、それを活用すると楽です。どんなことをしてくれるのか
上記の問題を解決できます。
自動でフォーマットを整えてくれる
""
がある場合は''
に変える- 1行が長すぎた場合は、自動で改行
- インデントを自動で揃える
コード規約に反していた場合の注意
- 非推奨の関数を使っている場合など
どうやれば良いのか
チームで共有するリポジトリ内に、
.vscode/settings.json
を作りましょう。
例えば、Vue.jsなどJavaScriptを中心としたプロジェクトの場合は、下記のような設定があります。settings.json{ "editor.formatOnSave": false, "eslint.autoFixOnSave": true, // Vus.js用のフォーマット設定 "eslint.validate": [ "javascript", "javascriptreact", { "language": "vue", "autoFix": true } ], "prettier.eslintIntegration": true, }eslintに従って、ファイル保存時にフォーマットを自動で整えてくれる設定です。
prettierというプラグインを使う前提なので、prettierをVSCodeにインストールしておけば、プロジェクトをcloneした人は何もせずとも、上記に従って自動フォーマットが行われる環境になります。そのため、コードレビュー時にフォーマットを気にする必要はありませんし、開発者もフォーマッタや規約に関してキャッチアップする必要はありません。
時間も大幅短縮で幸せになれますね。最後に
エディターは人それぞれ異なるため、複数のエディターに対する設定をプロジェクトのリポジトリに入れておいても良いでしょう。
自動化できるところは自動化し、ビジネスロジックに集中することで、より品質が保たれる上に開発のスピードが早くなるかと思います。
ぜひ参考にしてみてください!
- 投稿日:2019-07-11T14:33:05+09:00
Azure DevOps Repos(リポ)の超概要&Gitについて簡単に説明
ーーGitを理解されている方は読む必要がありません。
Azure DevOps全体の概要については、こちらをご覧ください。
https://qiita.com/mstakaha1113/items/1cf45a5119e1397d0315"Repos(リポ)"は、生産物を保存するサービスです。
サービスとして何があるのかご紹介します。
超概要なので、具体的な画面の説明はありません。そもそもリポジトリ?
"Repos"は、ソースコードを中心とした生産物を履歴などを意識しながら保管できるサービスです。
このような仕組みを一般的に"リポジトリ"と呼びます。
過去、様々なリポジトリが存在していました(もちろん今も存在しています)。
たとえば、
- VSS
- CVS
- Subversion
など、聞いたことや使ったことがあるのではないかと思います。
もしリポジトリを使っていない場合、開発を進めるたびに新たなフォルダを作ってコピーして改修するというような作業に明け暮れることとなります。
これ自体も問題なのですが、複数名で複数の課題に立ち向かっていく際、誰がいつどこをどのように修正したのか、それをどうレビューし承認し結合するのかということを制御するのが非常に困難になります。
このような課題を解決すべく、リポジトリはあります。リポジトリは、みんなが実施した作業を無駄なくバリューに変換するためのものです。
"Repos"は2種類のリポジトリを提供している
"Repos"では、TFVCベースとGitベースという2種類のリポジトリを提供しており、プロジェクトごとにどちらを採用するかを選択することができます。
端的に書くと、
- TFVC:中央集権的なリポジトリ、中央に1つリポジトリを配置して、全員がそこに対して生産物を登録していく。
- Git:地方分権的なリポジトリ、ある程度自由に中央のリポジトリをコピーしてきて、そこに対して生産物を登録、その後任意のタイミングで中央に申請して取り込んでもらう。
というような差がありますが、世の流れもありますし差を追求するのはやめましょう。
これからやるならGitベース1択
もちろん個人の主観ではありますが、これからAzure DevOpsを使うのであればGitを採用してください。
この先の説明も、Gitのみを対象としています。"Repos"のメニュー
かなりザックリした説明になります。
そもそものGitに関する簡単な説明は、このあと書きたいと思います。Files : ブランチに登録されているファイル一覧を表示します。
Commits : ブランチへのコミットの変遷を表示します。
Pushes : ブランチに対してプッシュされた情報を表示します。
Branches : ブランチの一覧を表示します。
Tags : タグ付け機能がありますので、それを利用します。
Pull requests : "ブランチで作ったものを承認して取り込んでほしい"という要求を出したり承認したりします。Gitの簡単な説明
冒頭で"Gitは地方分権的なリポジトリ"と書きました。ここでは、Gitと、中央集権的なリポジトリに触れて、メニューの理解を進めたいと思います。
簡単に書きすぎているが故の説明不足など、ご容赦ねがいます。中央集権的なリポジトリはファイルをコピペする
まずはGitとは異なるポリシーを持ったリポジトリをおさらいします。
たとえばVSSのようなリポジトリを使った開発を行う場合、リポジトリからフォルダやファイル構成を自分のPCにダウンロードしてきます。
取得するのは、主に最新のフォルダやファイルの構成です。
ファイルを更新したのち、リポジトリにアップロードを行います。
アップロードするのは、フォルダ構成やファイルそのものです。
どんなつもりでアップロードしたのかをコメントとして記述しますが、このコメントや履歴は中央にある1つのリポジトリで一括生成、管理します。
とてもシンプルでわかりやすいのですが、いくつかの問題も発生します。(実際には各ソフトウェアで解決が行われており問題に直面することは少ないと思いますが、理論上は以下のとおりです。)
- 複数名で同じファイルを改修したい場合、ファイルの取り合いが発生する
- 複数の案件に対する改修を実施している場合、コミットタイミングがわからなくなる
- 上記2点を踏まえると、状況次第では改修の"待ち"が発生する
Gitはリポジトリそのものをコピペする
Gitでは、リポジトリそのものを自分のPCにクローン(ダウンロード)します。
作業は個人のPCの中にクローンされたリポジトリに対して実施します。
基本的には1案件に対する複数ファイルの改修を行い、ローカルのリポジトリに対してコミット(改修後のファイルの登録)を行います。
全ての改修が終わり、テストも完了した時点で、このローカルのリポジトリを元あった場所(たとえばAzure DevOpsのRepos)にプッシュ(アップロード)します。
リポジトリとしてクローンしてくることのメリットは、コミット時に顕著になります。
リポジトリには、最終的なファイルだけではなく、ローカルリポジトリを更新した履歴が入っています。ファイルと履歴を一式送り込むことができますので、受け入れる側は、改修の意図を理解しながら受け入れるか否かを判断できます。実際にはどう扱うのか
先ほどの絵ではリポジトリは1つの大きな枠として表現しましたが、実際には1つではありません。
実際にはこのように扱います。
時間の流れを意識しながら、図の左側から右側へ向けて説明します。
はじめ、リポジトリは"master"という場所から始まります。
基本的な作業は
- "master"から"branch"(改修用のコピー品)を作る
- "branch"をローカルに"clone"(ダウンロード)する
- 改修しテスト、適宜"clone"したリポジトリに"commit"(登録)する
- "clone"したリポジトリを"push"(アップロード)する
- "Pull request"を発行しレビューと"merge"(ファイルと改修履歴の統合)を依頼する
- "branch"を"master"にマージする
という工程で行われます。
案件Aは、この基本的な作業です。緑色がmaster branch、青色のブランチを作成してオレンジ色のcloneを実施、改修内容をpush(オレンジ)して、ブランチ(青)をmaster(緑)にマージしています。
案件Cは案件Bのマージ前に作業を開始しています。案件Cのマージ時には案件Bに伴う改修が入ったmasterと比較して、案件Cの変更をマージするか否か選択します。同じファイルを改修している際は"conflict(衝突)"をGit側で検知してくれますので、状態を確認し、案件Cの取り込み方を検討します。
案件Dと案件Eも同じ構図です。こちらは後から始まる案件Eを先にマージしていますが、すべての状態を履歴として管理していますので、問題があっても確認は容易です。
これらの状態の確認や承認を実施するために"Pull request"が存在します。
他にも多くの機能がありますが、主題ではありませんので割愛します。まとめ
"Repos"についてメニューを確認しました。
"Repos"はリポジトリのことです。リポジトリを使えば、ファイルとその改修履歴を扱うことができます。
Gitは分散型のリポジトリです。最初から分散することを意識していますので、ファイルの取り合いやまわりの作業者との協調から解放されます。
その変わり、マージするときは内容の差異を正しく評価しなければなりません。Gitはそのことも容易に扱える仕組みになっています。
動画のようなもので無い限り、できるだけ開発中の資産はリポジトリに登録するようにしましょう。
設計書のようなドキュメントであってもリポジトリの利用をおすすめします。(設計書は無い方が良いですが、全部はなくせないと思いますので。)
また、リポジトリに入れたものは差分を確認できますので、差分を確認できるテキストベースの情報を生産するようにしましょう。
- 投稿日:2019-07-11T14:11:39+09:00
Gitのリベースでベースが変更される際に、コミット番号が変わる件を確認する
概要
Gitを用いていて、わりとわかりにくい「リベース」について。
developブランチと、ある時点のdevelopから派生したfeatureブランチ(feature/dev_#50としました)があったとします。
developがコミットされて先に進んでしまったときに、あたらしい時点のdevelopからの派生として、feature/dev_#50を リベースするシーンがあります。こういうことですね。
コミット履歴は前のコミット番号を保持する というGitの性質において、リベースした後のコミットたち(おもに
5d6a09d
,ef3cd3b
のことです)のコミット番号ってどうなるのかな?ってのを見てみます。前準備
git init echo "hello" >> Calc.java echo "hello" >> Calc2.java git add Calc.java && git add Calc2.java && git commit -m 'initial' git checkout -b develop && git checkout -b feature/dev_#50いま時点の状態を確認します。
$ git log --oneline --graph * 39eca7c (HEAD -> feature/dev_#50, master, develop) initial $develop(
39eca7c
) から feature/dev_#50 がブランチされました。SourceTreeでみるとこうです。
つづいて feature/dev_#50 に2回コミットしてみます。
git checkout feature/dev_#50 echo "hello from feature/dev_#50" >> Calc2.java git commit -a -m '1. modified in dev_#50' echo "hello from feature/dev_#50" >> Calc2.java git commit -a -m '2. modified in dev_#50'いま時点の状態を確認します。
$ git log --oneline --graph * ef3cd3b (HEAD -> feature/dev_#50) 2. modified in dev_#50 * 5d6a09d 1. modified in dev_#50 * 39eca7c (master, develop) initial $develop(
39eca7c
) から派生した feature/dev_#50 はいま時点ef3cd3b
を指しています。つづいて、develop に1つコミットします。
git checkout develop echo "hello from develop" >> Calc.java git commit -a -m 'modified in develop'いま時点の状態を確認します。
$ git log --oneline --graph * f618196 (HEAD -> develop) modified in develop * 39eca7c (master) initial $
39eca7c
を指していたdevelopはいま、f618196
を指しています。feature/dev_#50 との関係を見るためSourceTreeで見てみると、、、
- develop は
f618196
- feature/dev_#50 は
ef3cd3b
を指していることが図からもわかります。
リベースしてみる。
さてリベースについてです。
リ・ベースとはその名の通り、最初39eca7c
を指していた develop、から派生した feature/dev_#50 を、いまのf618196
を指しているdevelop から派生するように切り替えるということです。 図示してみると(最初の図ですが)こういうことです。とするとコミットログは、
4番目:
ef3cd3b
(feature/dev_#50 のコミット2個目)
3番目:5d6a09d
(feature/dev_#50 のコミット1個目)
2番目:f618196
(いまのdevelopが指しているコミット)
1番目:39eca7c
となるイメージですが、3,4番目の
5d6a09d
,ef3cd3b
は、いまのdevelop(f618196
) からブランチした後の新たなコミットとなり、新規にコミット番号が振られることになります。やってみると、、、
git checkout feature/dev_#50 git rebase developさあ、いま時点の状態を確認します。
$ git log --oneline --graph * d227747 (HEAD -> feature/dev_#50) 2. modified in dev_#50 * 503a3d3 1. modified in dev_#50 * f618196 (develop) modified in develop * 39eca7c (master) initial $想定通りとなりました。
リベースは派生元を切り替えるわけなので、派生先のコミット達は軒並み、新規コミットとしてあつかわれることがわかりましたね。。
おつかれさまでした。
関連リンク
- 投稿日:2019-07-11T10:57:05+09:00
Git管理をしたくないファイルをpushしてしまった
Git管理下に残したくないファイルをcommit pushしてしまった。
しかも、その後コミットを複数回重ねてしまい、revertやresetをしてファイル修正するのはめんどくさい
※それほど、重要なファイルコミットしたわけでもないことが大前提。そんなときに
.gitignore 対象ファイルやディレクトリの指定push後にgitignoreを追記しても、git管理や履歴には残ってしまうので
キャッシュを削除する。git rm -r --cached . git commit -m "キャッシュを削除し、gitignoreを反映" git push origin 指定のブランチ参考
https://laraweb.net/environment/3072/
https://qiita.com/kamesennin/items/226e3839e457b342b89f
https://qiita.com/Potof_/items/c75eba9cfa72819506de
- 投稿日:2019-07-11T00:08:30+09:00
GitHubで誤って違うブランチにマージしてしまった時にWeb上だけで戻す方法
状況
- masterとブランチAは同じコミット上にいる
- ブランチAを親ブランチとしてブランチBを作った
- ブランチBでソースをゴニョゴニョいじってコミット&プッシュした
- GitHubのWebでブランチBをブランチAにマージしようとして、誤ってmasterにプルリク出してマージしてしまった
- 間違いに気が付かずにWeb(リモート)でブランチBを削除した
- 間違いに気が付かずにローカルでブランチBを削除した
- クライアントツールの樹形図を見ていて間違いに気がついた
Web上だけで戻す(revert)方法
1. リモートで削除してしまったマージ元のブランチを復活させる
- [Pull Request]タブを開いて[Filters]に入力されている「is:open」を削除してEnter
- マージ済みのプルリクが表示されるので、間違ったマージを選択して開く
- 削除してしまったマージ元のブランチの横にある[Restore branch]ボタンでブランチを復活させる
2. マージを戻す
- マージしたところの横にある[Revert]ボタンで「マージを戻す用のプルリク」を作る
ここで
revert-{誤ったプルリクの番号}-{マージ元のブランチ名}
というフォーマットの「マージを戻す用のブランチ」が自動で作成される「マージを戻す用のプルリク」をマージする
「マージを戻す用のブランチ」を削除する(とっておきたかったら削除しなくてもOK)
3. 今度は間違えないようにマージをやり直す
- [Code]タブの[branches]タブで復活させたマージ元のブランチの横にある[New pull request]ボタンでプルリク画面を表示する
- マージ先ブランチが間違っていないことをすごくよく確認してプルリクを出してマージする
ローカルで削除したブランチはWeb上では戻せない
戻せたらスゴスギと思う。
プッシュしないでうっかりローカルブランチを削除してしまったから復活させたい!というときはgit reflog
とHEAD
で復活させられそう(やっていないけど)
git add
とかしてなくてまだGit管理下にいないファイルはもう無理かも
【Git】削除したブランチは復活できる!Git初心者から中級者になりたい方へ | ジーニアスブログ