Git,是目前世界上,最流行、最强大的分布式版本控制系统。
对于程序员来说,Git,已经成为了必备技能。无论是个人开发,还是团队协作,Git,都能帮助我们,更好地管理代码版本,追踪代码变更,进行团队协作。可以说,不会用Git的程序员,不是一个合格的程序员。
我自己,从大学开始接触Git,到现在工作多年,每天都在使用Git。从最初的只会add、commit、push,到后来能够熟练使用分支、合并、变基、撤销、回滚等高级功能,一路走来,踩了不少坑,也总结了不少经验。我见过太多的开发者,因为不会用Git,而导致代码丢失、版本混乱、协作冲突等问题。其实,只要掌握了Git的基本原理和常用命令,这些问题,都能避免。
2015年,Git,已经成为了版本控制系统的绝对主流。GitHub,作为最大的Git托管平台,已经拥有了数百万的开发者和数千万的代码仓库。无论是开源项目,还是商业项目,大多数都在使用Git进行版本控制。SVN、CVS等传统的集中式版本控制系统,已经逐渐被淘汰。
今天,分享Git版本控制,从基本原理到常用命令,从分支策略到团队协作,从常见问题到最佳实践,全方位讲解Git的使用方法和技巧,帮你掌握这个程序员的协作利器。
什么是版本控制
在讲Git之前,先简单介绍一下,什么是版本控制。
版本控制(Version Control),是一种记录文件内容变化,以便将来查阅特定版本修订情况的系统。
简单来说,版本控制,就是帮你管理文件的不同版本。你可以随时,把文件恢复到之前的某个版本;可以查看,文件在什么时候,被谁修改了,修改了什么内容;可以和其他人,协作开发同一个项目,而不会互相覆盖对方的代码。
没有版本控制的时候,开发者,通常用"复制文件夹"的方式,来管理版本。比如,把项目文件夹,复制一份,命名为"项目_20151105",然后在新的文件夹里修改。这种方式,非常原始,也非常容易出问题:
- 版本多了,不知道哪个版本,是最新的
- 想找某个历史版本,要一个个文件夹打开看
- 两个人同时修改同一个文件,很容易互相覆盖
- 想比较两个版本的差异,非常麻烦
- 占用大量磁盘空间
而版本控制系统,就是为了解决这些问题而诞生的。它,能自动记录文件的每次变更,能方便地查看和恢复历史版本,能支持多人协作开发,能节省磁盘空间。
版本控制系统,主要分为两类:
- 集中式版本控制系统:如SVN、CVS。所有的版本数据,都存储在中央服务器上。开发者,从中央服务器,检出代码,修改后,提交回中央服务器。缺点是,必须联网才能工作;中央服务器挂了,所有人都无法工作;中央服务器的数据丢了,所有版本都丢了。
- 分布式版本控制系统:如Git、Mercurial。每个开发者的电脑上,都有一个完整的版本库,包含所有的历史版本。开发者,可以在本地,提交代码,查看历史,创建分支,不需要联网。只有在需要和其他人协作时,才需要联网,推送或拉取代码。优点是,离线也能工作;安全性高,每个人的电脑上,都有完整的备份;分支和合并,非常强大和灵活。
Git,就是分布式版本控制系统的代表,也是目前最流行、最强大的版本控制系统。
Git的基本原理
要学好Git,首先要理解Git的基本原理。Git的原理,和其他版本控制系统,有很大的不同。
1. Git记录的是快照,不是差异
很多版本控制系统(如SVN),记录的是文件的差异。也就是说,每次提交,只记录文件相对于上一个版本,修改了哪些内容。
而Git,记录的是文件的快照。也就是说,每次提交,Git会把当时所有文件的状态,拍一张"快照",保存下来。如果某个文件,没有修改,Git不会重复保存,而是保留一个链接,指向之前保存的相同文件。
这种方式,让Git的分支和合并,非常高效。因为,创建一个分支,本质上,就是创建一个指向某个快照的指针,几乎不占用任何空间。
2. Git的三个区域
Git,有三个重要的区域:工作区、暂存区、版本库。
- 工作区(Working Directory):就是你在电脑里,能看到的项目目录。你在工作区里,修改、添加、删除文件。
- 暂存区(Staging Area / Index):是一个文件,保存了下次将提交的文件列表信息。一般,在Git仓库目录中,叫
.git/index。你用git add命令,把工作区的修改,添加到暂存区。 - 版本库(Repository):就是
.git目录,里面保存了所有的版本数据。你用git commit命令,把暂存区的内容,提交到版本库,形成一个新的版本。
这三个区域的关系,是Git最核心的概念。理解了这三个区域,就理解了Git的基本工作流程。
3. Git的工作流程
Git的基本工作流程,是这样的:
- 在工作区,修改文件
- 用
git add,把修改的文件,添加到暂存区 - 用
git commit,把暂存区的内容,提交到版本库,形成一个新的版本
就是这么简单。这三个步骤,就是Git最基本的操作。
4. Git的对象
Git,内部有四种对象:
- blob对象:存储文件的内容。每个文件的内容,对应一个blob对象。
- tree对象:存储目录结构。记录了目录下,有哪些文件和子目录,以及它们对应的blob对象或tree对象的哈希值。
- commit对象:存储一次提交的信息。包括提交的作者、时间、提交信息,以及对应的tree对象的哈希值,还有父提交的哈希值。
- tag对象:存储一个标签,指向某个commit对象。
Git,用SHA-1哈希值,来标识每个对象。每个对象的内容不同,哈希值就不同。Git,通过这些对象和哈希值,构建了整个版本库。
5. Git的引用
Git的引用(refs),是指向某个commit对象的指针。主要有:
- 分支(branch):指向某个commit对象的指针。你在某个分支上提交,分支指针,会自动向前移动。
- 标签(tag):指向某个commit对象的指针,通常不会移动。用于标记重要的版本,如发布版本。
- HEAD:指向当前所在分支的指针。你切换分支,HEAD就指向新的分支。
理解了Git的对象和引用,就理解了Git的内部原理。
Git基本命令
1. 配置Git
在使用Git之前,需要先配置一下你的用户名和邮箱,因为每次Git提交,都会使用这些信息。
# 配置用户名
git config --global user.name "Your Name"
# 配置邮箱
git config --global user.email "your@email.com"
# 配置默认编辑器
git config --global core.editor vim
# 配置换行符处理(Windows)
git config --global core.autocrlf true
# 配置换行符处理(Mac/Linux)
git config --global core.autocrlf input
# 查看配置
git config --list
# 查看某项配置
git config user.name2. 创建仓库
有两种方式,创建Git仓库:
# 方式一:在当前目录,初始化一个新的Git仓库
git init
# 方式二:克隆一个已有的远程仓库
git clone https://github.com/user/repo.git
# 克隆时,指定本地目录名
git clone https://github.com/user/repo.git myrepo3. 查看状态
# 查看工作区和暂存区的状态
git status
# 简洁模式
git status -sgit status,是最常用的命令之一。它会告诉你,哪些文件被修改了,哪些文件在暂存区,哪些文件没有被跟踪。
4. 添加文件到暂存区
# 添加指定文件到暂存区
git add filename
# 添加所有修改和新增的文件到暂存区
git add .
# 添加所有修改、新增、删除的文件到暂存区
git add -A
# 交互式添加
git add -i
# 补丁模式,逐块选择要添加的内容
git add -p5. 提交
# 提交暂存区的内容,打开编辑器输入提交信息
git commit
# 提交,并直接指定提交信息
git commit -m "提交信息"
# 提交所有已跟踪的文件的修改(不需要先git add)
git commit -a -m "提交信息"
# 修改上一次提交
git commit --amend
# 修改上一次提交的提交信息
git commit --amend -m "新的提交信息"6. 查看历史
# 查看提交历史
git log
# 简洁显示,每个提交一行
git log --oneline
# 显示最近N次提交
git log -n 5
# 显示提交的差异
git log -p
# 显示提交的统计信息
git log --stat
# 图形化显示分支合并历史
git log --graph --oneline --all
# 按作者筛选
git log --author="username"
# 按时间筛选
git log --since="2015-01-01" --until="2015-12-31"
# 查看某个文件的提交历史
git log filename
# 查看提交历史,包括被重命名的文件
git log --follow filename7. 查看差异
# 查看工作区和暂存区的差异
git diff
# 查看暂存区和版本库的差异
git diff --cached
# 或
git diff --staged
# 查看工作区和版本库的差异
git diff HEAD
# 查看两个提交之间的差异
git diff commit1 commit2
# 查看两个分支之间的差异
git diff branch1 branch2
# 查看某个文件的差异
git diff filename
# 统计差异的行数
git diff --stat8. 撤销操作
# 撤销工作区的修改(恢复到暂存区的状态)
git checkout -- filename
# 或(Git 2.23+)
git restore filename
# 撤销暂存区的添加(把暂存区的文件,放回工作区)
git reset HEAD filename
# 或(Git 2.23+)
git restore --staged filename
# 撤销工作区和暂存区的修改(恢复到最近一次提交的状态)
git checkout HEAD -- filename
# 或
git restore --source=HEAD --staged --worktree filename
# 撤销最近一次提交(保留修改在工作区)
git reset --soft HEAD~1
# 撤销最近一次提交(保留修改在暂存区)
git reset --mixed HEAD~1
# 或直接
git reset HEAD~1
# 撤销最近一次提交(丢弃修改,危险!)
git reset --hard HEAD~1
# 撤销到某个提交(丢弃之后的所有提交,危险!)
git reset --hard commit_id注意:git reset --hard,会丢弃工作区和暂存区的修改,非常危险!使用前,一定要确认,不需要那些修改了。
9. 删除和移动文件
# 删除文件,并把删除操作添加到暂存区
git rm filename
# 删除文件,但保留在工作区(只从Git中移除跟踪)
git rm --cached filename
# 重命名/移动文件,并把操作添加到暂存区
git mv oldname newname
# 这相当于:
# mv oldname newname
# git rm oldname
# git add newname10. 忽略文件
有些文件,不需要纳入Git的版本控制,如编译产物、日志文件、配置文件、依赖库目录等。可以创建一个.gitignore文件,来指定要忽略的文件。
.gitignore文件的格式:
# 注释
# 忽略所有的.log文件
*.log
# 忽略node_modules目录
node_modules/
# 忽略根目录下的dist目录
/dist
# 忽略所有目录下的tmp目录
tmp/
# 忽略所有的.o和.a文件
*.[oa]
# 不忽略(取反)某个文件,即使前面规则忽略了它
!important.log
# 忽略doc目录下的所有txt文件,但不包括子目录
doc/*.txt
# 忽略doc目录下所有的pdf文件,包括子目录
doc/**/*.pdfGitHub,提供了一个常用的.gitignore模板库,可以根据项目类型,选择合适的模板:https://github.com/github/gitignore
分支管理
分支,是Git最强大的功能之一。分支,让你可以,在不影响主线的情况下,开发新功能、修复bug、做实验。
1. 查看分支
# 查看本地分支
git branch
# 查看所有分支(包括远程分支)
git branch -a
# 查看远程分支
git branch -r
# 查看分支,以及每个分支最新的提交
git branch -v
# 查看已经合并到当前分支的分支
git branch --merged
# 查看还没有合并到当前分支的分支
git branch --no-merged2. 创建和切换分支
# 创建分支
git branch branchname
# 切换分支
git checkout branchname
# 或(Git 2.23+)
git switch branchname
# 创建并切换到新分支
git checkout -b branchname
# 或
git switch -c branchname
# 基于某个提交,创建分支
git checkout -b branchname commit_id
# 基于某个远程分支,创建本地分支
git checkout -b branchname origin/branchname3. 合并分支
# 把指定分支,合并到当前分支
git merge branchname
# 合并时,禁用快进(fast-forward),生成一个合并提交
git merge --no-ff branchname
# 合并时,只快进(如果不能快进,就失败)
git merge --ff-only branchname
# 合并时,遇到冲突,中止合并
git merge --abort
# 合并时,保留合并的提交信息
git merge --no-edit branchname4. 变基(rebase)
变基,是另一种合并分支的方式。它,会把当前分支的提交,"重新播放"到目标分支上,让提交历史,变成一条直线,更加整洁。
# 把当前分支,变基到目标分支
git rebase target_branch
# 交互式变基,可以修改、合并、删除、重新排序提交
git rebase -i target_branch
# 变基时,遇到冲突,解决冲突后,继续变基
git rebase --continue
# 变基时,遇到冲突,跳过当前提交
git rebase --skip
# 中止变基,恢复到变基前的状态
git rebase --abort注意:变基,会修改提交历史。如果,你的分支,已经推送到了远程仓库,并且,有其他人基于这个分支开发,就不要使用变基,否则,会给其他人带来麻烦。变基,只适合在本地分支,或者,只有你一个人使用的分支上使用。
5. 删除分支
# 删除本地分支(已经合并的)
git branch -d branchname
# 强制删除本地分支(不管有没有合并)
git branch -D branchname
# 删除远程分支
git push origin --delete branchname
# 或
git push origin :branchname6. 分支命名规范
良好的分支命名,能让团队协作,更加顺畅。常见的分支命名规范:
master/main:主分支,稳定版本,随时可以发布develop:开发分支,集成所有开发中的功能feature/xxx:功能分支,开发新功能bugfix/xxx:bug修复分支,修复bughotfix/xxx:紧急修复分支,修复线上紧急bugrelease/xxx:发布分支,准备发布新版本experiment/xxx:实验分支,做技术实验
远程仓库
远程仓库,是托管在网络上的项目版本库,如GitHub、GitLab、Bitbucket、Gitee等。通过远程仓库,你可以和其他人,协作开发。
1. 查看远程仓库
# 查看远程仓库
git remote
# 查看远程仓库,以及对应的URL
git remote -v
# 查看远程仓库的详细信息
git remote show origin2. 添加远程仓库
# 添加远程仓库
git remote add origin https://github.com/user/repo.git
# 修改远程仓库的URL
git remote set-url origin https://github.com/user/newrepo.git
# 重命名远程仓库
git remote rename oldname newname
# 删除远程仓库
git remote remove remotename3. 抓取和拉取
# 从远程仓库,抓取所有分支的更新(不合并)
git fetch
# 从指定远程仓库,抓取更新
git fetch origin
# 从远程仓库,拉取更新(抓取+合并)
git pull
# 从指定远程仓库和分支,拉取更新
git pull origin branchname
# 拉取时,使用变基(而不是合并)
git pull --rebase
# 拉取所有远程分支
git pull --all4. 推送
# 推送当前分支,到远程仓库
git push
# 推送指定分支,到远程仓库
git push origin branchname
# 第一次推送时,设置上游分支(以后可以直接git push)
git push -u origin branchname
# 或
git push --set-upstream origin branchname
# 推送所有分支
git push --all
# 推送标签
git push origin tagname
# 推送所有标签
git push --tags
# 强制推送(危险!会覆盖远程仓库的历史)
git push --force
# 更安全的强制推送(如果远程仓库,在你上次拉取后,有新的提交,就拒绝推送)
git push --force-with-lease注意:git push --force,会覆盖远程仓库的历史,非常危险!如果,有其他人,基于远程仓库的分支开发,强制推送,会给其他人带来麻烦。除非,你确定,只有你一个人使用这个分支,否则,不要使用强制推送。
5. 远程分支操作
# 查看远程分支
git branch -r
# 创建本地分支,跟踪远程分支
git checkout -b localname origin/remotename
# 设置当前分支,跟踪指定远程分支
git branch -u origin/remotename
# 查看分支的跟踪关系
git branch -vv
# 删除远程分支
git push origin --delete branchname
# 清理远程仓库已经删除的分支引用
git remote prune origin标签管理
标签,用于标记项目历史中的某个重要节点,通常是发布版本(如v1.0.0)。
1. 查看标签
# 查看所有标签
git tag
# 按模式筛选标签
git tag -l "v1.*"
# 查看标签的详细信息
git show v1.0.02. 创建标签
# 创建轻量标签(只是一个指向提交的指针)
git tag v1.0.0
# 创建附注标签(包含标签名、邮箱、日期、标签信息,推荐)
git tag -a v1.0.0 -m "版本1.0.0发布"
# 基于某个提交,创建标签
git tag -a v1.0.0 commit_id -m "版本1.0.0发布"3. 推送标签
# 推送指定标签,到远程仓库
git push origin v1.0.0
# 推送所有标签
git push --tags4. 删除标签
# 删除本地标签
git tag -d v1.0.0
# 删除远程标签
git push origin --delete v1.0.0
# 或
git push origin :refs/tags/v1.0.0常见工作流
1. Git Flow
Git Flow,是一种比较经典的分支管理工作流。它,定义了五种分支:
master:主分支,存储正式发布的版本develop:开发分支,集成所有开发中的功能feature/*:功能分支,从develop分支创建,开发完成后,合并回developrelease/*:发布分支,从develop分支创建,准备发布新版本,发布后,合并到master和develophotfix/*:紧急修复分支,从master分支创建,修复线上紧急bug,修复后,合并到master和develop
Git Flow,适合有明确版本发布周期的项目。但它,比较复杂,对于持续交付的项目,可能不太适合。
2. GitHub Flow
GitHub Flow,是一种更简单、更轻量的工作流。它,只有两种分支:
master:主分支,随时可以部署feature/*:功能分支,从master分支创建,开发完成后,通过Pull Request,合并回master
GitHub Flow,适合持续部署、持续交付的项目。它,简单、灵活,是目前最流行的工作流之一。
3. GitLab Flow
GitLab Flow,是GitLab提出的工作流,结合了Git Flow和GitHub Flow的优点。它,在GitHub Flow的基础上,增加了环境分支(如pre-production、production),来管理不同环境的部署。
4. 个人开发工作流
对于个人开发,工作流,可以更简单:
- 在master分支,保持稳定
- 开发新功能时,创建feature分支
- 在feature分支,开发和提交
- 开发完成后,合并回master
- 推送master到远程仓库
常见问题和解决方法
1. 合并冲突
当两个人,同时修改了同一个文件的同一部分,合并时,就会产生冲突。
解决方法:
- 用
git status,查看哪些文件有冲突 - 打开有冲突的文件,找到冲突标记(
<<<<<<<、=======、>>>>>>>) - 手动修改文件,解决冲突,删除冲突标记
- 用
git add,把修改后的文件,添加到暂存区 - 用
git commit,完成合并
2. 提交了错误的内容
如果,你刚提交了错误的内容,还没有推送到远程仓库:
# 修改上一次提交(可以修改提交信息,或者添加遗漏的文件)
git commit --amend
# 或者,撤销上一次提交,保留修改在工作区
git reset --soft HEAD~1
# 然后,重新修改和提交如果,已经推送到了远程仓库,不要使用git reset,而应该使用git revert,创建一个新的提交,来撤销之前的提交:
# 撤销指定提交
git revert commit_id
# 撤销最近一次提交
git revert HEAD3. 不小心add了不该add的文件
# 把指定文件,从暂存区移除(保留在工作区)
git reset HEAD filename
# 或者(Git 2.23+)
git restore --staged filename4. 不小心删除了文件
# 恢复工作区中,被误删的文件(恢复到暂存区的状态)
git checkout -- filename
# 或者(Git 2.23+)
git restore filename
# 如果,已经提交了删除,恢复到某个提交的版本
git checkout commit_id -- filename5. 想查看某个历史版本的文件
# 查看某个提交的文件内容
git show commit_id:filename
# 把某个提交的文件,恢复到工作区
git checkout commit_id -- filename6. 想撤销所有本地修改,恢复到远程仓库的状态
# 抓取远程仓库的最新内容
git fetch origin
# 强制重置本地分支,到远程分支的状态(危险!会丢弃所有本地修改)
git reset --hard origin/branchname7. 提交信息写错了
# 修改上一次提交的提交信息
git commit --amend -m "新的提交信息"
# 如果,已经推送到远程仓库,需要强制推送(谨慎!)
git push --force-with-lease8. 想把一个分支的某个提交,应用到另一个分支
# 切换到目标分支
git checkout target_branch
# 把指定提交,应用到当前分支
git cherry-pick commit_id
# 应用多个提交
git cherry-pick commit1 commit2 commit3
# 应用一个范围的提交
git cherry-pick commit1..commit2Git最佳实践
- 频繁提交,每次提交,只做一件事:不要攒一大堆修改,才提交一次。每次提交,应该只包含一个逻辑上的修改,这样,历史更清晰,也更容易回滚。
- 写好提交信息:提交信息,应该简洁明了,说明这次提交,做了什么。推荐的格式:第一行,简短描述(不超过50字符);空一行;详细描述(可选)。
- 使用分支:不要直接在master分支上开发。开发新功能、修复bug,都应该创建单独的分支。
- 定期拉取远程更新:在开始工作前,先
git pull,拉取远程仓库的最新更新,避免冲突。
- 提交前,先检查修改:提交前,用
git diff,检查一下自己的修改,确保没有提交错误的内容(如调试代码、密码、密钥等)。
- 不要提交敏感信息:不要把密码、密钥、配置文件等敏感信息,提交到Git仓库。可以使用
.gitignore,忽略这些文件,或者使用环境变量。
- 不要提交大文件和编译产物:不要把大文件(如视频、安装包)、编译产物(如node_modules、dist、bin)、日志文件等,提交到Git仓库。使用
.gitignore,忽略这些文件。
- 使用.gitignore:在项目开始时,就创建好
.gitignore文件,忽略不需要版本控制的文件。
- 变基 vs 合并:本地分支,或者只有你一个人使用的分支,可以使用变基,让历史更整洁;共享分支,使用合并,不要修改历史。
- 推送前,先测试:推送代码到远程仓库前,先在本地测试,确保代码能正常运行,不要把有问题的代码,推上去。
- 使用Pull Request / Merge Request:团队协作时,通过Pull Request(GitHub)或Merge Request(GitLab),来合并代码。这样,可以进行代码审查,讨论修改,确保代码质量。
- 定期清理分支:合并后的分支,及时删除,保持分支列表整洁。
学习资源
推荐书籍
- 《Pro Git》:Git官方书籍,深入浅出,非常适合学习Git。有中文版,免费在线阅读:https://git-scm.com/book/zh/v2
- 《Git权威指南》:国内作者写的Git书籍,非常详细,适合深入学习。
在线教程
- Git官方文档:https://git-scm.com/doc
- GitHub Guides:https://guides.github.com/
- 廖雪峰的Git教程:https://www.liaoxuefeng.com/wiki/896043488029600
- 菜鸟教程Git教程:https://www.runoob.com/git/git-tutorial.html
交互式学习
- Learn Git Branching:https://learngitbranching.js.org/ ,通过可视化的方式,交互式学习Git分支,非常有趣,也非常有效。
- Git Immersion:https://gitimmersion.com/ ,通过实际操作,学习Git。
总结
Git版本控制要点:
- 什么是版本控制:记录文件内容变化以便查阅特定版本的系统,解决复制文件夹管理版本的原始方式的问题(版本混乱、查找困难、协作冲突、占用空间)。分为集中式(SVN/CVS,所有版本数据在中央服务器,必须联网,服务器挂了所有人无法工作,数据丢了所有版本丢了)和分布式(Git/Mercurial,每个开发者电脑都有完整版本库,离线能工作,安全性高,分支合并强大灵活)。
- Git基本原理:记录快照不是差异(每次提交保存所有文件状态快照,未修改文件保留链接指向之前相同文件,让分支合并非常高效);三个区域(工作区Working Directory是电脑里能看到的项目目录,暂存区Staging Area/Index是.git/index保存下次提交的文件列表,版本库Repository是.git目录保存所有版本数据);工作流程(工作区修改文件→git add添加到暂存区→git commit提交到版本库形成新版本);四种对象(blob存储文件内容,tree存储目录结构,commit存储提交信息作者时间提交信息tree哈希父提交哈希,tag指向某个commit),用SHA-1哈希值标识每个对象;引用(branch分支指向commit的指针提交时自动前移,tag标签指向commit通常不移动用于标记重要版本,HEAD指向当前所在分支的指针)。
- 基本命令:配置(git config --global user.name/user.email/core.editor/core.autocrlf,git config --list查看);创建仓库(git init初始化,git clone克隆);查看状态(git status,-s简洁模式);添加到暂存区(git add filename,git add .所有修改新增,git add -A所有修改新增删除,-i交互式,-p补丁模式逐块选择);提交(git commit,-m指定信息,-a提交所有已跟踪文件修改不需先add,--amend修改上一次提交);查看历史(git log,--oneline简洁一行,-n最近N次,-p显示差异,--stat统计信息,--graph --oneline --all图形化分支合并,--author按作者,--since/--until按时间,filename某个文件,--follow包括被重命名文件);查看差异(git diff工作区和暂存区,--cached/--staged暂存区和版本库,HEAD工作区和版本库,commit1 commit2两个提交,branch1 branch2两个分支,filename某个文件,--stat统计行数);撤销操作(git checkout -- filename/ git restore filename撤销工作区修改恢复到暂存区,git reset HEAD filename/ git restore --staged filename撤销暂存区添加放回工作区,git checkout HEAD -- filename/ git restore --source=HEAD --staged --worktree filename撤销工作区和暂存区恢复到最近提交,git reset --soft HEAD~1撤销最近提交保留修改在工作区,git reset --mixed HEAD~1/ git reset HEAD~1撤销最近提交保留修改在暂存区,git reset --hard HEAD~1撤销最近提交丢弃修改危险,git reset --hard commitid撤销到某个提交丢弃之后所有提交危险,注意git reset --hard会丢弃工作区暂存区修改非常危险使用前确认不需要修改);删除移动(git rm filename删除并添加到暂存区,--cached只从Git移除跟踪保留在工作区,git mv oldname newname重命名移动并添加到暂存区);忽略文件(.gitignore指定要忽略的文件,.log所有log文件,nodemodules/忽略目录,/dist忽略根目录dist,!取反,doc/.txt忽略doc目录下txt不包括子目录,doc/*/.pdf忽略doc目录所有pdf包括子目录,GitHub提供常用.gitignore模板库github.com/github/gitignore)。
- 分支管理:查看分支(git branch本地,-a所有包括远程,-r远程,-v每个分支最新提交,--merged已经合并到当前分支,--no-merged还没合并);创建切换(git branch branchname创建,git checkout branchname/ git switch branchname切换,git checkout -b branchname/ git switch -c branchname创建并切换,基于某个提交git checkout -b branchname commitid,基于远程分支git checkout -b branchname origin/branchname);合并(git merge branchname把指定分支合并到当前,--no-ff禁用快进生成合并提交,--ff-only只快进不能快进就失败,--abort遇到冲突中止合并,--no-edit保留合并提交信息);变基rebase(git rebase targetbranch把当前分支变基到目标分支,-i交互式变基可以修改合并删除重新排序提交,--continue解决冲突后继续,--skip跳过当前提交,--abort中止恢复到变基前,注意变基会修改提交历史,已经推送到远程且有其他人基于这个分支开发不要使用变基,只适合本地分支或只有你一个人使用的分支);删除分支(git branch -d branchname删除已合并的本地分支,-D强制删除不管有没有合并,git push origin --delete branchname/ git push origin :branchname删除远程分支);分支命名规范(master/main主分支稳定版本随时发布,develop开发分支集成开发功能,feature/xxx功能分支,bugfix/xxx bug修复分支,hotfix/xxx紧急修复分支,release/xxx发布分支,experiment/xxx实验分支)。
- 远程仓库:查看(git remote,-v对应URL,show origin详细信息);添加(git remote add origin URL,set-url修改URL,rename重命名,remove删除);抓取拉取(git fetch抓取所有分支更新不合并,git fetch origin指定远程,git pull拉取更新抓取+合并,git pull origin branchname指定远程分支,--rebase拉取时使用变基,--all拉取所有远程分支);推送(git push推送当前分支,git push origin branchname指定分支,-u/--set-upstream第一次推送设置上游分支以后可直接git push,--all推送所有分支,git push origin tagname推送指定标签,--tags推送所有标签,--force强制推送危险会覆盖远程历史,--force-with-lease更安全的强制推送如果远程在你上次拉取后有新提交就拒绝,注意git push --force会覆盖远程历史非常危险除非确定只有你一个人使用否则不要用);远程分支操作(git branch -r查看远程分支,git checkout -b localname origin/remotename创建本地分支跟踪远程,git branch -u origin/remotename设置当前分支跟踪指定远程,git branch -vv查看分支跟踪关系,git push origin --delete branchname删除远程分支,git remote prune origin清理远程已删除的分支引用)。
- 标签管理:查看(git tag,-l "v1.*"按模式筛选,git show v1.0.0查看详细信息);创建(git tag v1.0.0轻量标签只是指向提交的指针,git tag -a v1.0.0 -m "信息"附注标签包含标签名邮箱日期信息推荐,基于某个提交git tag -a v1.0.0 commit_id -m "信息");推送(git push origin v1.0.0推送指定标签,--tags推送所有标签);删除(git tag -d v1.0.0删除本地标签,git push origin --delete v1.0.0/ git push origin :refs/tags/v1.0.0删除远程标签)。
- 常见工作流:Git Flow(五种分支master主分支正式发布版本,develop开发分支集成开发功能,feature/从develop创建开发完成合并回develop,release/从develop创建准备发布发布后合并到master和develop,hotfix/从master创建修复线上紧急bug修复后合并到master和develop,适合有明确版本发布周期的项目但比较复杂);GitHub Flow(两种分支master主分支随时可部署,feature/从master创建开发完成通过Pull Request合并回master,简单灵活适合持续部署持续交付是目前最流行的工作流之一);GitLab Flow(结合Git Flow和GitHub Flow优点,增加环境分支如pre-production production管理不同环境部署);个人开发工作流(master保持稳定,开发新功能创建feature分支,开发提交,完成合并回master,推送到远程)。
- 常见问题解决:合并冲突(git status查看冲突文件,打开文件找冲突标记<<<<<<< ======= >>>>>>>,手动修改解决冲突删除标记,git add添加到暂存区,git commit完成合并);提交错误内容(还没推送git commit --amend修改上一次提交或git reset --soft HEAD~1撤销保留修改在工作区重新修改提交;已经推送不要用git reset应该用git revert commitid创建新提交撤销之前的提交,git revert HEAD撤销最近一次);不小心add了不该add的文件(git reset HEAD filename/ git restore --staged filename从暂存区移除保留在工作区);不小心删除文件(git checkout -- filename/ git restore filename恢复工作区误删文件恢复到暂存区状态;已经提交了删除git checkout commitid -- filename恢复到某个提交的版本);查看某个历史版本的文件(git show commitid:filename查看内容,git checkout commitid -- filename恢复到工作区);撤销所有本地修改恢复到远程(git fetch origin抓取最新,git reset --hard origin/branchname强制重置本地分支到远程状态危险会丢弃所有本地修改);提交信息写错了(git commit --amend -m "新信息"修改上一次提交信息,已经推送需要git push --force-with-lease谨慎);把一个分支某个提交应用到另一个分支(git checkout targetbranch切换到目标分支,git cherry-pick commitid应用指定提交,多个提交git cherry-pick commit1 commit2,范围git cherry-pick commit1..commit2)。
- 最佳实践:频繁提交每次只做一件事(不要攒一大堆修改才提交,每次提交只包含一个逻辑修改历史更清晰更容易回滚);写好提交信息(简洁明了说明做了什么,第一行简短描述不超过50字符空一行详细描述可选);使用分支(不要直接在master开发,新功能修复bug创建单独分支);定期拉取远程更新(开始工作前先git pull避免冲突);提交前先检查修改(git diff检查确保没有提交错误内容如调试代码密码密钥);不要提交敏感信息(密码密钥配置文件等用.gitignore忽略或环境变量);不要提交大文件和编译产物(视频安装包node_modules dist bin日志等用.gitignore忽略);使用.gitignore(项目开始就创建好);变基vs合并(本地分支或只有你一个人用的分支可以变基让历史整洁,共享分支用合并不修改历史);推送前先测试(本地测试确保正常运行不要推有问题的代码);使用Pull Request/Merge Request(团队协作通过PR/MR合并代码进行代码审查讨论修改确保质量);定期清理分支(合并后的分支及时删除保持列表整洁)。
- 学习资源:《Pro Git》Git官方书籍深入浅出有中文版免费在线阅读git-scm.com/book/zh/v2,《Git权威指南》国内作者写的非常详细;在线教程Git官方文档git-scm.com/doc,GitHub Guides guides.github.com,廖雪峰Git教程,菜鸟教程Git教程;交互式学习Learn Git Branching learngitbranching.js.org可视化交互式学习分支非常有趣有效,Git Immersion gitimmersion.com通过实际操作学习。
Git,是目前世界上,最流行、最强大的分布式版本控制系统。对于程序员来说,Git,已经成为了必备技能。掌握了Git,你就能更好地管理代码版本,追踪代码变更,进行团队协作。
学习Git,不要死记硬背命令,而要理解它的基本原理。理解了Git的三个区域、对象、引用、分支等基本概念,很多命令,就自然而然地理解了,不需要死记硬背。
另外,学习Git,最好的方式,就是多实践。在实际项目中,多使用Git,遇到问题,多查文档,多尝试,慢慢就熟练了。
"工欲善其事,必先利其器。"希望这篇文章,能帮你掌握Git这个强大的工具,让你的开发工作,更加高效、更加顺畅。
最后,记住:Git,只是工具。好的工具,能提升效率,但真正决定项目质量的,还是代码本身和团队协作。 不要过度追求工具的技巧,而忽略了代码质量和团队沟通。
祝你,在Git的世界里,游刃有余,高效协作!
评论(0)
暂无评论,快来抢沙发~
评论功能仅对会员开放,请先登录
登录