【Git】从入门到精通(三)—— 创建第一个Git仓库

作者:全栈陈序员 系列:《Git版本控制从入门到精通》 适用人群:零基础到入门进阶 阅读时间:约 18 分钟


大家好

前两篇我们打牢了概念地基、装好了 Git 环境。本篇终于要亲手创建第一个 Git 仓库了!

我们会完成一个最完整、最真实的新手体验:

  • 用 git init 把一个普通目录变成 Git 仓库;
  • 深入剖析 .git 目录里到底装了什么;
  • 跑通"创建文件 → add → commit → log → 修改 → 再提交"的完整闭环;
  • 讲清 git init 的常用选项;
  • 把一个已有项目纳入 Git 管理;
  • 讨论 master vs main 的历史与切换;
  • 介绍 README.md 和开源协议的写法与选择。

跟着敲一遍,你就真正"用上 Git"了。


一、两种创建仓库的方式

Git 创建仓库有两种主要方式:

方式 命令 场景
在现有目录初始化 git init 把本地已有项目纳入 Git 管理,或从零开始新建项目
克隆远程仓库 git clone <url> 已有远程仓库(如 GitHub 上的项目),想下载到本地

本篇重点讲 git init,因为它是理解"仓库是怎么来的"的基础。git clone 涉及远程操作,会在第19篇详细讲。


二、git init 详解

2.1 创建项目目录并初始化

我们从一个空目录开始:

复制代码
# 创建项目目录
$ mkdir my-first-repo

# 进入目录
$ cd my-first-repo

# 初始化 Git 仓库
$ git init
Initialized empty Git repository in /Users/chensen/my-first-repo/.git/

输出告诉我们:在当前目录下创建了一个 .git 子目录,仓库已初始化。

2.2 查看目录结构

复制代码
$ ls -la
total 0
drwxr-xr-x   3 chensen  staff   96 Nov  2 10:00 .
drwxr-xr-x  20 chensen  staff  640 Nov  2 10:00 ..
drwxr-xr-x  10 chensen  staff  320 Nov  2 10:00 .git

注意:.git 是隐藏目录 (以点开头),普通 ls 看不到,需要 ls -la。这个目录就是 Git 仓库的"心脏",所有版本数据都存在这里。

2.3 .git 目录结构详解

复制代码
$ ls -la .git
total 64
drwxr-xr-x   10 chensen  staff   320 Nov  2 10:00 .
drwxr-xr-x    3 chensen  staff    96 Nov  2 10:00 ..
-rw-r--r--    1 chensen  staff   138 Nov  2 10:00 HEAD
-rw-r--r--    1 chensen  staff    23 Nov  2 10:00 config
-rw-r--r--    1 chensen  staff   147 Nov  2 10:00 description
drwxr-xr-x    2 chensen  staff    64 Nov  2 10:00 hooks/
-rw-r--r--    1 chensen  staff  4096 Nov  2 10:00 index          # 暂存区文件(首次init后可能还没有)
drwxr-xr-x    2 chensen  staff    64 Nov  2 10:00 info/
drwxr-xr-x    3 chensen  staff   128 Nov  2 10:00 logs/
drwxr-xr-x    4 chensen  staff   128 Nov  2 10:00 objects/
drwxr-xr-x    4 chensen  staff   128 Nov  2 10:00 refs/

逐个说明:

文件/目录 作用
HEAD 指向当前所在分支,内容如 ref: refs/heads/main
config 当前仓库的 local 级配置(仅对本仓库生效)
description 仓库描述(供 GitWeb 使用,一般不用管)
hooks/ 钩子脚本目录(pre-commit、post-commit 等),第27篇详讲
index 暂存区的二进制文件,记录哪些文件将被提交
info/ 全局排除文件(info/exclude,类似 .gitignore 但不提交)
logs/ 引用变更日志(git reflog 用,第24篇详讲)
objects/ 所有 Git 对象的存储(commit、tree、blob),是版本库核心
refs/ 引用(分支、标签)的存储,refs/heads/ 存分支,refs/tags/ 存标签

关键认知:

  1. .git 目录就是仓库本身 。你可以把工作区的文件全删了,只要 .git 还在,所有历史都能恢复。
  2. 千万不要手动改 .git 里的东西(除非你确切知道在做什么),用 Git 命令操作。
  3. .git 不要提交到另一个 Git 仓库(不要嵌套仓库),否则会出问题。

