Git Commands

たまに忘れるので、自分にもわかりづらい適当なメモを残します。

基本

用語概念
GIT警察、検察
リポジトリ
ファイル人間
ファイルの変更犯罪
アントラッキングファイル不法入国者
アンモディファイドファイルカタギ
モディファイドファイル被疑者
ステージドファイル被告人
コミット服刑
ブランチ前科
ステージング裁判所

18333fig0201-tn.png

逮捕&起訴

$ git add <Filename>
$ git add . # 全部
$ git add -p # 対話式で選択

判決

$ git commit -m 'commit message' # 判決理由が入る

強制送還

$ rm <filename> # 普通に削除
$ git clean -f # 先に--dry-run で確認すると酔い

免罪、誤認逮捕、不起訴

$ git rm <filename>
$ git mv <filename>
$ git reset <filename> # addしたindexにあるfileをindexから除外
$ git reset --hard HEAD^
$ git reset --hard <commit hash> # 刑の免除
$ git revert <commit hash> # 逆位相
$ git rebase -i # タイムリープ
$ git checkout <commit hash>

処分保留?

$ git stash list
$ git stash save -u <message> # アントラッキングも含める
$ git stash apply <stash number>
$ git stash drop <stash number>
$ git stash clear # 全消し

比較系

$ git diff 
$ git diff --cached
$ git diff HEAD HEAD^

取り調べ

$ git status
$ git status --short

実刑の確認

$ git show <commit name>

前科の確認

$ git log 
$ git log --graph --date=short --format='%C(yellow)%h%C(reset) %C(magenta)[%ad]%C(reset)%C(red)%d%C(reset) %s %C(cyan)@%an%C(reset)' # aliasのやつ

マージ系

$ git merge <branchname> # 現在のブランチに別のブランチをマージ
$ git push -f # プルリク歴史修正の時の強制プッシュ
$ git push origin <local branchname> # 現在のブランチをリモートにマージ
$ git pull origin <remote branchname> # リモートのブランチを現在のブランチにマージ
$ git fetch # originの今のブランチの変更履歴を取得 --allだと全てのブランチ
$ git mergetool

ブランチ刑

$ git reflog # ブランチの操作ログ
$ git checkout -b <branchname> # ブランチを作成してチェックアウト
$ git branch -a  # 全部ブランチ名の確認
$ git branch -r  # リモート全部ブランチ名の確認
$ git branch -v  # 詳細表示
$ git branch -d <branchname> # ローカルのを削除
$ git push origin :<branchname> # リモートに削除

$ git fetch
$ git checkout master
$ git merge origin/master

タグとか

$ git tag # tag一覧
$ git tag <tagname> # タグ付け
$ git -d <tagname> # ローカルのタグ削除
$ git push origin :<tagname> # リモートに削除
$ git push origin --tags # タグ全部送信

最初にやること

$ git init # 一から作る
$ git remote add origin git@<ssh hostname>:<myname>/<reponame>.git
$ touch README.md
$ git add .
$ git commit -m 'init'
$ git push -u origin master
$ git clone # 他人のパクる

不法入国者へ戻す

$ git rm --cached "filename"
$ echo "filename" >> .gitignore 

submodule

$ git submodule add https://github.com/twbs/bootstrap.git bootstrap
$ git submodule update # 内部submoduleを同期する

後からgitignoreに追加

$ echo "hoge.tmp" >> .gitignore
$ git rm --cached hoge.tmp

リベース

マージとリベースの違い

※Gitは共通の祖先のコミットから比較してdiffを出している。

$ # 下図だと、共通の親はCなのでCからFまでの変更点(EとDへ変更した内容)としてまとめられる
$ checkout master && git merge topic 
$ # 下図だと、共通の親はEなのでEからD'までの変更点(Dで変更した内容)としてまとめられる
$ checkout topic && git rebase master

マージ image リベース image

プルリクが別のプルリクに依存する場合のプルリクの作り方

$ git fetch --all # リモートのブランチ一覧取得
$ git checkout develop # developブランチは派生元にしたいブランチ(このブランチはmasterから派生していおり、変更が今後ありそうにないブランチ、プルリクではLGTM済み)
$ git checkout feature # developブランチから新たなfeatureを作成する
$ # featureブランチのプルリク作成
$ git commit -m "追加" # featureに追加する
$ # developのプルリクがmasterにマージされた
$ git fetch --all # リモートのブランチ一覧取得
$ git checkout feature 
$ git rebase develop # featureブランチの上で最新のdevelopにrebaseする
$ git push origin feature -f # フォースプッシュでプルリクの履歴を書き換える

プルリクのコミットをキレイにする(rebase squash)

$ git rebase -i <commit hash> # 修正したいコミットの一つ前のコミットのハッシュを指定する(0d4a808の前のコミットを指定する)

pick 9a54fd4 commitの説明を追加   # <- この中で一番古いのコミット
squash 0d4a808 pullの説明を追加    # <- これをsオプションで上のコミットと混ぜられる

