git的指针ref和reflog
Git指针ref概念
ref是一种指向一次提交的非直接方式,可以看做是提交哈希(commit hash)的别名,用于表示Git的分支和标签。ref作为普通文件存储于.git/refs目录下:
其中,
heads目录定义了仓库中所有的本地分支,heads目录下的每个文件的文件名对应分支名,文件内容为该分支最后一次提交对应的哈希值。在main分支上进行一次提交,Git实际就是修改refs/heads/main的内容,新建一个分支,实际就是将提交哈希写入一个新文件中。tags目录与heads作用类似,不同之处在于保存git tags而非分支信息。-
remote目录存放着所有远程仓库,每个远程仓库对应一个子目录,该子目录下又存放着获取(fetch)到存储库中的所有远程分支:
因此,在一些需要指定具体提交哈希的场景中,除了指定哈希值之外,还可以直接指定ref,比如git show .git/refs/heads/HEAD。
对于大型仓库,Git会周期性执行垃圾回收,以减少不必要的对象并压缩ref,以提高性能。当然,也可以使用git gc手动执行垃圾回收,该命令会将上述分支和tag对应的ref文件压缩到.git目录下的packed-refs文件中。
特殊ref的指向
HEAD:最近检出(check out)的提交(commit)或分支。FETCH_HEAD:最近从远程仓库中获取(fetch)的分支。ORIG_HEAD:在较大变更前HEAD的备份。MERGE_HEAD:使用git merge合并到当前分支的提交(commit)。CHERRY_PICK_HEAD:使用git cherry-pick摘取部分内容到当前分支的提交(commit)。
远程仓库的默认名origin
origin是远程仓库链接的别名,origin对应的链接太长,使用起来较为麻烦。因此origin的本质是指向远程仓库的一个指针名,而master/main则属于仓库中的一个部分。
可以通过git remote -v或者仓库配置文件.git/config查看远程仓库的具体链接,可以通过git remote add <remote-repo-name> <url>添加新的远程仓库别名<remote-repo-name>和对应的链接<url>。
git push默认创建origin和main,因此推送时可以省略,完整形式应是git push origin main。如果希望Git记录推送到远程分支的默认值,可以加上-u参数,也就是git push -u <remote> <local>,这样当下次还想要继续推送到该远程分支时,推送命令就可以简写为git push。
远程分支和本地分支的映射refspecs
refspecs将本地仓库的分支映射到远程仓库的分支,以便使用本地Git命令管理远程分支,并配置一些特殊的git push和git fetch行为。
refspecs定义如下:
其中,
+表示强制远程仓库执行非快进更新(non-fast-forward update)。<src>表示本地仓库的源分支。<dst>表示远程仓库的目标分支。
refspecs可以与git push一起使用,为远程分支指定不同的名称。比如以下命令将main本地分支推送到origin远程仓库,但使用qa-main作为远程仓库origin中对应分支的名称:
同样可以利用refspecs删除远程分支,类似地,此时将本地分支的名称置为空即可:
通过修改Git的配置文件.git/config,可以使用refspecs修改git fetch的默认行为。默认情况下,git fetch获取远程仓库的所有分支,因此.git/config文件相关内容如下:
上述配置要求Git下载远程仓库origin的所有分支,如果只需要main分支,可以更新相关内容如下:
类似地,可以修改git push的默认行为。比如,如果想一直将本地分支main推送到远程仓库origin的qa-main,可以更新相关内容如下:
相对ref
HEAD~1:等同于HEAD~或HEAD^1或HEAD^,后退至HEAD之前的提交。HEAD^2:后退至当前分支的第二个父提交。HEAD~1^2:后退至HEAD之前的提交,再后退到当前分支的第二个父提交上,如果HEAD没有合并分支,则非法。HEAD@{2}:指向git reflog记录的整体操作的第三条操作(git reflog记录的整体操作从0开始)。
reflog
reflog记录了在当前仓库上进行的所有Git操作,可以通过git reflog查看该Git日志,比如:
其中,HEAD{<num>}用于标识在reflog中的提交(commit),可以配合其他命令对指定提交(commit)进行操作,比如删除最后一次提交时,可以执行git reset --soft HEAD@{1}。
Refs and the Reflog Git 里面的 origin 到底代表啥意思? git push 的 -u 参数含义 这才是真正的GIT——GIT实用技巧 这才是真正的GIT——分支合并