2.4 查看 HEAD 内容

复制代码
$ cat .git/HEAD
ref: refs/heads/main

说明当前在 main 分支(如果你的 Git 默认分支是 main)。如果还没提交过,refs/heads/main 这个文件还不存在,提交后才会创建。

2.5 查看 config 内容

复制代码
$ cat .git/config
[core]
	repositoryformatversion = 0
	filemode = true
	bare = false
	logallrefupdates = true

这是仓库级配置,刚 init 时只有一些默认项。你可以用 git config --local 添加仓库特有配置。


三、第一个完整工作流

现在我们跑通 Git 最核心的闭环:工作区 → 暂存区 → 版本库。

3.1 创建第一个文件

复制代码
# 创建 README.md
$ echo "# My First Repo" > README.md

# 查看文件
$ cat README.md
# My First Repo

此时文件在工作区,但 Git 还不知道它。查看状态:

复制代码
$ git status
On branch main

No commits yet

Untracked files:
  (use "git add <file>..." to include in what will be committed)
	README.md

nothing added to commit but untracked files present (use "git add" to track)

Untracked files 表示 Git 发现了一个新文件 README.md,但还没追踪它。Git 友好地提示你用 git add 把它加入暂存区。

3.2 加入暂存区

复制代码
$ git add README.md

再次查看状态:

复制代码
$ git status
On branch main

No commits yet

Changes to be committed:
  (use "git rm --cached <file>..." to unstage)
	new file:   README.md

文件状态从 Untracked 变成了 Changes to be committed(待提交),说明它已进入暂存区。

3.3 提交到版本库

复制代码
$ git commit -m "初始提交:添加README"
[main (root-commit) 3e92b4a] 初始提交:添加README
 1 file changed, 1 insertion(+)
 create mode 100644 README.md

解读输出:

  • [main (root-commit) 3e92b4a]:在 main 分支创建了根提交 (root-commit,即第一个提交),提交哈希是 3e92b4a(简写,完整是40位);
  • 1 file changed, 1 insertion(+):1个文件变更,1行新增;
  • create mode 100644 README.md:新建了文件 README.md,权限模式 100644。

3.4 查看提交历史

复制代码
$ git log
commit 3e92b4a8e5f1c2d9b7a3f6e8d4c2b1a9f0e7d6c5 (HEAD -> main)
Author: 全栈陈序员 <chensen@example.com>
Date:   Mon Nov 2 10:05:00 2026 +0800

    初始提交:添加README

git log 显示所有提交历史。当前只有一个提交,包含:完整哈希、作者、日期、提交信息。

按 q 退出 log 的分页浏览。

3.5 修改文件再提交

模拟日常开发:修改文件,再提交一次。

复制代码
# 修改 README.md
$ echo "" >> README.md
$ echo "这是一个用于学习 Git 的示例项目。" >> README.md

# 查看内容
$ cat README.md
# My First Repo

这是一个用于学习 Git 的示例项目。

查看状态:

复制代码
$ git status
On branch main
Changes not staged for commit:
  (use "git add <file>..." to update what will be committed)
  (use "git restore <file>..." to discard changes in working directory)
	modified:   README.md

no changes added to commit (use "git add" and/or "git commit -a")

modified 表示已追踪的文件被修改了,但还没暂存。

查看差异:

复制代码
$ git diff
diff --git a/README.md b/README.md
index 6e0c4c5..b3d7e8a 100644
--- a/README.md
+++ b/README.md
@@ -1 +1,3 @@
 # My First Repo
+
+这是一个用于学习 Git 的示例项目。

git diff 显示工作区与暂存区的差异:新增了2行(1空行+1内容行)。

暂存并提交:

复制代码
$ git add README.md
$ git commit -m "完善README说明"
[main d3f1a2b] 完善README说明
 1 file changed, 2 insertions(+)

再次查看历史:

复制代码
$ git log
commit d3f1a2b9c4e5f6a7b8c9d0e1f2a3b4c5d6e7f8a9 (HEAD -> main)
Author: 全栈陈序员 <chensen@example.com>
Date:   Mon Nov 2 10:10:00 2026 +0800

    完善README说明

commit 3e92b4a8e5f1c2d9b7a3f6e8d4c2b1a9f0e7d6c5
Author: 全栈陈序员 <chensen@example.com>
Date:   Mon Nov 2 10:05:00 2026 +0800

    初始提交:添加README

