Skip to content

Latest commit

 

History

History
333 lines (269 loc) · 8.46 KB

chapter2.md

File metadata and controls

333 lines (269 loc) · 8.46 KB

基础知识

Git引用常规放在<repo>/refs/中,可以有任意层次的文件夹结构。 惯例如下:

  • heads
    • 各本地分支
  • remotes
    • 各远程仓库
      • 各远程分支
  • tags
    • 各标签
  • stash - 见第3章git stash
  • replace - 见第1章git replace
  • notes - 见第1章git notes

Git特别引用直接放在<repo>下,一般包括HEAD等。

引用可以分为直接(指向对象的)引用和间接(指向其他引用的)两种。

本章所有命令都不涉及worktree。后续章节会介绍如何利用worktree来操纵对象(Lv3)。

创建直接引用

注:若引用已存在,则会覆盖

  • Lv0 该操作非常危险,因为没有保存操作记录。
mkdir -p ./refs/heads/
echo d4dafde7cd9248ef94c0400983d51122099d312a > ./refs/heads/br1
echo d4dafde7cd9248ef94c0400983d51122099d312a > ./refs/tags/tg1
  • Lv2 该操作会在<repo>/logs/refs/heads/br1中留下操作记录。
git update-ref --no-deref -m 'Reason for update' refs/heads/br1 d4da
git update-ref --no-deref refs/tags/tg1 d4da
  • Lv3 该操作会在<repo>/logs/refs/heads/br1中留下操作记录,原因是branch: Created from ...或者branch: Reset to ...
# 此处必须省略refs/heads/
git branch -f br1 d4da
# 此处必须省略refs/tags/
git tag -f tg1 d4da

查看直接引用

  • Lv0
cat ./refs/heads/br1
# d4dafde7cd9248ef94c0400983d51122099d312a
cat ./refs/tags/tg1
# d4dafde7cd9248ef94c0400983d51122099d312a
  • Lv2
git rev-parse refs/heads/br1
# d4dafde7cd9248ef94c0400983d51122099d312a
git rev-parse refs/tags/tg1
# d4dafde7cd9248ef94c0400983d51122099d312a
  • Lv3
# 此处必须省略refs/heads/
git branch -avl br1
#   br1 d4dafde The commit message May have multiple lines!
# 此处必须省略refs/tags/
git tag -l tg1
# tg1

创建间接引用

  • Lv0
echo 'ref: refs/heads/br1' > ./refs/heads/br2
  • Lv2
git symbolic-ref refs/heads/br2 refs/heads/br1

查看间接引用

  • Lv0
cat ./refs/heads/br2
# ref: refs/heads/br1
  • Lv2 注意以下两者的区别
git symbolic-ref refs/heads/br2
# refs/heads/br1
git rev-parse refs/heads/br2
# d4dafde7cd9248ef94c0400983d51122099d312a
  • Lv3 Lv3命令只能看到解引用后的对象,无法看清楚间接引用本身
# 此处必须省略refs/heads/
git branch -avl br1
#   br1 d4dafde The commit message May have multiple lines!
git branch -avl br2
#   br2 d4dafde The commit message May have multiple lines!

删除引用

  • Lv0
rm ./refs/heads/br1
rm ./refs/heads/br2
rm ./refs/tags/tg1
  • Lv2
# 以下操作会删除refs/heads/br1
git update-ref -d refs/heads/br1
git update-ref -d --no-deref refs/heads/br1
git update-ref -d refs/heads/br2 # 注意--no-deref的作用
# 以下操作会删除refs/heads/br2
git update-ref -d --no-deref refs/heads/br2
(git symbolic-ref refs/heads/br2 refs/heads/br1)
git symbolic-ref --delete refs/heads/br2
  • Lv3
# 此处必须省略refs/heads/
(git update-ref --no-deref refs/heads/br1 d4da)
git branch -D br1
# Deleted branch br1 (was d4dafde).
(git symbolic-ref refs/heads/br2 refs/heads/br1)
git branch -D br2
# Deleted branch br2 (was refs/heads/br1).
# 此处必须省略refs/tags/
(git update-ref --no-deref refs/tags/tg1 d4da)
git tag -d tg1
# Deleted tag 'tg1' (was d4dafde)

关于update-ref的特别备注

--no-deref表明修改引用本身(不论其是什么类型的) 不带--no-deref表明修改引用本身(如果其不存在或者是直接引用)或者引用的引用(如果其是间接引用)

# 以下操作会修改refs/heads/br1
git update-ref refs/heads/br1 efd4
git update-ref --no-deref refs/heads/br1 efd4
git update-ref refs/heads/br2 efd4 # 注意--no-deref的作用
# 以下操作会修改refs/heads/br2,由间接引用变为直接引用
git update-ref --no-deref refs/heads/br2 efd4

查看历史记录

git update-ref --no-deref refs/heads/br1 d4da
git update-ref --no-deref refs/heads/br1 efd4
  • Lv0
cat ./logs/refs/heads/br1
# cat: ./logs/refs/heads/br1: No such file or directory
  • Lv3
git reflog refs/heads/br1

批量查看引用

  • Lv2

git show-ref接类似于git rev-parse的东西,而git for-each-ref接前缀:

