本页内容
如何使用 git init 初始化 Git 仓库
快速回答: 在项目目录中运行 git init,即可创建本地 Git 仓库。它会创建隐藏的 .git/ 目录,但不会暂存文件、创建提交、创建 GitHub 仓库或上传任何内容。
本页采用的默认设置: 下方展示的输出来自使用 Git 默认 SHA-1 对象格式和默认
files引用后端的仓库,因此你会看到.git/objects/和.git/refs/heads/。git init --object-format=sha256和git init --ref-format=reftable会改变这两项细节,但不会改变这里介绍的整体布局。
语法
git init # initialise the current directory
git init <directory> # create the directory, then initialise it
git init --bare <dir> # create a repository with no working tree
git init -b main # set the initial branch name
如何初始化 Git 仓库
对于新项目,先创建文件夹并初始化,然后暂存并提交一个文件:
mkdir my-project
cd my-project
git init -b main
echo "# My project" > README.md
git add README.md
git commit -m "Initial commit"
如果已经有项目,请从项目根目录运行 git init,不要另建文件夹。在支持的 Git 版本中,git init -b main 可以指定初始分支名;直接运行 git init 则使用你配置的默认值。只有先用 git add 暂存文件、再用 git commit 记录提交,Git 才会跟踪这些文件。如果 Git 要求填写作者信息,请参考 git config 指南。之后要发布仓库,可以先用 git remote 添加远程地址,再单独执行 push。
在现有项目文件夹中运行时,git init 会创建或刷新 .git/ 中的仓库元数据,但不会暂存或提交项目文件。git init <directory> 在目标目录不存在时也会创建它;重新初始化仓库可能会刷新元数据或钩子模板。接下来通常先用 git add 暂存文件,再用 git commit 记录第一个快照。
git init 到底做了什么?
从本质上说,计算机的文件系统相对简单:它记录文件名、文件内容、文件大小和目录层级,但并不原生理解变更历史、作者身份或分支路径。
当你在文件夹中运行 git init 时,Git 会在隐藏的 .git/ 目录中创建本地仓库数据库。已有文件不会改变:它们不会被暂存或提交,也不会联系远程服务器。
当你运行 git status 等命令时,Git 会比较工作树与仓库状态。git init 不会启动后台监视器,也不会跟踪文件;请使用 git add 和 git commit 来记录工作。
.git/ 中发生了什么(动手探索)
要理解 Git 的工作方式,你需要查看 .git/ 目录。让我们初始化一个全新的仓库,并检查 Git 内部数据库的骨架。
第 1 步:初始化目录
首先创建新目录并初始化:
下面 shell 输出中的路径、时间戳、所有权、权限和确切消息会因操作系统、Git 版本、用户和配置而异;请将其视为示例输出。
$ mkdir git-init-deepdive && cd git-init-deepdive
$ git init
Initialized empty Git repository in /home/admin/Code/git-init-deepdive/.git/
现在列出新建 .git/ 文件夹的内容:
$ ls -al .git/
total 32
drwxr-xr-x 7 admin admin 4096 Jul 7 10:25 .
drwxr-xr-x 3 admin admin 4096 Jul 7 10:25 ..
-rw-r--r-x 1 admin admin 23 Jul 7 10:25 HEAD
-rw-r--r-x 1 admin admin 92 Jul 7 10:25 config
-rw-r--r-x 1 admin admin 73 Jul 7 10:25 description
drwxr-xr-x 2 admin admin 4096 Jul 7 10:25 hooks
drwxr-xr-x 2 admin admin 4096 Jul 7 10:25 info
drwxr-xr-x 4 admin admin 4096 Jul 7 10:25 objects
drwxr-xr-x 4 admin admin 4096 Jul 7 10:25 refs
下面分析新初始化仓库中每个条目的作用:
1. HEAD(活动指针)
HEAD 文件是一个纯文本文件,用来告诉 Git 当前活动的是哪个分支或提交。读取它的内容:
$ cat .git/HEAD
ref: refs/heads/main
这段输出表明,HEAD 指向 refs/heads/main 引用文件。不过,如果查看仓库,会发现分支文件 refs/heads/main 还不存在!
$ ls -R .git/refs
.git/refs:
heads/ tags/
.git/refs/heads:
# Empty!
这种状态称为未出生分支(Unborn Branch)。Git 会让 HEAD 指向初始分支目标(例如 main),但要等到第一次提交后才会创建分支引用。在本页的 SHA-1 示例中,该引用包含 40 个十六进制字符的对象 ID;SHA-256 仓库使用的 ID 长度不同。
2. config(本地配置设置)
此文件存放仓库级设置,它们会覆盖系统级和全局配置(详情请参阅 git config)。查看初始设置:
$ cat .git/config
[core]
repositoryformatversion = 0
filemode = true
bare = false
logallrefupdates = true
这些核心变量定义了 Git 如何与文件系统交互:
repositoryformatversion = 0:定义仓库数据库格式的版本。如果 Git 遇到高于自身支持范围的仓库版本,就会拒绝读取。filemode = true:告诉 Git 跟踪 POSIX 文件可执行位的变化(例如通过chmod +x将脚本设为可执行)。bare = false:声明这是一个标准工作仓库,磁盘上包含已检出的文件。“裸”仓库只包含 Git 管理目录(通常用于远程托管服务器),此项值为true。logallrefupdates = true:指示 Git 维护 reflog(记录分支顶端和HEAD随时间指向何处的详细历史),数据存放在.git/logs/中。
3. description(旧式 Web 辅助文件)
这是一个纯文本文件,包含占位内容:Unnamed repository; edit this file 'description' to name the repository.。它供 GitWeb(一个旧式基于 Web 的查看器)使用。在现代开发中会忽略此文件,可以安全地删除或保留原样。
4. hooks/(生命周期自动化)
此文件夹包含在 Git 事件发生时执行自动化任务的 shell 脚本模板(例如 pre-commit、commit-msg、pre-push)。初始化时,这些模板会从系统安装的模板目录复制过来。
默认情况下,此目录中的所有脚本都以 .sample 结尾,因此不会执行。要启用某个钩子,请删除 .sample 后缀,并使脚本可执行(chmod +x)。
5. info/exclude(仅本地生效的忽略列表)
此文件用于定义忽略模式,作用类似于 .gitignore。不过,.gitignore 会提交并与团队共享,而 info/exclude 只在本地生效。可以用它忽略特定于本机的文件(例如本地 IDE 配置),而不会影响其他开发者的环境。
6. objects/(对象数据库)
这是仓库的核心存储数据库。它使用内容寻址存储来保存对象,对象分为以下几类:
- Blob:保存文件内容。
- Tree:保存目录层级。
- Commit:保存指向树和父提交的元数据快照。
初始化时,数据库只包含两个空的子目录:info/ 和 pack/(用于 packfile 索引和存储优化)。在第一次提交之前,数据库是空的。
7. refs/(引用)
此目录相当于仓库提交指针的索引。它包含:
refs/heads/:存放本地分支指针。refs/tags/:存放标签(指向历史提交的固定指针)。refs/remotes/:存放用于跟踪远程仓库分支状态的指针(添加远程仓库后创建)。
详细命令选项与高级用法
1. 重新初始化已有仓库
如果在已经是 Git 仓库的目录中运行 git init,会发生什么?
$ git init
Reinitialized existing Git repository in /home/admin/Code/git-init-deepdive/.git/
在已有仓库上运行 git init 是安全的。它不会覆盖提交、分支、索引或配置文件,而是检查目录,在元数据文件被意外删除时修复它们,并从系统模板目录获取更新后的钩子模板。
2. 裸仓库(git init --bare)
普通仓库的已检出项目文件位于 .git/ 目录旁的工作区中。裸仓库没有已检出的工作区:仓库的 Git 目录本身就是顶层目录。裸仓库通常用作共享远程仓库,供协作者推送和克隆。
# Initialize a bare repository
$ git init --bare my-project.git
Initialized empty Git repository in /home/admin/Code/my-project.git/
查看裸仓库的目录结构:
$ ls -F my-project.git
HEAD config description hooks/ info/ objects/ refs/
这里没有 .git/ 子目录,也没有已检出的项目文件;这些条目本身就是仓库。日常编辑时,请把裸仓库克隆成普通工作仓库。git init --bare 只创建一个空仓库,不会复制你现有项目中的提交。如果需要创建包含现有历史的裸仓库副本,请改用 git clone --bare <source> <target>.git。可参阅官方 git init 手册 和 Pro Git 的在服务器上搭建 Git指南。
3. 设置初始分支名称
过去,Git 初始化时默认将主分支命名为 master。为了采用现代命名约定,可以在初始化时指定默认分支名称:
# Initialize a repository with a default branch named "main"
$ git init --initial-branch=main
也可以全局设置默认分支名称,让今后的所有 git init 命令自动使用它(参阅 git config):
$ git config --global init.defaultBranch main
实际场景:设置一个干净的仓库
下面演示如何初始化新项目,并在记录第一次提交前完成标准设置。
第 1 步:创建项目目录并初始化 Git
$ mkdir team-portal && cd team-portal
$ git init --initial-branch=main
Initialized empty Git repository in /home/admin/Code/team-portal/.git/
第 2 步:设置 Git 配置
核对本地用户配置,确保提交对应到你的团队身份:
$ git config --local user.name "Alex Developer"
$ git config --local user.email "alex@portalproject.com"
第 3 步:定义忽略规则
创建 .gitignore 文件,避免跟踪临时文件或系统缓存:
$ echo "node_modules/" > .gitignore
$ echo ".DS_Store" >> .gitignore
$ echo "*.log" >> .gitignore
第 4 步:编写初始代码并记录第一次提交
创建文件、暂存文件并记录提交:
$ echo "<h1>Team Portal</h1>" > index.html
$ git add .
$ git commit -m "chore: initial repository layout"
[main (root-commit) f23c92e] chore: initial repository layout
2 files changed, 4 insertions(+)
create mode 100644 .gitignore
create mode 100644 index.html
现在第一次提交已经记录,查看 .git/refs/heads/main:
$ cat .git/refs/heads/main
f23c92e10db526ab1a9db3f28249a02ce5c144e1
未出生分支状态已经解除。在这个 SHA-1/files-backend 示例中,refs/heads/main 指向上面展示的示例提交 ID;具体对象 ID 会因仓库内容和提交元数据而异。
常见陷阱与错误
1. 意外创建嵌套仓库
错误做法: 在已经由 Git 仓库跟踪的文件夹的子目录中运行 git init。
/my-project/ (.git/ exists)
└── /src/
└── /components/ (runs git init here)
为什么会有问题: 该子目录会成为一个独立仓库。父仓库通常会将它视为未跟踪目录(除非它被忽略),不会自动吸收内部仓库的历史。子模块需要显式配置。
解决方法: 初始化前,先检查当前目录属于哪个仓库:
# This prints the root of the current repository, if there is one.
$ git rev-parse --show-toplevel
如果误创建了嵌套仓库,删除它的 .git/ 目录会将其中的文件变回父工作树中的普通文件,但会永久删除嵌套仓库的历史和元数据。删除前请确认路径准确无误:
$ rm -rf path/to/nested-project/.git
2. 在系统主目录中初始化
错误做法: 不小心在终端默认路径(例如 C:\Users\Username\ 或 /home/username/)运行 git init。
为什么会有问题: Git 会尝试跟踪电脑上的每个文件,包括桌面文件、下载内容、应用程序和系统缓存。这会拖慢终端,并导致提交冲突。
解决方法: 找到并删除主目录中误创建的 .git 文件夹:
# Navigate to home and delete the hidden .git directory
$ cd ~
$ rm -rf .git
(注意: 执行 rm -rf .git 前,务必再次确认当前位于主目录,以免删除有效的项目历史。)
3. 手动编辑数据库对象
错误做法: 试图手动修改、重命名或写入 .git/objects/ 或 .git/refs/ 中的文件来修复仓库问题。
为什么会有问题: Git 的对象数据库依赖精确的加密哈希。即使只修改对象文件中的一个字符,也会破坏哈希,使仓库无法读取。
解决方法: 使用 Git 命令行 API 操作仓库内容,而不是直接编辑 .git/ 中的文件。
命令速查
| 命令 | 作用 | 常见场景 |
|---|---|---|
git init | 初始化标准 Git 仓库 | 在项目根目录运行一次 |
git init --bare | 初始化没有工作目录的仓库 | 远程服务器 / 共享中心 |
git init -b <name> | 指定自定义初始分支名 | 替代旧式的 master 分支命名 |
git init --template=<dir> | 使用自定义钩子模板初始化仓库 | 统一团队钩子 |
rm -rf .git | 取消项目跟踪并删除所有本地历史 | 警告:具有破坏性且不可逆 |
常见问题(大家还问了)
git init 做什么?
git init 会通过创建 .git/ 子目录,将当前目录变成 Git 仓库。该目录保存对象数据库、分支引用和本地配置。它不会创建提交,也不会立即跟踪任何文件,更不会联系服务器。在有内容被记录到历史之前,你仍需使用 git add 和 git commit。
git init 会把我的代码上传到 GitHub 吗?
不会。git init 是一个完全在本机存储上运行的本地命令。它会在你的目录中初始化本地版本数据库,但不会连接互联网或关联外部主机。要将代码上传到 GitHub,必须先在 GitHub 上创建远程仓库,再使用 git remote add 将其关联到本地,并推送提交。
如何撤销 git init?
要移除项目的 Git 跟踪,请删除隐藏的 .git/ 文件夹。这会移除所有提交历史、分支、配置设置和储藏,但磁盘上的工作文件仍会保留,只是不再受到跟踪:
$ rm -rf .git
标准仓库和裸仓库有什么区别?
标准 Git 仓库包含一个与文件工作副本并列的 .git/ 文件夹,因此可以在本地编辑和提交。裸仓库只在根目录中直接包含 Git 数据库文件(没有 .git/ 文件夹),也没有工作目录。裸仓库通常用于远程服务器,以安全地保存推送的提交。
为什么 .git 文件夹默认是隐藏的?
.git/ 目录默认隐藏,是为了避免意外修改、移动或删除其中的内容。所有版本历史都保存在此目录中,因此删除它会删除整个仓库的历史。
检验你的知识
正在加载测验…