Git项目管理
写在前面:获取帮助
如果忘了某条指令怎么用,查帮助文档:
# 比如查看init指令的帮助文档
git help init
git init --help
帮助文档是你安装Git的时候就一起安装到了本地的,都是html格式文件,离线也可以查看,运行指令直接浏览器蹦出来
Git概论
首先讲各种指令之前讲讲Git眼中的项目
咱们用汉语一般说的项目,在Git中叫repository简称repo,即仓库
一个仓库有不同的分支,分支可以理解为版本
每个分支又有不同的提交,提交也可以理解为版本
不同的分支可以同时存在,但同一个分支的不同提交不能同时存在
Git配置
Git有很多配置,比如用户名,邮箱,公钥私钥,凭证管理器,等等,那么这些配置,一共分为三级:
- 系统级:C:/Program Files/Git/etc/gitconfig
- 用户级:C:\Users\34705\.gitconfig或Linux下的~/.gitconfig
- 本地级:.git/config
低级能够覆盖高级,如果关于某一配置项,低级没有定义,那么默认继承高级定义
git config --list #会展示以上三个config文件的全部内容
git config --list --show-origin #展示配置项来自哪个config
账户配置
要使用git工具,你必须在代码托管平台如github或gitee有账户,即使你只是想管理你本地的项目,但git仍然需要知道是”谁”做了“什么改动”,所以使用前必须注册账号并配置账户信息
用这两行来配置你的账户信息:
git config --global user.email "you@example.com"
git config --global user.name "Your Name"
配置好了以后这样查看:
git config --global user.email
git config --global user.name
账户配置这里,这里的邮箱和用户名并不是要和谁去连接,你写完全不存在的都可以,这里只是希望能记录提交的作者信息,让团队中其他人一看就知道是谁提交的。
凭证管理:
git路径下有一个程序叫git credential manager,凭证管理器
凭证就是指gitee或github平台的用户名和密码
需要凭证的操作有:
- git push
设置凭证管理器路径:
git config --global credential.helper "\"U:/PortableGit/mingw64/bin/git-credential-manager.exe\""
分区概念:
创建了本地仓库以后,有三个区:
- 工作区(workspace)
- 暂存区(index)
- 本地仓库(repository)
我们新创建的文件,叫做untracked,
我们修改了已有的文件,叫做unstaged,
他们都在工作区里
跟踪(tracked):所谓已跟踪或未跟踪,跟踪就是指文件已经通过git add添加到了暂存区或已经提交了,如果只是在工作区那么就是untracked,需要git add到暂存区
创建本地仓库
如果要用Git工具来管理你的项目,而你的项目只是一个文件夹,里面有各个模块的代码,如何将这个文件夹初始化为一个Git项目?
git init
在当前目录中执行git init,你的这个文件夹里就会多出一个.git文件夹,并成为一个本地仓库
查看当前仓库的状态
git status
如果你在一个不是本地仓库的目录里执行这条指令,会报错:
F:\Program Files\Obsidian\Notes>git status
fatal: not a git repository (or any of the parent directories): .git
如果你在一个本地仓库里执行这条指令,那就会显示:
- 当前仓库的工作区中所有unstaged和untracked
- 当前仓库的暂存区中所有uncommitted
工作区添加到暂存区
git add
将上述的工作区中的文件,经过add进入到暂存区index,这时候就准备好commit了
git add 后面可以跟文件名,也可以跟目录名
git add filename.subfix
git add . //将当前目录下所有文件都放到暂存区了
暂存区恢复到工作区
git restore
git restore --staged filename.subfix
unstage,将一个文件从暂存区里取出来
清除未跟踪文件
git clean -f -d
如果你新建了一些untracked files,但是想放弃他们
恢复已跟踪的一个文件
一个已跟踪的文件被修改了,但是还未git add到暂存区,这时你git status查看,会显示:
modified xxx
那么如果想放弃修改恢复原状:
git checkout -- <filepath> #注意--与<之间有一个空格
工作区提交到本地仓库
git commit
git commit -m “描述”
暂存区的内容,经过commit以后到达本地仓库的当前分支成为一个版本
一次commit,产生一个版本
commit不能提交单个文件,一提交就是将整个暂存区里的东西全部提交了
查看提交日志
log
查看commit记录,对于每一个记录,可以查看其:
- 提交标识号:每次提交都会有一个极长的字符串作为其标识号
- Author:提交者
- Date:提交日期
- 提交描述:每次commit都必须附带一个对本次提交的decription
options:
–all 显示所有分支
–pretty-oneline 将提交信息显示为一行
–abbrev-commit 使得输出的commitID更简短
–graph 以图的形式显示
当前还没有过任何提交记录
版本回滚
git reset
git reset --hard ID
版本回滚
如果你回滚到以前的某个版本,那么它之后的版本,你再通过git log去查的话就没有了
查看版本变更的所有记录
git reflog
记录了所有的版本变化的记录
git里面只要你提交过就丢不了
分支
每个人的开发互不影响,或者支线与主线互不影响
查看分支
git branch #列出所有本地物理分支
git branch -a
- 列出所有本地分支
- 列出所有远程分支的引用
- 列出远程仓库的HEAD指向
创建分支
git branch branch_name #创建一个本地分支
创建这个分支是根据当前分支的当前状态来拷贝一个副本
删除分支
git branch -d branch_name
git branch -D branch_name # 强制删除
切换分支
git checkout branch_name
切换这个分支以后,你的所有commit都会作用于当前分支,对另一个分支毫无影响
git checkout -b branch_name
创建并切换
合并分支
git merge branch_name
将branch_name合并到当前分支
冲突解决
当两个分支,他们对同一个文件的同一行有不同修改时,就会confict
这时git会让你来决定这一行的内容到底是什么
HEAD指针
头指针,指向当前的分支
分支使用的一般规范
master
线上分支,发行分支,一般不直接对这个分支进行任何修改
develop
开发分支
feature
每当项目要添加一个新功能时,就从develop创建一个新分支feature_x,然后对这个分支开发,开发好了以后merge到develop
当一个功能开发完了以后,这个功能对应的分支就可以删除了
hotfix
当线上项目发生bug时,就从master创建一个hotfix分支,修改bug,修改好了以后再merge回master,同时也要merge到develop上面
其他常见的分支还有pre,test等
其余分支不同公司有不同要求,不同团队有不同规范
远程仓库
SSH身份确认
SSH有一套身份确认机制,我们本地每台电脑可以生成一个ssh公钥,这个公钥相当于一个身份证号,然后github或gitee可以添加电脑的ssh公钥,添加了以后表明“某台电脑可以与这个账户交互"
每台机器的ssh公钥保存目录一般都是/root/.ssh
如果没有的话可以创建公钥:
ssh -keygen -t rsa -C "347053504@qq.com"
# 2025/3/18 在B212电脑上报错Bad escape character 'ygen'. 原因尚不明确,还是遵从gitee平台指示使用:
ssh-keygen -t ed25519 -C "Gitee SSH Key"
创建完以后查看其内容,并添加到github或gitee账户:
cat id_rsa.pub
然后就可以克隆和推送了
克隆远程仓库到本地
git clone 远程项目地址 [项目在本地的别名]
clone 这个操作是不需要你去配置公钥,也不需要凭证,只要你有这个项目的地址,就可以克隆。
克隆会把远程仓库的所有分支的引用(reference)克隆下来,但是只会检出(checkout)HEAD分支到本地,其他分支都是引用信息
不存在切换到某个远程分支的操作,因为你本地就一个master分支,你切换到某个分支前提是你本地有这个分支,
这时候你执行:
git branch
只会看到* master,你执行git branch -a才能看到其他分支的引用信息
其他分支没有被创建为本地分支,如果你想切换到其他分支,
git checkout origin/feature_1
这会进入detached HEAD状态,头指针会分离,指向该远程分支的最新提交,
- 引用是个什么概念:
引用就是信息,克隆了所有分支的引用就是你在本地,能知道这个仓库对应的远程仓库有几个分支分别都是谁。
但是有一个错误的理念,就是认为我能切换到某某个远程分支,这是错误的,
你可以git checkout origin/feature_1来访问这个远程分支上的提交,但是本质上你本地没有这个分支,
git checkout -b feature_1 origin/feature_1
这条指令会在本地创建一个叫feature_1的分支并且跟踪feature_1远程分支,并切换到这个分支
头指针HEAD:
HEAD有两种状态:
attached:
HEAD指向某个分支,分支又指向某个提交
detached:
HEAD直接指向某个提交或标签,而不是分支
添加远程仓库
首先要把远程仓库和本地仓库建立一个对应关系
git romote add 远程仓库别名 远程仓库地址(SSH或HTTPS)
git remote add origin git@github.com:ztsrxh/RoadBEV.git
99%情况下,一个本地仓库对应一个远程仓库,极少数情况下,一个本地仓库会对应到多个远程仓库
查看远程仓库
查看本地仓库所对应到的所有远程仓库
git remote 光显示别名
git remote -v 显示别名和url链接
之前你git remote add 过的所有远程仓库都会被显示
推送到远程仓库
git push [-f] [--set-upstream] [远程仓库别名] [本地分支名] [:远端分支名]
# 可以完全不写分支,默认是:本地当前分支->其对应upstream远程分支
git push origin
# 这里的master指的是本地分支名
git push origin master
D:\new>git push origin master
To https://gitee.com/jason-wan-fighter/JLU-single-chip-processor-course.git
! [rejected] master -> master (fetch first)
error: failed to push some refs to 'https://gitee.com/jason-wan-fighter/JLU-single-chip-processor-course.git'
hint: Updates were rejected because the remote contains work that you do not
hint: have locally. This is usually caused by another repository pushing to
hint: the same ref. If you want to integrate the remote changes, use
hint: 'git pull' before pushing again.
hint: See the 'Note about fast-forwards' in 'git push --help' for details.
push pull和merge其实不太一样,一个常见的误区就是认为push不能修改原来的任何,只能加东西,其实不是,可以删可以改,只要本地分支比远程分支的commit更新,那就能push成功。
push和pull都是merge操作,最后结果一样也不行,比如你说你远程仓库里就一个readme,然后你本地创个仓库, git remote add ,然后添加个read,然后再加点啥别的,然后开始往上push,这行吗?这不行。你说你本地的最新commit不是包含了远程仓库了么,但是提交历史不一样,也不行。所以真要想对远程仓库做点啥改动,老老实实clone下来弄。
推送时不能有超过100MB的大文件,如果只是代码的话那么即使很大的项目也不可能超过100Mb,超过的一般是你把视频什么的放进去了。如果你一次commit中有大文件,那么你即使新的commit把大文件删了,那么仍然push不上去,因为有大文件的那次提交的历史记录仍然保存在项目里,所以你的项目仍然含有超过100M的文件。那么这样的话就只能删除历史记录了,会很麻烦。
–options:
-f:
如果产生conflict,无脑强制用本地覆盖远端
一般公司里会把-f禁用,以免小白把仓库里的代码全覆盖了
–set-upstream:
推送到远端的同时还建立与远端分支的联系,一次执行,永远绑定
git push --set-upstream origin master: master
查看本地分支和远程分支的对应关系
git branch -vv
抓取
抓取就是将仓库里的更新都抓取到本地,不会进行合并
如果不指定远端名称和分支名,那就抓取全部分支
git fetch [remote name] [branch name]
git merge origin/master
拉取
拉取指令就是将远端仓库的修改拉到本地并自动进行合并,等同于fetch+merge
如果不指定远端名称和分支名,则抓取更新所有分支
git pull
现实的教训告诉我们不要用默认,任何操作都要明确显示指定,不要用默认,因为默认操作做什么依赖于设置
.gitignore
当前项目下有一些文件我们希望git忽视掉,
创建一个叫.gitignore的文件,里面保存你希望忽视的文件格式:
*.a
.gitignore文件一般是项目组统一给一个,不需要自己写
Pull Request:
正常的git工作流
要给一个项目开发一个新功能,先
git clone url
git branch feature_new
git checkout feature_new
git add .
git commit -m "new feature developed"
git checkout main
git merge feature_new
git push origin main
references:
教程视频
https://www.bilibili.com/video/BV1MU4y1Y7h5?spm_id_from=333.788.player.switch&vd_source=aa5c28fd779dafffc339fb1f6d26c788&p=7
Git官方文档
https://git-scm.com/book/en/v2/Getting-Started-About-Version-Control
报错记录:
可疑的路径:把仓库clone 进了u盘里
G:\markdown-notes>git status
fatal: detected dubious ownership in repository at 'G:/markdown-notes'
'G:/markdown-notes' is on a file system that does not record ownership
To add an exception for this directory, call:
git config --global --add safe.directory G:/markdown-notes
2025/3/25/18:22,我把一个仓库克隆进了u盘里,然后cd进这个仓库进行git status的时候,报了这个错,但是我把仓库克隆到本地F盘的时候就没有报错
结论就是不要把仓库克隆到u盘里,u盘不属于这台电脑的文件系统。