Git 仓库:如何用 git init 创建并连接 remote
Git 仓库就是项目文件夹加上隐藏的 .git 目录,其中保存了全部历史、分支和设置。可以用 git init 在项目文件夹中创建仓库,也可以用 git clone 下载现成的仓库。远程仓库通过 git remote add origin 地址 连接。
Git 仓库就是一个由 Git 跟踪修改的项目。它在物理上是普通的项目文件夹,外加一个隐藏的 .git 目录,所有历史——提交、分支、标签和设置——都保存在那里。删除 .git,剩下的只是没有任何版本历史的文件。
仓库由哪些部分组成
使用 Git 时,需要记住三个区域,修改会在它们之间流动:
- 工作目录(working tree):你看到并编辑的文件;
- 暂存区(staging area,即 index):下一次提交的草稿,修改通过
git add进入这里; - 历史:
.git中的提交数据库,修改通过git commit进入这里。
严格来说,仓库本身就是 .git 的内容。工作目录只是 Git 从历史中取出的一份“展开”的版本。
如何用 git init 创建仓库
进入项目文件夹,执行一条命令:
cd ~/projects/my-app
git init
Initialized empty Git repository in /home/user/projects/my-app/.git/
可以在空文件夹中创建仓库,也可以在已经有文件的文件夹中创建。后一种情况不会丢失任何内容:现有文件会变成未跟踪(untracked)状态,直到你用 git add 添加它们。
该命令的几个常用变体:
# 创建文件夹并同时在其中创建仓库
git init my-app
# 指定第一个分支的名称(否则默认为 master 或设置中的值)
git init -b main
# 让 main 成为所有新仓库的默认分支
git config --global init.defaultBranch main
第一次提交
没有任何提交的空仓库几乎没有用处。执行 git init 之后,通常这样操作:
git config --global user.name "Ivan Petrov"
git config --global user.email "ivan@example.com"
git status
git add .
git commit -m "Initial project structure"
用户名和邮箱只需在电脑上设置一次,它们会被写入每一次提交。没有设置的话,Git 会拒绝提交,并要求你先表明身份。
马上添加 .gitignore
在第一次 git add . 之前,先创建 .gitignore,列出不应进入仓库的内容:依赖、构建产物、机密信息、IDE 文件。
node_modules/
dist/
.env
.idea/
.vscode/
*.log
__pycache__/
如果文件已经被提交,.gitignore 并不会把它移除。需要停止跟踪它,同时保留磁盘上的文件:git rm --cached .env,然后提交。
.git 文件夹里有什么
日常工作中不需要进入这个目录,但了解其结构能解答很多疑问:
| 条目 | 保存的内容 |
|---|---|
objects/ | 压缩后的对象:文件内容(blob)、目录结构(tree)、提交 |
refs/heads/ | 分支:内容为最后一次提交哈希的文件 |
refs/tags/ | 标签 |
HEAD | 指向当前分支的指针,例如 ref: refs/heads/main |
config | 该仓库的设置,包括 remote 列表 |
index | 暂存区的状态 |
hooks/ | 在事件(如 pre-commit、pre-push)发生时运行的脚本 |
由此可以得出重要结论:Git 中的分支只是一个包含单个哈希的小文件。因此创建分支是瞬间完成的,而且不占多少空间。
如何确认某个文件夹是仓库
git status
# 或者更精确地
git rev-parse --is-inside-work-tree
如果不在仓库中,会得到 fatal: not a git repository (or any of the parent directories): .git。注意其中的 “parent directories”:Git 会向上逐级查找 .git。如果不小心在用户主目录中执行了 git init,那么整个主目录都会变成仓库——此时需要删除那个 .git 文件夹。
本地仓库与远程仓库
通过 git init 创建的仓库只存在于你的电脑上。要与他人共享代码并保留备份,需要连接一个远程仓库(remote),即服务器上的副本:GitHub、GitLab、Bitbucket,或你自己的 Git 服务器。
从 Git 的角度看,远程仓库并不是“主”仓库:每个副本都是完整的,并且包含全部历史。只有团队的约定才使它成为中心。
git remote:连接远程仓库
remote 是服务器地址的简称。按惯例,主 remote 的名称是 origin。
# 添加 remote
git remote add origin git@github.com:username/my-app.git
# 查看 remote 及其地址
git remote -v
origin git@github.com:username/my-app.git (fetch)
origin git@github.com:username/my-app.git (push)
然后推送分支,并建立与远程分支的关联:
git push -u origin main
git remote 的常用命令
| 命令 | 作用 |
|---|---|
git remote -v | 列出 remote 及其地址 |
git remote add <名称> <url> | 添加新的远程仓库 |
git remote set-url origin <url> | 修改地址,例如从 HTTPS 改为 SSH |
git remote rename origin old | 重命名 remote |
git remote remove old | 删除 remote(不影响服务器本身) |
git remote show origin | 详细信息:分支、跟踪关系、落后情况 |
地址格式
https://github.com/user/repo.git:HTTPS 方式,任何地方都可用,写入时需要令牌;git@github.com:user/repo.git:SSH 方式,需要密钥,配置好之后无需输入密码;/srv/git/repo.git或file:///srv/git/repo.git:本地路径,适合实验。
常见错误
“error: remote origin already exists”。 同名 remote 已经存在。如果要修改地址,使用 git remote set-url origin <url>,而不是再次执行 add。
“failed to push some refs” / “Updates were rejected”。 服务器上有你本地没有的提交,通常是在网站上创建仓库时自动生成的 README。执行 git pull --rebase origin main,然后再次推送。如果两段历史完全无关,Git 会提示“refusing to merge unrelated histories”,此时 git pull 需要加上 --allow-unrelated-histories。更省事的做法是:在网站上创建完全空白的仓库。
“src refspec main does not match any”。 你要推送的分支不存在:要么还没有任何提交,要么分支名为 master。用 git branch 检查。
自己的 Git 服务器:裸仓库(bare)
GitHub 并不是必需的。任何你能通过 SSH 访问的机器都可以作为远程仓库。为此,在服务器上创建一个“裸”(bare)仓库——没有工作目录,只有 .git 的内容:
# 在服务器上
ssh user@server
git init --bare /srv/git/my-app.git
# 在自己的电脑上
git remote add origin user@server:/srv/git/my-app.git
git push -u origin main
要让三个人共同使用这样的服务器,只需给同事 SSH 访问权限,并为仓库文件夹设置一个有写入权限的共享组。如果需要按分支或项目划分权限,这样就不够用了,那时需要完整的 Git 托管服务。
不能在裸仓库中“进去修改文件”——它只用于通过 push 和 fetch 交换数据。所有 Git 托管平台的仓库都是这样工作的。如果需要网页界面、评审和任务管理,可以部署自托管方案,例如 GitLab、Gitea 或 Forgejo。
跟踪分支:本地仓库如何看到服务器
连接 remote 并首次执行 git fetch 或 git push 之后,仓库中会出现形如 origin/main 的远程分支。它们并不是服务器上的分支,而是你上次同步时所见服务器状态的本地快照。只有执行 fetch、pull 和 push 时才会更新。
三个交换命令的区别如下:
| 命令 | 改变的内容 |
|---|---|
git fetch | 更新 origin/*,不改动你的分支和文件 |
git pull | fetch 加上把 origin/main 合并到当前分支 |
git push | 发送你的提交,并更新服务器上的分支 |
查看你的分支比服务器超前或落后多少:
git fetch
git status -sb
## main...origin/main [ahead 2, behind 1]
这表示你有两个服务器上没有的提交,同时服务器上还有一个你没有的提交。在 push 之前,需要先拉取那个提交。
在第一次 push 时加上 -u,即可设置本地分支与远程分支的关联(upstream)。如果忘了,可以单独设置:git branch --set-upstream-to=origin/main。使用 git branch -vv 查看所有关联。
多个仓库:单体仓库还是每个项目一个仓库
新手常问要创建多少个 Git 仓库。一个简单的规则:每个可以独立开发和发布的单元对应一个仓库。练习项目、个人项目和各个独立服务应当分开存放。不要为整个“我的项目”文件夹建一个仓库:历史会混在一起,要单独展示某个项目到作品集也会变得困难。
大公司有时出于统一修改和统一构建的目的,会把所有代码放在一个单体仓库(monorepo)中,但这是需要配套工具的架构决定。新手应该从“一个项目一个仓库”开始,并且不要在一个仓库中直接嵌套另一个仓库,除非使用子模块。
git init 还是 git clone
| 场景 | 命令 |
|---|---|
| 从零开始一个新项目 | git init |
| 已有没有版本控制的代码文件夹 | 在该文件夹中执行 git init |
| 项目已经在 GitHub 或服务器上 | git clone <url> |
| 需要在自己的服务器上建立中心仓库 | git init --bare |
执行 git clone 之后,origin remote 已经配置好,无需手动添加。
分步示例:从文件夹到 GitHub 上的仓库
- 创建项目文件夹,执行
git init -b main。 - 添加
.gitignore和 README。 - 做第一次提交:
git add .,然后git commit -m "Initial commit"。 - 在 GitHub 上创建一个空仓库——不要勾选 README、许可证或 .gitignore。
- 连接它:
git remote add origin <地址>。 - 推送代码:
git push -u origin main。 - 之后按循环工作:修改 →
git add→git commit→git push。
总结
Git 仓库就是你的项目加上包含完整历史的 .git 文件夹。用 git init 创建,用 git remote add origin 和首次 git push -u 建立与服务器的连接。远程仓库可以是 GitHub、GitLab,也可以是你自己的、包含裸仓库的 Git 服务器。创建第一个仓库、理解暂存区以及连接 remote 的实践,在 Git 课程中有讲解。
常见问题
如何删除 Git 仓库,但保留文件?
删除项目根目录下的隐藏文件夹 .git。在 Linux 和 macOS 上执行 rm -rf .git。文件会保留,但全部版本历史都会丢失。
在已经是仓库的文件夹中执行 git init 安全吗?
安全。Git 会提示 Reinitialized existing Git repository,不会改动历史,只会补充缺少的内部文件。
一个仓库可以连接多少个 remote?
任意多个。比如向自己的 fork 推送时用 origin,同步原始项目时用 upstream,开源项目通常这样工作。
仓库的设置保存在哪里?
保存在 .git/config 文件中。用户级的全局设置位于 ~/.gitconfig,通过 git config --global 修改。
裸仓库与普通仓库有什么区别?
裸仓库没有工作目录,只保存 Git 的内部数据。它作为中心仓库部署在服务器上,用于接收 push。