# Rebase 326fc9f..0d4a808 onto d286baa
#
# Commands:
#  p, pick = use commit
#  r, reword = use commit, but edit the commit message
#  e, edit = use commit, but stop for amending
#  s, squash = use commit, but meld into previous commit
#  f, fixup = like "squash", but discard this commit's log message
#  x, exec = run command (the rest of the line) using shell
#
# If you remove a line here THAT COMMIT WILL BE LOST.
# However, if you remove everything, the rebase will be aborted.
#
$ git push origin hoge -f
$ # もしcannot squash without a previous commitが出た場合
$ git rebase --abort

プルリクの過去のコミットを変更する(rebase edit)

  • 空のコミットメッセージと内容のcommitがある場合は下手に
$ git rebase -i <commit hash> # 修正したいコミットの一つ前のコミットのハッシュを指定する(0d4a808の前のコミットを指定する)

pick 9a54fd4 commitの説明を追加   # <- この中で一番古いのコミット
edit 0d4a808 pullの説明を追加      # <- このコミットでの変更内容を再変更する

# Rebase 326fc9f..0d4a808 onto d286baa
#
# Commands:
#  p, pick = use commit
#  r, reword = use commit, but edit the commit message
#  e, edit = use commit, but stop for amending
#  s, squash = use commit, but meld into previous commit
#  f, fixup = like "squash", but discard this commit's log message
#  x, exec = run command (the rest of the line) using shell
#
# If you remove a line here THAT COMMIT WILL BE LOST.
# However, if you remove everything, the rebase will be aborted.
#
$ vim hoge.js 
$ git add hoge.js # 変更を追加
$ git commit --amend # コミットに追加する
$ git rebase --continue # コミットを適用する
$ git push origin hoge -f

リベースのマージ

$ git rebase branch
// コンフリクトしたファイルを修正後
$ git add conflicted_file
$ git commit
$ git rebase --continue
$ git rebase --abort // ダメそうだったら

スタッシュ

コマンドをよく忘れるが次を見ればいい。 https://qiita.com/akasakas/items/768c0b563b96f8a9be9d

コンフリクト解消

$ git pull origin master # コンフリ発生!!
$ git reset --hard ORIG_HEAD # マージを元にもどす

リベース前のブランチからの派生した新ブランチを、リベース済みの元ブランチへのリベースする方法

  • develop > feature > hotfix の順で派生しておりhotfixがfeatureの機能に依存している
    1. featureをdevelopでrebaseした(その結果featureのコミット番号が全部変わった)
    2. bugfixをfeatureでrebaseしようとするとconflictが発生した(しかも、diffがめちゃくちゃ)
$ git push origin hotfix # rebase前のhotfixのバックアップ
$ git checkout hotfix
$ git rebase --onto feature ff34ed1 # featureを元にしたff34ed1に続くcommitを持つhotfixのブランチを作る
$ # つまり、
$ # - ff34ed1は古いfeature(リベースされる前)の最後のcommit番号。
$ #   - つまり、hotfixのPRのコミットログにあるfeatureの最後のCommit番号 
$ #   - 別の言い方をすればhotfixブランチの元のcommit番号
$ # - featureオプションはもちろん新しいrebase済みのブランチを指す
First, rewinding head to replay your work on top of it...
Applying: AAAAAAAA #31
Applying: XXXXXXX #31
Applying: VVVVVVV #31
$ git diff master --stat # hotfixのPRのdiffとくらべて同じなら多分大丈夫
6 files changed, 251 insertions(+), 3 deletions(-)

つまり、rebaseされた元のブランチfeaturに、 rebaseされる前のfeatureの最後のcommit(hotfixの元のcommit)を足したということ

リベース前のブランチからの派生した新ブランチ(マージコミット済み)を、リベース済みの元ブランチへのリベースする方法

master > feature > hotfix の順でhotfixはfeatureからrebaseで切った。
ただし、masterが別のブランチ(feature2)でマージされ、歴史が進められたので、featureブランチとfeature2ブランチでconflictした
そこで、featureブランチをmasterでmergeし、マージコミットをfeatureブランチに作って、conflictを解消した
その後、featureブランチはmasterブランチにマージした(mergeコミットありで)
hotfixはfeatureから切られているので、featureに再rebaseしたが、hotfixの修正内容が反映されていない。
その時は、hotfixをmasterブランチでmergeして解消するのが良い。

同一ファイルを分割してCommit

$ git add -p
y or n or q...
$ git diff --cached # the diff between staging and HEAD

あるファイルをあるコミット/ブランチの前に戻す

$ git checkout c5f567~1 -- file_a.py file_b.py

https://stackoverflow.com/questions/215718/reset-or-revert-a-specific-file-to-a-specific-revision-using-git

--no-ff --no-commit

https://qiita.com/nog/items/c79469afbf3e632f10a1

参考文献

  • https://liginc.co.jp/web/tool/79390
  • http://www.backlog.jp/git-guide/stepup/stepup7_5.html
  • https://stackoverflow.com/questions/27445747/how-to-rebase-over-already-rebased-branch
  • https://stackoverflow.com/questions/1587846/how-do-i-show-the-changes-which-have-been-staged