(git update-ref --no-deref HEAD d4da)
(git update-ref --no-deref SOME_THING d4da)
(git update-ref --no-deref refs/heads/br1 d4da)
(git symbolic-ref refs/heads/br2 refs/heads/br1)
(git update-ref --no-deref refs/remotes/origin/br3 d4da)
(git update-ref --no-deref refs/tags/tg1 d4da)
git show-ref --head
# d4dafde7cd9248ef94c0400983d51122099d312a HEAD
# d4dafde7cd9248ef94c0400983d51122099d312a refs/heads/br1
# d4dafde7cd9248ef94c0400983d51122099d312a refs/heads/br2
# efd4f82f6151bd20b167794bc57c66bbf82ce7dd refs/heads/master
# e8fc2c133d02a4ffb5c5e9f9f9472410d222cea3 refs/notes/commits
# d4dafde7cd9248ef94c0400983d51122099d312a refs/remotes/origin/br3
# d4dafde7cd9248ef94c0400983d51122099d312a refs/tags/tg1
# 9cb6a0ecbdc1259e0a88fa2d8ac4725195b4964d refs/tags/the-tag
git show-ref
# d4dafde7cd9248ef94c0400983d51122099d312a refs/heads/br1
# d4dafde7cd9248ef94c0400983d51122099d312a refs/heads/br2
# efd4f82f6151bd20b167794bc57c66bbf82ce7dd refs/heads/master
# e8fc2c133d02a4ffb5c5e9f9f9472410d222cea3 refs/notes/commits
# d4dafde7cd9248ef94c0400983d51122099d312a refs/remotes/origin/br3
# d4dafde7cd9248ef94c0400983d51122099d312a refs/tags/tg1
# 9cb6a0ecbdc1259e0a88fa2d8ac4725195b4964d refs/tags/the-tag
git for-each-ref
# d4dafde7cd9248ef94c0400983d51122099d312a commit	refs/heads/br1
# d4dafde7cd9248ef94c0400983d51122099d312a commit	refs/heads/br2
# efd4f82f6151bd20b167794bc57c66bbf82ce7dd commit	refs/heads/master
# e8fc2c133d02a4ffb5c5e9f9f9472410d222cea3 commit	refs/notes/commits
# d4dafde7cd9248ef94c0400983d51122099d312a commit	refs/remotes/origin/br3
# d4dafde7cd9248ef94c0400983d51122099d312a commit	refs/tags/tg1
# 9cb6a0ecbdc1259e0a88fa2d8ac4725195b4964d tag	refs/tags/the-tag
git show-ref br1
# d4dafde7cd9248ef94c0400983d51122099d312a refs/heads/br1
git for-each-ref br1
git show-ref refs/remotes/
git for-each-ref refs/remotes/
# d4dafde7cd9248ef94c0400983d51122099d312a commit	refs/remotes/origin/br3

两个都不能列出$GIT_DIR下的引用!

给定commit-ish,逆向查找引用

  • Lv1
git show-ref | grep $(git rev-parse d4da) | awk '{ print $2; }'
# refs/heads/br1
# refs/heads/br2
# refs/remotes/origin/br3
# refs/tags/tg1
  • Lv2
git name-rev d4da
# d4da tags/tg1
git name-rev --all
# e8fc2c133d02a4ffb5c5e9f9f9472410d222cea3 notes/commits
# cb132dbe2c9e9f8d684452078ba659242d5b9cb7 notes/commits~1
# efd4f82f6151bd20b167794bc57c66bbf82ce7dd master
# d4dafde7cd9248ef94c0400983d51122099d312a tags/tg1
  • Lv3
git describe d4da
# fatal: No annotated tags can describe 'd4dafde7cd9248ef94c0400983d51122099d312a'.
# However, there were unannotated tags: try --tags.
git describe --always d4da
# d4dafde
git describe d4da~
# fatal: Not a valid object name d4da~
git describe --always d4da~
# fatal: Not a valid object name d4da~

添加--dirty可以在结果后面添加-dirty,特别适用于版本号。

总结

  • 添加/修改/删除
    • Lv0
      • 不推荐
    • Lv2
      • git rev-parse <object>
      • git update-ref --no-deref <ref> [-d|<new>] - 修改<ref>
      • git update-ref <ref> [-d|<new>] - 修改<ref>或者其引用的引用
      • git symbolic-ref --delete <ref>
      • git symbolic-ref <from> <to>
    • Lv3
      • git branch -f <branch> <commit-ish> - 只能操纵refs/heads/
      • git branch -D <branch> - 只能操纵refs/heads/
      • git tag -f <tag> <commit-ish> - 只能操纵refs/tags/
      • git tag -d <tag> - 只能操纵refs/tags/
  • 查看历史记录
    • Lv0
      • cat <repo>/logs/<ref>
    • Lv3
      • git reflog
  • 单独查看
    • Lv0
      • cat <repo>/<ref>
    • Lv2
      • git rev-parse <ref> - 可以接多个但是不如git show-ref好用
      • git symbolic-ref <ref>
  • 批量查看
    • Lv2
      • git show-ref [--head] [<ref>...]
      • git for-each-ref [<ref-pattern>...]
    • Lv3
      • git branch -av
      • git branch -avl <branch-pattern>
      • git tag -l <tag-pattern>
  • 给定commit-ish,逆向查找引用
    • Lv2
      • git name-rev [--tags] --all|<commit-ish>
    • Lv3
      • git describe [--all] [--always] [<commit-ish>] - 留空表示HEAD
      • git describe [--all] [--always] --dirty

扩展阅读

git-rev-parse: specifying revisions