现在有两条提交记录,最新的在上。

3.6 美化日志输出

复制代码
$ git log --oneline
d3f1a2b 完善README说明
3e92b4a 初始提交:添加README

$ git log --oneline --graph --all
* d3f1a2b 完善README说明
* 3e92b4a 初始提交:添加README

--oneline 每个提交一行,--graph 显示分支图,--all 显示所有分支。日常推荐用这个组合,或者用上一篇配的 git lg 别名。


四、git init 的常用选项

4.1 指定初始分支名:-b

复制代码
$ mkdir repo2 && cd repo2
$ git init -b main
Initialized empty Git repository in /Users/chensen/repo2/.git/

-b main 让初始分支直接叫 main,省去后续改名麻烦。需要 Git 2.28+。

4.2 裸仓库:--bare

复制代码
$ mkdir my-project.git && cd my-project.git
$ git init --bare
Initialized empty Git repository in /Users/chensen/my-project.git/

裸仓库没有工作区 ,只有 .git 目录的内容直接放在当前目录。用途是作为远程中央仓库(服务器上的共享仓库),开发者往这里 push/pull。

裸仓库的目录名习惯以 .git 结尾,如 my-project.git。后面讲远程仓库时会用到。

4.3 自定义模板:--template

复制代码
$ git init --template=/path/to/my-template

用自定义模板初始化,模板里的 hooks、配置等会被复制到新仓库的 .git 中。适合企业统一初始化仓库规范。

4.4 分离对象目录:--separate-git-dir

复制代码
$ git init --separate-git-dir=/path/to/external-git-storage

把 .git 的对象存储放到外部目录,工作区只留一个指针文件。适合大仓库或特殊存储需求。


五、将现有项目纳入Git管理

实战场景:你手上已经有一个项目目录,想给它加上版本控制。

复制代码
# 假设已有项目
$ cd ~/projects/legacy-app
$ ls
src/  config/  README  start.sh

# 初始化
$ git init
Reinitialized existing Git repository in /Users/chensen/projects/legacy-app/.git/

# 查看状态:所有文件都是 Untracked
$ git status
On branch main

No commits yet

Untracked files:
  (use "git add <file>..." to include in what will be committed)
	README
	config/
	src/
	start.sh

nothing added to commit but untracked files present (use "git add" to track)

重要:在 add 之前,先创建 .gitignore,避免把编译产物、日志、密钥等不该版本化的东西加进去:

复制代码
# 创建 .gitignore
$ cat > .gitignore << 'EOF'
# 编译产物
*.class
target/
build/

# IDE 文件
.idea/
.vscode/
*.iml

# 日志
*.log
logs/

# 系统文件
.DS_Store
Thumbs.db

# 敏感配置
config/local.properties
.env
EOF

然后分批添加并提交:

复制代码
# 添加所有文件
$ git add .

# 查看将要提交的内容(确认没有误加敏感文件)
$ git status

# 提交
$ git commit -m "chore: 将现有项目纳入Git管理"

铁律 :第一次 git add . 前一定要检查 git status,确认没有密钥、密码、大文件。一旦提交了敏感信息,即使后面删除,历史里仍然有,清除很麻烦(需 git filter-branch 或 BFG)。


六、初始分支名:master vs main

6.1 历史背景

Git 从诞生起,默认初始分支名一直是 master。这个词源自 BitKeeper 的 "master repository"(主仓库),本身并无种族含义。

2020年5月,Black Lives Matter 运动兴起,科技界开始反思术语中的种族敏感词。master / slave 这对术语(主从)被认为有奴隶制暗示。GitHub 在 2020年6月宣布:

  • 新建仓库的默认分支名从 master 改为 main;
  • 旧仓库不强制改,但提供改名工具。

Git 官方从 2.28 起支持配置默认分支名,但为兼容性仍默认 master。GitHub/GitLab 平台默认已改为 main。

6.2 如何修改默认分支名

配置 Git 全局默认分支名(推荐新装环境做):

复制代码
$ git config --global init.defaultBranch main

之后所有 git init 默认创建 main 分支。

已有仓库改名:

复制代码
# 把 master 改名为 main
$ git branch -m master main

# 如果有远程,更新远程的默认分支
$ git push -u origin main

# 删除远程旧分支
$ git push origin --delete master

