LoginSignup
1
3

More than 3 years have passed since last update.

git 中級者になりたいメモ

Last updated at Posted at 2020-12-30

まえがき

git に関する知見をいくつかの視点から紹介します。ひとつでも新しい発見があれば幸いです。

リモート追跡ブランチの残骸を削除する

remote branch を削除しようと思うと

git push origin --delete feat1

とすれば可能だ。これで remote branch も remote-tracking branch も削除される。

ところで remote の feat1 を他人によってすでに削除されている場合、ローカルに残っている remote-tracking branch は消せない。以下のようなエラーになる。

$ git br -a
* feat1
  main
  remotes/origin/HEAD -> origin/main
  remotes/origin/feat1
  remotes/origin/main

$ git push origin --delete feat1
error: unable to delete 'feat1': remote ref does not exist
error: failed to push some refs to 'github.com:mochizukikotaro/git-study.git'

これは remote show することで、stale(新鮮じゃない、腐りかけている)していることが判る。

$ git remote show origin
* remote origin
  Fetch URL: git@github.com:mochizukikotaro/git-study.git
  Push  URL: git@github.com:mochizukikotaro/git-study.git
  HEAD branch: main
  Remote branches:
    main                      tracked
    refs/remotes/origin/feat1 stale (use 'git remote prune' to remove)
  Local branch configured for 'git pull':
    main merges with remote main
  Local ref configured for 'git push':
    main pushes to main (local out of date)

こういった branch は以下の二通りの方法で削除することができる。

git remote prune orign

# または

git fetch origin --prune

push の -u オプションとは何か?

リポジトリを新たに作るとき、以下を打つようにと言われる。

git remote add origin git@github.com:mochizukikotaro/git-study.git
git branch -M main
git push -u origin main

ここで push の -u オプションはなんだろう?

これは --set-upstream-to の省略系です。もしここで -u をつけなかった場合は git pull すると以下の提案を受けます

$ git pull
略
See git-pull(1) for details.

    git pull <remote> <branch>

If you wish to set tracking information for this branch you can do so with:

    git branch --set-upstream-to=origin/<branch> feat2

これは、作業ブランチに upstream が無い状態です。以下のコマンドで状態を確認することができると思います。

git branch -vv
git status -sb 

upstream を unset しする場合は以下。

$ git branch --unset-upstream
$ git status -sb
## feat2
$ git branch -vv
  branch fea2ffa insert hey feat2
* feat2  fea2ffa insert hey feat2
  main   67360e7 [origin/main: behind 4] add piyo.txt file

upstream を set する場合は以下。

$ git branch --set-upstream-to=origin/feat2 feat2
Branch 'feat2' set up to track remote branch 'feat2' from 'origin'.
~/D/s/git-study (feat2)
$ git status -sb
## feat2...origin/feat2

detached HEAD を理解しておく

公式のドキュメントを読めば書いてある。
https://git-scm.com/docs/git-checkout#_detached_head

以下をうつと、detached HEAD にできる。

$ git co HEAD~

そうすると以下のような提案を受けることになるが、はじめて detached になると焦る。

  git switch -c <new-branch-name>
  git switch -

そもそも detached じゃない場合は、HEAD は branch を参照している。以下のような状態。

$ cat .git/HEAD
ref: refs/heads/feat2

ところが、detached になっているのは以下のような状態。ブランチを参照するのではなく、直接コミットハッシュを指している。

$ cat .git/HEAD
6b751be4d4829ef98b4dfb9613b41423bd9cdcfc

原理をわかっていれば、慌てなくて済む。detached になってもおちついて、switch -c や switch - しておけば良い。

ちなみに HEAD^ に戻しながら、new branch を作る(detached にならずに)方法は、git switch -c new_branch HEAD^ でよい。

upstream branch を確認する

以下のように branch の -vv オプションで、upstream branch を確認できる。ローカルの feat2 は origin/feat2 が upstream に設定されている。なので feat2 で git pull をすれば、そこから自動で pull される。

$ git branch -vv
  feat2 fea2ffa [origin/feat2] insert hey feat2
  feat3 6b751be insert mu name to hoge.txt
* feat4 6b751be insert mu name to hoge.txt
  main  67360e7 [origin/main: behind 4] add piyo.txt file

または、以下のように、今いるブランチの情報を確認できる。

$ git status -sb
## feat2...origin/feat2

逆に remote の情報を見ることで、どのブランチが追跡されているか確認することができる。以下では、feat2 と main が tracked になっているのが見える。

$ git remote show origin
* remote origin
  Fetch URL: git@github.com:mochizukikotaro/git-study.git
  Push  URL: git@github.com:mochizukikotaro/git-study.git
  HEAD branch: main
  Remote branches:
    feat2 tracked
    main  tracked
  Local branches configured for 'git pull':
    feat2 merges with remote feat2
    main  merges with remote main
  Local refs configured for 'git push':
    feat2 pushes to feat2 (up to date)
    main  pushes to main  (local out of date)

プルリクを出したときの remote の見え方

まずは、プルリクを出したユーザーから見たとき。feat5 ブランチから push しました。

$ git push
$ git remote show origin
* remote origin
  Fetch URL: git@github.com:mochizukikotaro/git-study.git
  Push  URL: git@github.com:mochizukikotaro/git-study.git
  HEAD branch: main
  Remote branches:
    feat2 tracked
+   feat5 tracked
    main  tracked
  Local branch configured for 'git pull':
    main merges with remote main
  Local refs configured for 'git push':
    feat2 pushes to feat2 (up to date)
+   feat5 pushes to feat5 (up to date)
    main  pushes to main  (up to date)

