基础
# 初始化
git init <name>
# 查看状态
git status
# 查看历史记录
git log
# 查看某次提交的具体信息
git show <commit_id>
# 添加到暂存区
git add <file>
# 提交
git commit <-m "commit">
# 修改提交
git commit --amend
远程仓库
clone
git clone [-b branch] git@server:repo [local_directory]
- 默认拷贝master分支
- 默认拷贝到当前目录
- 上述形式默认是以git协议传输,可以修改成通过HTTPS协议clone
# git协议,需要把公钥放在GitHub上
git clone git@github.com:wuentao1998/shell.git
# https 协议
git clone https://github.com/wuwentao1998/shell.git
- 只克隆某个指定分支的最近一次commit:
git clone -b <branch> --depth=1 <repo>
- 有些时候Git仓库的历史提交较多或较大,导致整个仓库很大
- 比如在仓库历史的某次commit时,有人不小心提交了1G的文件,虽然后面的commit中他把这个文件删除了,但是在.git文件夹中仍然存储着这个文件,所以如果我们克隆仓库这个仓库,会把所有的历史协作记录都clone下来
- 其实对于我们直接使用仓库,而不是参与仓库工作的人来说,只要把最近的一次commit给clone下来就好
- 这样可以大大加快克隆的速度,特别在连接仓库网络不好的时候
- 有些时候Git仓库的历史提交较多或较大,导致整个仓库很大
- 如果后续想要把之前的历史重新再全部pull,可以使用
git fetch --unshallow
pull/fetch
git fetch <shortname> <remote_branch>:<local_branch>
- 拉取指定远程分支的修改,并不影响代码库代码
- 只是更新了/指向的commit_id的本地缓存
- 需要手动
git merge/rebase <shortname>/<branch>
git pull <shortname> <remote_branch>:<local_branch>
- 默认从远程的master分支拉取到本地master分支
- 拉取并合并,相当于
git fetch + git merge/rebase
- 默认是
--merge
, 也可以通过--rebase
用rebase替换merge
- 默认是
- 如果本地已经提交了commit,远端也更新了commit了,那么可能产生冲突
push
git push [-uf] remote_repo [local_branch: remote_branch]
-u
参数可以把本次操作设为默认操作-f
参数强制推送
remote
# 关联远程库
git remote add <shortname> <url>
# 重命名远程库的shortname
git remote rename <old> <new>
# 删除远程库
git remote rm <shortname>
# 查看远程库的地址
git remote -v
# 查看远程库具体信息, 例如有哪些远程分支
git remote show shortname
分支操作
- 删除远程分支
git push --delete <shortname> <branch>
branch
git branch [-ravu]
r
参数为查看远程分支a
参数为同时查看远程和本地分支v
参数可以看到各个分支的最新提交vv
参数可以看到本地分支关联的远程分支- 前面有
*
的为当前分支
git branch <branch>
- 创建新分支
git branch -[d/D] <branch>
- 删除本地分支
- 当feature,hotfix等分支合并到master分支后,应该删除该分支
D
参数为强制删除
- 删除本地分支
git branch -m <old> <new>
- 重命名本地分支
git branch --set-upstream-to=<shortname>/<branch>
- 关联当前分支到指定远程分支
checkout
# 切换分支
git checkout <branch>
# 新建分支并切换到该分支
git checkout -b <branch>
# 基于远程分支新建本地分支
git checkout -b <branch> <shortname>/<branch>
合并
merge
git merge <branch>
- 把指定分支合并到当前分支
--no-ff
参数禁用fast-forward- fast-forward的隐患在于如果master使用该方式merge了dev, 当我们删除dev时,dev的历史就看不见了
- 只有在没有需要合并内容的时候,会有这个
fast-forward
方式的提交 - 如下图前一次提交是fast-forward,后两次不是,可以看出后者多了一个commit
rebase
-
可以用来修改提交历史,也可以用于合并
-
rebase相当于把当前分支的修改移动到源分支最新修改的后面,这样合并到源分支时就不会冲突了
-
由于rebase改变了当前分支的历史(例如提交时间),所以只能对个人分支操作,禁止对多人操作的公共分支执行rebase
- 例如master, dev分支
-
rebase的好处:
- 源分支看上去是一条直线,更加清晰
- 可以修改feature分支的commit记录
- 例如合并commit,修改message等
-
rebase的坏处:
- 当前分支实际branch out的节点找不到了
- 如果出现冲突,merge只要解决一次,rebase可能要多次
-
参考:
cherry-pick
git cherry-pick <commit_id>
- 只合并这一次修改
撤销
# 撤销提交的修改
git reset --hard HEAD^
# 撤销提交并将修改放回暂存区
git reset --soft HEAD^
# 撤销提交并将修改放回工作区
git reset (--mixed) HEAD^
# 撤销工作区修改
git checkout -- <file>
# 撤销暂存区修改
git reset HEAD <file>
# 同时撤销暂存区和工作区修改
git reset --hard HEAD
# 反做commit_id的提交
# 形成新的提交,比reset更安全
git revert <commit_id>
修改历史
reset
# 合并提交
git reset --soft HEAD~n
git commit
rebase
# 修改提交记录
git rebase -i <commit_id>
git commit --amend # 如果前缀是edit则会进行这一步
git rebase --continue
#如果分支已经提交到了远程库,需要强制覆盖
git push -f
- 变更commit_id之后的提交记录,不包括其本身
- 使用rebase时待编辑的提交历史和log中显示的顺序是反过来的
- 可以直接在交互式编辑器中把提交历史翻转
- squash用于合并提交
- edit可用于拆分提交
- 参考:https://www.jianshu.com/p/4a8f4af4e803
filter-branch
标签
# 列出所有标签
git tag
# 显示标签详细详细
git show <tag_name>
# 推送标签
git push <origin> <tag_name>
# 打标签,默认为当前提交
git tag <commit_id>
储藏
- 默认只储藏提交到暂存区的文件,可以通过-u把工作区的文件也储藏
# 储藏
git stash
# 查看储藏列表
git stash list
# 还原储藏到工作区
git stash pop
比较
# 工作区与暂存区对比
git diff
# 工作区与版本库对比
git diff head
# 暂存区与版本库对比
git diff --cached
# 比较远程分支和本地分支的差异
git diff <local_branch> <remote_branch>
删除文件
- 如果文件已经加入了暂存区,那么用rm删掉文件本身还可以从暂存区找回
- 找回命令:
git checkout -- <file>
- 这个命令同时可用于我们不想保留工作区对文件的改动
- 找回命令:
git rm <file>
把文件从暂存区删除,文件本身还存在git rm -f <file
同时把文件本身和暂存区删除
清除
- 只删除新文件和目录,不清除修改
# 清除所有未暂存文件
git clean -f
# 同时清除未暂存文件和目录
git clean -df
# 模拟清除
git clean -n
恢复
git reflog
保留了所有操作记录- 包括 commit, reset, revert等操作记录
- 一般用来恢复错误操作
- 如果我们采取了hard-reset操作,但是却想取消该操作
- 如果还保留了新提交的commit_id,则可以通过
git reset <commit_id>
直接恢复 - 如果没有保留,则可以通过
git reflog
查找commit_id
- 如果还保留了新提交的commit_id,则可以通过
忽略文件
- 由 .gitignore文件管理
- 格式规范
- 所有空行或者以 # 开头的行都会被 Git 忽略。
- 可以使用 shell 所使用的简化了的正则表达式匹配。
- 星号匹配零个或多个任意字符
- [abc] 匹配任何一个列在方括号中的字符(这个例子要么匹配一个 a,要么匹配一个 b,要么匹配一个 c)
- 如果在方括号中使用短划线分隔两个字符,表示所有在这两个字符范围内的都可以匹配(比如 [0-9] 表示匹配所有 0 到 9 的数字)
- 问号(?)只匹配一个任意字符
- 使用两个星表示匹配任意中间目录,比如
a/**/z
可以匹配 a/z, a/b/z 或a/b/c/z
等。
- 匹配模式可以以(/)开头防止递归
- 匹配模式可以以(/)结尾指定目录
- 要忽略指定模式以外的文件或目录,可以在模式前加上惊叹号(!)取反。
# no .a files
*.a
# but do track lib.a, even though you're ignoring .a files above
!lib.a
# only ignore the TODO file in the current directory, not subdir/TODO
/TODO
# ignore all files in the build/ directory
build/
# ignore doc/notes.txt, but not doc/server/arch.txt
doc/*.txt
# ignore all .pdf files in the doc/ directory
doc/**/*.pdf
配置
- 配置文件
- 整个计算机的全局配置在 /etc/gitconfig 中
- 计算机中每个用户的配置在~/.gitconfig中
- 每个git仓库的配置在 .git/config中
- 优先级依次递增
- 默认通过https协议代替git协议
- 因为git协议通过9418端口传输,而很多防火墙会禁止这一端口
- 可以在
~/.gitconfig
文件中修改
git config --global url."https://".insteadOf "git://"
- 用户名和邮箱配置
git config --global user.name "your name"
git config --global user.email "your email"
- 查看配置
git config --list
workflow
- master分支只能merge别的分支,不能直接提交
- 每次加一个新功能,都创建一个feature分支
- 合并到dev或者master分支前,先
git pull
拉取最新分支 - 合并dev前先在feature分支rebase,解决完冲突再merge
- merge后删除feature分支
commit message规范
- commit message一般包含三个部分
- header
- body
- footer
- 通常用来说明不兼容的改动和关闭的 Issue 列表