6.3 该用哪个?

  • 新项目 :用 main,顺应社区约定,避免争议;
  • 老项目 :如果团队没意见,保持 master 也没问题,不必为了改名而改名;
  • 跟随平台 :GitHub/GitLab 新建仓库默认 main,本地保持一致最省心。

本系列统一使用 main。


七、README.md 与 LICENSE

一个规范的仓库,根目录至少要有两个文件:README.md 和 LICENSE。

7.1 README.md 的作用与写法

README 是项目的"门面",是别人(包括未来的你)了解项目的第一入口。GitHub/GitLab 会在仓库主页自动渲染 README.md。

一个好的 README 应包含:

复制代码
# 项目名称

一句话简介:这个项目是做什么的。

## 功能特性

- 特性1
- 特性2
- 特性3

## 快速开始

### 环境要求

- Node.js >= 18
- Python >= 3.10

### 安装

```bash
npm install

运行

复制代码
npm start

使用示例

复制代码
const lib = require('your-lib');
lib.doSomething();

项目结构

复制代码
src/        源代码
docs/       文档
tests/      测试

贡献指南

欢迎提 Issue 和 PR。提交前请阅读 CONTRIBUTING.md。

开源协议

MIT License - 详见 LICENSE

联系方式

作者:全栈陈序员 邮箱:chensen@example.com

复制代码
**写好 README 的原则**:
1. **开头一句话说清是什么**,别让人猜;
2. **快速开始要真能跑通**,步骤清晰、命令准确;
3. **配示例代码**,比千言万语管用;
4. **保持更新**,过时的 README 比没有更糟。

### 7.2 开源协议选择

LICENSE 文件声明项目的开源协议,决定别人能怎么用你的代码。常见协议:

| 协议 | 关键限制 | 适用场景 |
|------|---------|---------|
| **MIT** | 几乎无限制,保留版权声明即可 | 最流行,适合大多数个人/开源项目 |
| **Apache 2.0** | MIT + 显式专利授权 + 修改需声明 | 适合涉及专利的企业级项目(如 Kubernetes) |
| **GPL v3** | 衍生作品必须也开源(传染性) | 适合希望强制开源的软件(如 Linux 内核) |
| **LGPL** | 修改库本身要开源,但可被闭源软件链接 | 适合库/框架 |
| **BSD 2/3-Clause** | 类似 MIT,措辞略有不同 | 学术项目常见 |
| **Mozilla (MPL)** | 修改的文件要开源,可混合闭源 | Firefox 等 |
| **Unlicense / CC0** | 放弃所有权利,完全公有 | 想完全无约束的小工具 |

**MIT 协议示例(LICENSE 文件):**

MIT License

Copyright (c) 2026 全栈陈序员

Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:

The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.

复制代码
**选择建议**:
- 个人项目、想最大化传播:**MIT**;
- 公司项目、有专利考量:**Apache 2.0**;
- 希望衍生品也必须开源:**GPL v3**;
- 不确定:先用 MIT,最宽松最省心。

> GitHub 在新建仓库时可直接选择协议并自动生成 LICENSE 文件。也可用 `choosealicense.com` 网站辅助决策。

---

## 八、常见问题FAQ

**Q1:`git init` 后,目录里除了 `.git` 什么都没有,是不是失败了?**

A:没有失败。`git init` 只创建 `.git` 目录,不会创建任何业务文件。你的工作区文件由你自己创建。

**Q2:能不能在一个仓库里再 `git init`?**

A:可以,会提示 `Reinitialized existing Git repository`,不会丢失已有数据。但不要在仓库里嵌套另一个仓库(子目录再 init),会混乱。需要子仓库请用 `git submodule`(第30篇)。

**Q3:误删了 `.git` 目录怎么办?**

A:`.git` 没了,所有历史就没了,无法恢复(除非有远程备份)。所以 `.git` 极其重要,但**不要把它加到 .gitignore**------它本来就不该被追踪,Git 会自动忽略它。

**Q4:`git init` 创建的仓库和 GitHub 上创建的仓库什么关系?**

A:本地 `git init` 创建的是纯本地仓库,没有远程。GitHub 上创建的是远程仓库。通常流程是:本地 init → 在 GitHub 建空仓库 → `git remote add origin <url>` → `git push -u origin main`。后面会详讲。

**Q5:为什么我 `git init` 后默认分支是 master 而不是 main?**

A:你的 Git 版本 < 2.28,或没配置 `init.defaultBranch`。执行 `git config --global init.defaultBranch main` 即可。

**Q6:能否把一个目录同时作为工作区和裸仓库?**

A:不行。裸仓库(`--bare`)没有工作区,专门用作远程共享仓库。工作区仓库和裸仓库是两种不同形态,不要混用。

**Q7:`git init` 在已有 `.git` 的目录执行会怎样?**

A:安全。Git 检测到已有 `.git`,只更新缺失的子目录和文件,不会覆盖你的提交历史。输出 `Reinitialized existing Git repository`。

---

## 九、最佳实践

1. **先建 `.gitignore` 再 add**:避免误提交编译产物、IDE 文件、密钥。
2. **初始分支用 `main`**:`git config --global init.defaultBranch main`,一次配置终身受益。
3. **第一个提交放 README + .gitignore + LICENSE**:让仓库一开始就规范。
4. **提交信息要有意义**:`初始提交`可以,但 `feat: 初始化项目结构` 更好。后面会讲提交信息规范。
5. **不要把 `.git` 提交到别的仓库**:避免嵌套。
6. **定期 `git status`**:随时知道当前状态,避免意外。
7. **敏感信息绝不提交**:密码、私钥、`.env` 一律进 `.gitignore`。一旦提交,即使删除,历史仍在,需用 BFG/filter-branch 清理,非常麻烦。

---

## 十、小结

本篇我们亲手创建了第一个 Git 仓库,跑通了完整闭环:

1. **两种建仓方式**:`git init`(本地初始化)和 `git clone`(克隆远程)。
2. **`git init`** 在当前目录创建 `.git` 子目录,仓库数据全在其中。
3. **`.git` 目录**包含 `HEAD`(当前分支)、`config`(仓库配置)、`index`(暂存区)、`objects`(对象存储)、`refs`(引用)等,是仓库的核心,勿手动改、勿丢失。
4. **完整工作流**:创建文件(工作区)→ `git add`(暂存区)→ `git commit`(版本库)→ `git log`(查看历史)→ 修改 → 再 add/commit。
5. **`git init` 选项**:`-b main` 指定初始分支,`--bare` 创建裸仓库(用于服务器),`--template` 自定义模板。
6. **现有项目纳入 Git**:init → 先建 `.gitignore` → `git add .` → 检查 status → commit。
7. **master vs main**:2020年后社区改用 `main`,用 `init.defaultBranch main` 配置默认,已有仓库用 `git branch -m master main` 改名。
8. **README.md** 是项目门面,要写清是什么、怎么用、怎么跑;**LICENSE** 声明协议,个人项目用 MIT 最省心。

你现在已经有了一个能提交、能查看历史的本地仓库。但"工作区、暂存区、版本库"这三个区域到底怎么流转?为什么要有暂存区?下一篇我们深入这个**理解 Git 的核心概念**。

> 下一篇:**《Git从入门到精通(四)------ Git三大区域:工作区、暂存区与版本库》**

---

*如果本文对你有帮助,欢迎点赞、收藏、关注。我是全栈陈序员,我们下篇见。*
相关推荐
首席数智官2 小时前
Agent进入产业,腾讯云重新定义AI生态价值
大数据·人工智能
Elasticsearch2 小时前
我们的 agent 技能如何调研、构建和测试完整的 Elastic 集成
elasticsearch
无心水2 小时前
20、大数据架构设计理论与实践 核心考点与学习笔记
大数据·笔记·学习·架构师·系统架构设计师·软考系统架构设计师·架构设计师
chaoyuanl2 小时前
超元力玻璃剧场:裸眼3D、8K高清与悬空栈桥的成熟文旅解决方案
大数据·人工智能·3d·xr·vr
程序员梅雨2 小时前
【从零开始学习数据仓库 | 第三篇】: Flume——数据采集基石
java·大数据·数据仓库·后端·学习·flume
Elasticsearch2 小时前
AgentHack Shanghai|基于阿里云AI搜索 Elasticsearch x Qoder 构建 AI Agent 应用
elasticsearch
全栈陈序员2 小时前
【Git】从入门到精通(四)—— Git三大区域:工作区、暂存区与版本库
大数据·git·elasticsearch
Sayai2 小时前
Elasticsearch ingest pipeline 被禁用之后:性能代价、安全治理与数据入库时间的四种替代方案
大数据·运维·安全·elasticsearch·搜索引擎·性能优化
YIN_尹3 小时前
【git原理与使用】git基本操作及底层原理(一)
java·git·elasticsearch