他ユーザーからの見え方

$ git remote show origin
* remote origin
  Fetch URL: git@github.com:mochizukikotaro/git-study.git
  Push  URL: git@github.com:mochizukikotaro/git-study.git
  HEAD branch: main
  Remote branches:
    feat2 tracked
+   feat5 new (next fetch will store in remotes/origin)
    main  tracked
  Local branches configured for 'git pull':
    feat2 merges with remote feat2
    main  merges with remote main
  Local refs configured for 'git push':
    feat2 pushes to feat2 (up to date)
    main  pushes to main  (local out of date)

ls-remote はどちらからも同じように見えます。

$ git ls-remote origin
375efdafea49de18c971fa5a6e38c9626ef72f67    HEAD
fea2ffa5f90e4c756f6795bc0142d31ad02e992c    refs/heads/feat2
+ ad50b826f784c6fc973650d62600b5815f81ab34  refs/heads/feat5
375efdafea49de18c971fa5a6e38c9626ef72f67    refs/heads/main
75a92a643719a3949e6d2de91ef787b9a7365da3    refs/pull/2/head
6b751be4d4829ef98b4dfb9613b41423bd9cdcfc    refs/pull/3/head
cc0937c22bd7ea3e3bb4bcc88443fdcb2b7fa0c9    refs/pull/4/head
+ ad50b826f784c6fc973650d62600b5815f81ab34  refs/pull/5/head
+ 967839a6c917a33715046be70feae9c8268121b1  refs/pull/5/merge

他人のプルリクを持ってくる

hub コマンド使えばいいのですが。使わずにやろうとすると、ここを読めばいけます。
https://docs.github.com/en/free-pro-team@latest/github/collaborating-with-issues-and-pull-requests/checking-out-pull-requests-locally

たとえば、以下のように5番目のプルリクが出ているとします。良い感じに fetch すれば済みます。

$ git ls-remote origin | grep /5
ad50b826f784c6fc973650d62600b5815f81ab34    refs/pull/5/head
967839a6c917a33715046be70feae9c8268121b1    refs/pull/5/merge

$ git fetch origin pull/5/head:pr_5
$ git switch pr_5

このときに、refs がどうなっているのか見ておきたいです。

 $ la .git/refs/remotes/origin/
 total 16
 drwxr-xr-x  4 mochizuki  staff   128B 12 30 19:14 ./
 drwxr-xr-x  3 mochizuki  staff    96B 12 30 17:08 ../
 -rw-r--r--  1 mochizuki  staff    41B 12 30 19:14 feat2
 -rw-r--r--  1 mochizuki  staff    41B 12 30 19:09 main

 $ la .git/refs/heads/
 total 40
 drwxr-xr-x  7 mochizuki  staff   224B 12 31 15:16 ./
 drwxr-xr-x  5 mochizuki  staff   160B 12 30 17:08 ../
 -rw-r--r--  1 mochizuki  staff    41B 12 30 19:14 feat2
 -rw-r--r--  1 mochizuki  staff    41B 12 31 12:47 feat3
 -rw-r--r--  1 mochizuki  staff    41B 12 31 13:00 feat4
 -rw-r--r--  1 mochizuki  staff    41B 12 30 17:08 main
+ -rw-r--r--  1 mochizuki  staff    41B 12 31 15:16 pr_5

上のように、 fetch origin pull/5/head:pr_5 のようにシンプルに :pr_5 を指定しましたが、 .git/refs/heads/ に入ってきました。git branch ですでに pr_5 が存在しているので、そうですよね。

ハッシュも上でみた refs/pull/5/head と同じです。それはそうですよね。

$ cat .git/refs/heads/pr_5
ad50b826f784c6fc973650d62600b5815f81ab34

別のアプローチとして(ほぼ同じだが)、以下でもよい。

git switch -c new_br
git pull origin pull/5/head

ときどき記事で以下のような方法を見る。(僕はこの方法は使わない)

$ git fetch origin pull/5/head:refs/remotes/pr/pr_5

これは、fetch 先が refs/remotes/pr/pr_5 となっている。こうすると refs/head に入ってこないので、git branch しても pr_5 というブランチは出てこない。

上のようにやった場合は、つづけて以下のようにするらしい。

$ git switch -c new_br pr/pr_5
あるいは↓など
$ git switch -c new_br refs/remotes/pr/pr_5

こうすることで、手元にもってこれるが。これをした場合、git branch -D new_br とブランチを削除しても refs/remotes/pr 配下ファイルは残ってします。これを上手に消す方法は見つけていない。僕としては、あまり大量にローカルに持ってきたくはないので、最初にしめした git fetch origin pull/5/head:pr_5 というやり方が良いように思う。

この辺の仕組みは Git Objects や Git References のドキュメントを読むことでより理解がすすみました。
https://git-scm.com/book/en/v2

tilde ~ と caret ^ の違い

以下を読めば理解できる。

https://stackoverflow.com/questions/2221658/whats-the-difference-between-head-and-head-in-git
https://git-scm.com/book/en/v2/Git-Tools-Revision-Selection

$ git log --oneline --graph
*   1ce9f4b (HEAD -> a) Merge branch 'b' into a
|\
| * 0470c60 (b) b2
| * c8189fa b1
* | 27de526 a3
|/
* 35eee15 a2
* e63c007 a1

上のようなコミットログを自分で作ってみて、あとは rev-parse で調べるとよくわかります。

$ git rev-parse --short @
1ce9f4b

$ git rev-parse --short @^2~2
35eee15

参考

ドキュメント
https://git-scm.com/book/en/v2

1
3
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
1
3