- 2021/12/21 二刷
传送门:《Git教程》
10 分推荐的 git 入门读物,抽出一个下午的时间就能读完,你会对 git 基本操作有一个完整的认识!
初始化
git init
初始化git add <file>
添加文件,可以反复多次使用git commit -m <message>
提交
status
查看工作区和缓存区状态。
$ git status
diff
# 和最近一次 commit 相比做了哪些修改
$ git diff
# 查看工作区和版本库最新版本区别
$ git diff HEAD --
版本回退
在 Git 中,HEAD
表示当前版本,也就是最新的提交,上一个版本是 HEAD^
,上上个版本就是 HEAD^^
,另一种写法是 HEAD~2
# 查看提交历史(--oneline 单行显示)
$ git log
# 查看命令历史
$ git reflog
# 回退到上个版本(写法一:^)
$ git reset --hard HEAD^
# 回退到指定版本(写法二:<commit id>)
$ git reset --hard 748309a
撤销修改
checkout
、reset
、restore
它们有什么区别?
场景1 - 丢弃工作区修改
# 撤销工作区的修改,回到最近一次 git add 或 git commit 时状态
$ git checkout -- <file>
场景2 - 丢弃缓存区的修改
# 回到 git add 之前的状态
$ git reset head <file>
场景3 - 丢弃版本库的修改
# 版本回退
$ git reset --hard <commit id>
工作区
|
| modified
↓
MODIFYTABLE
|
| add . ←————————
↓ |
staged |
| |
| modified |
↓ |
MODIFYTABLE ————————
# 可以想象有一张工作表,每次工作区改动都会记录在表中,当 add 时会把把内容移动到缓存区
# 如需把缓存区内容移动到工作区
# 同 git reset HEAD .
$ git restore --staged .
# 如只需恢复工作区改动,直接 restore 即可
# restore 会优先考虑缓存区而不是工作表
# 同 git checkout -- .
$ git restore .
# reset 除了回退版本,也可以把缓存区的修改回退到工作区
$ git reset HEAD .
删除文件
删除工作区文件并把记录添加到缓存区(把 删除 记录到工作表并把工作表内容移动到缓存区)。
如果修改内容没有添加到缓存区仍强制删除,会丢失在缓存区的内容,只能恢复最新分支的记录。
$ git rm <file>
远程库
往某个账户的仓库推送代码时,该仓库需要有推送方的 SSH Key 公钥,否则无法推送。
Git 支持多种协议,使用 https
除了速度慢以外,还有个最大的麻烦是每次推送都必须输入口令。但是在某些只开放 http 端口的公司只能使用 https
。
第一次推送时需要加上 -u
参数,这能让 git 把本地的分支(默认 master)和远程的分支(默认 master)关联起来
# 添加远程库
$ git remote add gitee git@gitee.com:Thinc/test-repo.git
$ git remote add github git@github.com:shaoshenchen/LeetCode.git
# 删除远程库
$ git remote rm github
# 查看远程库
$ git remote -v
pull 操作
注:非原文资料,参考 醉逍遥neo 同学,push 同
# 将 远程指定分支 拉到 本地指定分支
$ git pull origin <远程分支名>:<本地分支名>
# 将 远程指定分支 拉到 本地当前分支
$ git pull origin <远程分支名>
# 将 与本地当前分支同名的远程分支 拉到 本地当前分支(需先关联远程分支)
$ git pull
push操作
# 将 本地指定分支 推到 远程指定分支
$ git push origin <本地分支名>:<远程分支名>
# 将 本地指定分支 推到 与本地指定分支同名的远程分支上
$ git push origin <本地分支名>
# 将 本地当前分支 推到 与本地当前分支同名的远程分支上(需先关联远程分支)
$ git push
创建与合并分支
# 创建并切换到 dev 分支
# 等价于 git branch dev & git checkout dev
$ git checkout -b dev
Switched to a new branch 'dev'
# 另一种新的创建并切换分支方法
$ git switch -c dev
Switched to a new branch 'dev'
# 查看当前分支
$ git branch
* dev
master
# 修改分支(工作完成,回到原来分支)
$ git checkout master
# 合并分支(合并指定分支到当前分支)
# Fast-forward 快进模式 直接把 master 指向 dev
# 禁用快进模式可以 --no-ff 就能在 merge 时生成新的 commit
$ git merge dev
Updating d46f35e..b17d20e
Fast-forward
readme.txt | 1 +
1 file changed, 1 insertion(+)
# 删除分支(强制删除用 -D)
$ git branch -d dev
Deleted branch dev (was b17d20e).
解决冲突
# 可以用 status 查看冲突文件
$ git status
On branch master
Your branch is ahead of 'origin/master' by 2 commits.
(use "git push" to publish your local commits)
You have unmerged paths.
(fix conflicts and run "git commit")
(use "git merge --abort" to abort the merge)
Unmerged paths:
(use "git add <file>..." to mark resolution)
both modified: readme.txt
no changes added to commit (use "git add" and/or "git commit -a")
# 用 log 查看分支合并图
$ git log --graph
* cf810e4 (HEAD -> master) conflict fixed
|\
| * 14096d0 (feature1) AND simple
* | 5dc6824 & simple
|/
* b17d20e branch test
* d46f35e (origin/master) remove test.txt
* b84166e add test.txt
* 519219b git tracks changes
* e43a48b understand how stage works
* 1094adb append GPL
* e475afc add distributed
* eaadf4e wrote a readme file
解决 Bug
# 临时“储藏”当前工作区
$ git stash
Saved working directory and index state WIP on dev: f52c633 add merge
# 从出 Bug 的分支创建新分支(假设 Bug 在 master)
$ git checkout master
$ git checkout -b issue-101
# 修复完提交
$ git add .
$ git commit -m 'fix bug 101'
# 回到出 Bug 的分支,合并并删除新建分支
$ git switch master
$ git merge --no-ff -m 'merge bug fix 101' issue-101
$ git branch -d issue-101
# 恢复工作区
# git stash apply 恢复但不删除 stash 内容,需要 git stash drop 手动删
# git stash pop 恢复且删除
$ git switch dev
$ git stash list
stash@{0}: WIP on dev: f52c633 add merge
$ git stash stash@{0}
# “复制”提交所做的修改(并自动做一次提交)
# master 分支从 dev 分出来的,bug 在 dev 分支上也存在
$ git branch
* dev
master
$ git cherry-pick 4c805e2
多人协作
- 首先,可以试图用
git push origin <branch-name>
推送自己的修改; - 如果推送失败,则因为远程分支比你的本地更新,需要先用
git pull
试图合并; - 如果合并有冲突,则解决冲突,并在本地提交;
- 没有冲突或者解决掉冲突后,再用
git push origin <branch-name>
推送就能成功!
如果 git pull
提示 no tracking information ,则说明本地分支和远程分支的链接关系没有创建,用命令 git branch --set-upstream-to <branch-name> origin/<branch-name>
。
标签
# 新建标签 git tag <tagName>
$ git tag v1.0
# 查看所有标签
$ git tag
v1.0
# 在之前的某次提交打标签
# 找到历史提交的 commit id 然后打上
$ git log --pretty=oneline --abbrev-commit
dcbb9ea (HEAD -> master, origin/master, origin/HEAD) add file c.txt
f3604b2 add file b.txt
c4b105c (tag: v1.0) add file a.txt
748309a Initial commit
$ git tag v1.1 f3604b2
# 查看标签信息 git show <tagname>
$ git show v1.1
# 删除标签 git tag -d <tagname>
$ git tag -d v1.0
# 推送标签到远程 git push origin <tagname>
$ git push orogin v1.1
# 一次性推送尚未推送的本地标签
$ git push origin --tags
# 删除远程标签 git push origin :refs/tags/<tagname>
$ git push origin :refs/tags/v1.1
使用代码托管平台
# 查看远程库信息
$ git remote -v
# 删除已有远程库
$ git remote rm origin
# 关联新的远程库 git remote add <originName> <originUrl>
$ git remote add origin https://gitee.com/Thinc/test-repo.git
# 再添加一个新的远程库
$ git remote add github https://github.com/shaoshenchen/LeetCode
忽略特殊文件
创建一个特殊的 .gitignore
文件。最全面的配置可以参考 https://github.com/github/gitignore
# 强制添加文件到 git
$ git add -f node_modules/
配置别名
当前仓库的配置文件在 .git/config
文件中;当前用户的配置文件在 .gitconfig
目录下。
# 给 checkout 配置别名 co
$ git config --global alias.co checkout
# 给命令配置别名
$ git config --global alias.unstage 'reset HEAD'
$ git unstage index.html
# 等价于 git reset HEAD index.html