[26/3/17]Git入门
【【GeekHour】一小时Git教程】 www.bilibili.com/video/BV1HM…
基础配置
以下配置只需要执行一次
- 用户名配置:
git config --global user.name "用户名" - 邮箱配置:
git config --global user.email 邮箱地址 - 保存用户名和密码:
git config --global credential.helper store
创建仓库
- 本地创建一个新仓库:
git init - 从远程克隆一个仓库:
git clone 仓库地址(仓库地址结尾是.git)
基础概念
三个区:
- 工作区
- 暂存区
- 本地仓库
一般的工作流:你修改了一些文件,先从工作区 add 到暂存区,等你工作到差不多了,add 的内容足够多了,然后再用 commit 提交到本地仓库。
文件的四种状态
- 未跟踪( Untrack ):新创建的,都没有 add 的文件
- 未修改( Unmodified ):add 完成之后没有修改的
- 已修改( Modified ):add 之后修改的
- 已暂存( Staged ):刚刚 add 的
基础操作
git status:查看仓库状态git add 文件名:将文件加入暂存区(文件名可以使用通配符或者文件夹,例如 . 表示当前文件夹,意思就是把当前文件夹下的所有文件都提交到暂存区)git commit -m "提交信息":将暂存区的文件提交到仓库git log [--oneline]:查看提交记录,可以获取到版本 ID !
回退版本 reset
版本 ID 通过 log 命令查看,还有一个特殊的版本 ID HEAD 表示最新版本,此外还有上一个版本可以用 HEAD^ 或者 HEAD~ 表示;此外还有,前 2 个版本可以这样写:HEAD~2
git reset --sort 版本ID:回退,并保留工作区和暂存区的所有修改内容git reset --hard 版本ID:回退,并丢弃工作区和暂存区的所有修改内容git reset --mixed 版本ID:回退,只保留工作区的内容,但是丢弃暂存区
查看差异 diff
查看不同区、不同版本、不同分支下的内容差异
不加参数则默认查看的是工作区和暂存区的差异
git diff:默认比较工作区和暂存区的差异git diff 版本ID:比较工作区和特定版本的差异git diff --cache:比较暂存区和版本库的差异git diff 版本ID1 版本ID2:比较指定版本的不同git diff 版本ID1 版本ID2 文件名:只比较这一个文件的不同版本的差异- 分支的差异的比较和版本差异比较相似
删除文件 rm
- 先用系统命令删除一个文件,然后为了更新这个状态,你需要将这个文件再次
add到暂存区,就能够更新这个文件被删除的状态了!(或者你直接用 git status 看到它提示你这个文件被删除,需要用什么命令进行更新就好了) git rm 文件名:用 git 提供的删除命令进行操作git rm --cached 文件名:将这个文件从暂存区移除,但是不删除文件本体
忽略文件 .gitignore
需要忽略的文件:系统或者软件自动生成的文件,编译的中间文件和结果文件,运行时产生的日志缓存临时文件,带有隐私信息的文件
- 在
.gitignore这个文件里,一行写一条忽略规则,且忽略规则是从上到下的顺序进行匹配的 - 忽略文件里的空行会被忽略,
#开头的行被视为注释 - 最简单的,写一个完整的文件名
- 忽略文件夹,必须以
/结尾,例如:temp/ - 可以使用通配符,比如说
*.log - 使用
**表示任意的目录 - 使用
!表示取反
例子:
# 忽略所有的.a文件(默认就是任意文件夹下的)
*.a
# 跟踪所有的 lib.a 文件,即使有前面的忽略规则
!lib.a
# 只当前目录下的TODO文件(因为开头是/)
/TODO
# 忽略任何文件夹下,名为 build 的文件夹(结尾/表示文件夹)
build/
# 忽略特定层级的txt文件,但是doc/xxx/a.txt不会被忽略
doc/*.txt
# 忽略doc文件夹以及其所有子目录下的 pdf 文件
doc/**/*.pdf
# 补充 ** 表示任意层级的文件夹,包括当前目录,类似于 * 匹配0个字符
远程仓库
两种推送方式:
- HTTPS 方式:每次推送时都需要验证用户名和密码
- SSH 方式:不需要每次都验证,但是需要配置密钥
密钥配置
cd ~ # 先回到用户根目录
cd .ssh # 没有就自己创建一个
ssk-keygen -t rsa -b 4096 # 生成SSH密钥
# 接下来需要输入密钥文件名和密码
# 生成的 id_rsa 是私钥, id_rsa.pub 是公钥
# 请把公钥的文本内容复制粘贴到 Github 的 SSH keys设置中
# 如果使用的是默认文件名,就结束了,否则需要手动创建一个配置
touch config
# congfig文件内容如下5行
# github
Host github.com
HostName github.com
PreferredAuthentications publickey
IdentityFile ~/.ssh/私钥名称
从远程仓库开始
- 克隆仓库 :
git clone 仓库链接
同步仓库
- 推送更新内容 :
git push <remote> <branch> - 拉取更新内容 :
git pull <remote>
关联本地仓库到远程仓库
- 增加远程链接:
git remote add <shortname> <url>这里的 shortname 一般是 origin,url 是仓库的链接 - 指定分支名字:
git branch -M main把分支名修改为 main (如果你的默认分支名就是 main 那么可以不用运行这一行) - 关联:
git push -u origin main让远程的 origin 仓库和本地的 main 分支关联起来,补充:完整版本git push -u origin main:main - 查看远程仓库:
git remote -v
pull 拉取远程仓库
git pull <远程仓库名> <远程分支名>:<本地分支名> pull 后面的参数可以省略
注意:运行 git pull 之后会自动进行一次仓库合并,如果没有冲突就会合并成功,否则会因为冲突而合并失败,需要手动解决冲突
此外,如果远程分支和本地分支名字相同,可以省略冒号和后面的部分:
git pull <远程仓库名> <相同的分支名>
fetch 拉取修改
fetch 只是获取远程仓库的修改,但是并不会自动合并到本地仓库,需要手动合并。
VS Code 中的 Git 符号含义
分支 Branch
- 查看分支:
git branch - 创建新的分支:
git branch 新分支名 - 切换到新分支:
git checkout 新分支名或者git switch 新分支名
注意!checkout 还可以用于恢复文件,所以如果你有文件和新分支名相同,可能会产生歧义!所以更加推荐新命令 switch - 合并分支:首先你要处于主分支(你的目标是把别的分支合并过来)
git merge 新分支名注意这会自动产生一次提交,会自动打开 vim 要你输入提交信息,可以直接 :wq 使用默认的提交信息;此外,分支合并后并不会自动被删除! - 图形化查看分支合并情况:
git log --graph --oneline --decorate --all - 删除已经合并的分支:
git branch -d 新分支名这样删除的必须是已经合并的分支 - 强制删除未合并分支:
git branch -D 新分支名大写 D 强制删除 - 查看历史版本代码:
git checkout -b 分支名 版本ID只是查看,不会修改任何的内容!
合并分支时解决冲突
何时出现冲突?
如果两个分支修改了同一个文件的同一行代码,此时才产生冲突。
也就是运行 merge 的时候,会报错,此时:
- 可以用
git status查看冲突文件 - 可以用
git diff查看冲突的内容
看到冲突内容之后,需要手动修改再提交 (补充说明:Git 会自动把两个分支对同一个部分修改的内容都添加到那个冲突文件里面,你只需要考虑删除哪些就行)
修改后 add commit 就行,会自动完成合并过程
否则,如果你希望中止这次合并,也可以在提交之前使用:git merge --abort
变基(合并) Rease
语法:git rebase 目标分支
注意:需要先切换到自己想嫁接过去的分支,然后目标分支是其他被嫁接分支。
merge 是如同溪流汇聚一样的合并:
rebase 是把分支拆开插入式的合并:
dev 上变基:我是 dev,我迁移到 main 之后
git switch dev
git rebase main
main 上变基:我是 main,我迁移到 dev 之后
git switch main
git rebase dev
注意拆开的位置就是出现分叉的位置!
比较
然后,变基只是将分叉的位置往后移,并不是说,变基之后两个分支就会合并成一个分支了,还是两个分支,会继续分叉。
比如说,我在 mian 上开发,但是 dev 分支总是变基,不过对我来说没有任何影响,它不论怎么变基,都影响不到 main 上的代码。
Git 工作流
例如:
- GitFlow 模型
- GitHubFlow 模型