Shell入门 – Git篇
Shell入门 – Git篇
Git 是常用的版本管理工具,非常有必要了解其用法。目前很多 IDE 都内置了对 Git 的支持,也存在一些 GUI 软件,如 TortoiseGit 等,使用起来都很方便。但是它的命令行工具,更加灵活也更加强大,了解一下也是不错的。
Git 基本概念
远端版本库(origin)
Git 服务端,可以将本地修改推送至远端,其他人从远端拉取代码,除了版本管理,还可以设置其他一些东西,比如权限,ssh 配置等。
本地工作区(working directory)
就是 Git 所在目录,可以理解为所有的内容修改都在工作区进行。
本地暂存区(stage)
暂时保存工作区的内容,用于提交。修改的内容,或者新增的文件,都可以使用 git add 添加至暂存区。
本地版本库
使用 git commit 会将暂存区的修改提交至本地仓库。
分支(branch)
Git 可以将各自的修改用 分支 隔离开,在自己分支上操作不会影响到其他分支,最后统一合并到主分支。
Git 内部有个指向最后一次提交的 HEAD 指针。
主分支之前名字叫 master,这名字有点政治不正确,现在已经改成 main 了。
额外提一嘴,之前常见的主从用词:master-slave,听起来更加政治不正确,现在也改叫 leader-follower 了。
世界人民大团结万岁。
安装 Git
Windows
直接在 Git - Downloads (git-scm.com) 下载安装就可以了,统统下一步就 OK。
Linux
直接用各自的包管理工具安装就可以,如 Debian 系可以使用 sudo apt install git。
Mac
没有用过,手头也没有Mac,自行摸索吧。
配置 Git
设置用户信息(config)
# 设置用户邮箱
git config --global user.email "wanglifa@chaguan.com"
# 设置用户名
git config --global user.name "Lifa Wang"
创建版本库
本地创建(init)
# 创建版本库(会多出一个.git目录)
git init
# 将文件添加到暂存区,file_name 表示文件名,也可以用 "." 代替,表示将所有文件都添加到暂存区
git add file_name
# 将暂存区的文件提交至版本库,提交信息是要写的
git commit -m commit_message
远端拉取创建(clone)
# 通过 ssh 协议拉取
git clone git@github.com:996icu/996.ICU.git
# 通过 http 协议拉取
git clone https://github.com/996icu/996.ICU.git
git clone 会创建同名文件夹,后续操作需要进入该文件夹执行。
ssh 和 http 两种协议在日常使用中几乎没有区别。在 clone 时,如果是 ssh 协议,需要提前配置 ssh 密钥;如果是 http 协议,需要提供邮箱密码,可以选择保存,之后操作就不要再填密码了。
如何配置 ssh 密钥,那是另一个话题,以后再说吧。
工作区操作
查看当前状态(status)
git status
这是使用最多的命令,可以查看当前工作区状态,并且 Git 会非常智能地给出提示。比如:
$ git status
On branch main
Your branch is ahead of 'origin/main' by 1 commit.
(use "git push" to publish your local commits)
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: linux/Shell入门-Git篇.md
no changes added to commit (use "git add" and/or "git commit -a")
输出会显示当前分支 main,显示当前分支和远端版本库的版本差异,提示使用 git push 发布版本到远端,显示尚未保存到暂存区的文件,如果需要提交至暂存区,可以使用 git add,如果要撤销修改可以使用 git restore,按提示操作就非常省心,很多 Git 命令都会有提示,要好好利用。
比较修改内容(diff)
# file_name 参数可选,不填则比较所有文件
git diff file_name
# 和指定提交进行比较,HEAD代表最后一次提交,也可以换成其他的 commit_id
git diff HEAD file_name
# 查看 diff 命令详细用法
git diff -h
将工作区修改添加到暂存区(add)
# 将指定文件保存至暂存区
git add file_name
# 将工作区所有内容都保存至暂存区
git add .
提交至本地版本库(commit)
# 提交信息是要写的
git commit -m "commit message"
保存到本地(stash)
这种情况用于当前正在修改 function1,尚未完成(尚未提交),但是插入了更高优先级的 function2,且需要在同一分支上操作,为将 function1 和 function2 隔离开,可以使用 git stash 功能,将 function1 保存至 stash 区且工作区回退至 clean 状态,待 function2 修改完成,再将 function1 还原回来。
# 将工作区修改保存至 stash 区,同时工作区还原至 clean 状态
git stash
# 查看 stash 区内容
git stash list
# stash 区出栈,被保存内容还原至工作区
git stash pop
# 查看 stash 命令详细用法
git stash -h
撤销修改(restore/checkout/reset/clean)
# 命令有很多,以下都可以看一下
# 撤销工作区对 file_name 的修改
git restore file_name
# 将暂存区修改撤回到工作区,即撤销 git add 操作
git restore --staged file_name
# 将 file_name 的修改撤销至暂存区状态,如果暂存区没有该文件,则撤销至版本库状态(上一次commit),"--" 很重要
git checkout -- file_name
# git reset既可以回退版本,也可以把暂存区的修改回退到工作区。用HEAD时,表示最后一次提交
git reset HEAD file_name
# 删除未被 Git 跟踪的文件
git clean -df
版本回退(reset)
# 回退到指定提交
git reset commit_id
# 回退至指定提交,同时文件内容也回退至该次提交
git reset --hard commit_id
# 回退至上一次提交
git reset --hard HEAD
# 回退到上一个HEAD,^可以使用多个,表示往前数的HEAD个数,多了还是用commit_id,更清晰
git reset --hard HEAD^
查看提交记录(log/reflog/blame)
# 查看提交记录
git log
# 查看提交记录,只显示关键信息
git log --pretty=oneline
# 查看提交记录,只显示关键信息,commit_id简化显示
git log --pretty=oneline --abbrev-commit
# 查看操作记录(HEAD信息)
git reflog
# 查看文件内容修改记录
git blame file_name
分支操作(branch)
# 创建分支
git branch feature_kill_MaziLiu
# 切换分支,注意如果有"--"表示撤销内容修改
git checkout feature_kill_MaziLiu
# 上述两个命令可以合并为一个:创建并切换至新分支
git checkout -b feature_kill_MaziLiu
# 列出所有本地分支
git branch
# 删除分支
git branch -d feature_kill_MaziLiu
# 强制删除分支
git branch -D feature_kill_MaziLiu
# 合并指定分支到当前分支
git merge main
# 合并远端分支到当前分支
git merge origin/main
远端交互(origin/pull/push/checkout)
# 将当前分支推送至远端版本库,同时将本地分支和远端feature_kill_MaziLiu分支关联起来
# 关联之后就不需要加 -u 及其参数了
git push -u origin feature_kill_MaziLiu
# 拉取远端关联版本到本地
git pull
# 推送本地分支至远端,--force 强制覆盖远端,不推荐
git push
# 查看远端版本库的分支
git branch -r
# 拉取远端分支,创建并切换至对应本地分支
git checkout -b feature_kill_MaziLiu origin/feature_kill_MaziLiu
# 建立本地分支和远端分支的关联
git branch --set-upstream feature_kill_MaziLiu origin/feature_kill_MaziLiu
标签操作(tag)
tag,顾名思义,就是个记号,一般发重要版本可能会打个标记。
# 在最后一次提交处打标签,标签名字为 MaziLiuKilled : 刘麻子已经被咔嚓了
git tag MaziLiuKilled
# 查看已有tag
git tag
# 在指定提交处打标签
git tag tag_name commit_id
# 查看标签详细信息
git show tag_name
# 创建一个带说明的tag,-a后面是tag名称,-m后面是说明文字
git tag -a tagname -m "tag_message" commit_id
# 删除标签
git tag -d tagname
# 删除远端标签(需要先本地删除)
git push origin :refs/tags/tag_name
# 推送某个tag到远端
git push origin tag_name
# 推送所有未推送的标签到远端
git push origin --tags
别名(alias)
Git 的配置,包括上文 [配置 Git](#配置 Git) 都可以直接修改 .git/config 文件,当然命令行直接操作也是可以的。
很多 Git 命令都比较长,比较难记,可以使用较短的别名代替,可以极大降低 Git 命令行的使用难度。比如:
# 配置 logone 别名,配置后可以直接 git logone
git config --global alias.logone "log --pretty=oneline --abbrev-commit"
可以搭配 Linux 别名使用,效果也很好。比如:
# 添加到 ~/.bashrc,本地创建新分支后,可以直接 upush 推送到远端同名分支并建立关联
alias upush='git push -u origin `git symbolic-ref --short HEAD`'
.gitignore 文件
用于配置不想被 Git 追踪的文件,也可以修改 .git/info/exclude 文件达到同样的效果。
# .gitignore 可以反向生效,比如只追踪 .c 文件
!*.c
常见问题及小技巧
创建分支后无法 push
可能是分支被保护了,需要设置 Protected Branch ,选择 unprotected 。
使用 TortoiseGit,进行 pull/push 等操作时,总是提示输入用户名和密码
修改配置文件,.git/config,credential 的值修改为 store,也可以用 git config --global credential.helper store 命令实现。
使用 diff 比较差异
# 将差异重定向到文件,用于后续分析
git diff commit_id1 commit_id2 > diff.txt
# 使用 -stat 仅打印摘要
git diff branch_name1(commit_id1) branch_name2(commit_id2) --stat > diff.txt
# 使用脚本出补丁文件
mkdir target && git diff --name-only commit_id1 commit_id2 | while read line; do cp --parents $line target/; done
Git 新仓库 pull 报错:fatal: refusing to merge unrelated histories
解决方法:git pull origin master --allow-unrelated-histories
pull 报错:OpenSSL SSL_read: Connection was reset, errno 10054
解决方法:git config --global http.sslVerify "false"
git bash 界面无法正常显示中文
解决方法:git config --global core.quotepath false
浙公网安备 33010602011771号