学习时间:2018年12月7日~2019年1月6日 参考视频:深入掌握Git与实战开发
- 直接记录快照,而非差异比较
- 文件的三种状态
已修改(modified)| 已暂存(staged)| 已提交(committed) - windows下换行符问题
bash git config --global core.autocrlf false
Git常用命令
1. 获得版本库
Linux 下查看 git 安装目录
which git
git init # 初始化版本库git clone <url> # 克隆版本库
2. 版本管理
git add . # 将已修改或新添加的文件加入到暂存区中(不包括被删除的文件)git add -u # git add --update 包括修改或者删除的文件git add -A # git add --all 等价于上面2个,即修改/删除/添加都会被加入到暂存区git add filename # 将已修改的文件加入到暂存区中,支持正则表达式git checkout -- filename # 将工作区中的修改丢弃掉(相对于最后一次保存在暂存区中的文件)git reset HEAD filename # 将添加到暂存区的内容移除到工作区git rm --cached filename # 将文件从暂存区删除git commit # 将暂存区的所有文件提交到版本库中git commit -m "注释" # 提交时直接增加注释信息git commit -am "注释" # 将修改的文件(之前纳入到版本库中)加入到暂存区并提交git rm filename # 删除文件,并纳入到暂存区# ------------ 等价于以下2步 ------------ #rm filename # 删除文件git add filename # 将删除操作加入到暂存区# ------------------------------------- #git commit -m "注释" # 提交删除操作git reset HEAD filename # 将待删除的文件从暂存区恢复到工作区git checkout -- filename # 将工作区中的修改丢弃掉git mv oldfilename newfilename # 重命名文件,并并纳入到暂存区# ------------ 等价于以下2步 ------------ #mv oldfilename newfilename # 删除文件git add oldfilename newfilename # 将删除操作加入到暂存区,或者执行"git add ."# ------------------------------------- #git commit -m "注释" # 提交git commit --amend -m "修改后的注释" # 修改上次提交的注释内容
3. 查看信息
git status # 查看状态信息git log # 查看当前分支提交日志git log -n 3 # 查看最近3条提交日志git log --graph # 图形化查看git log --abbrev-commit # 简略显示commit IDgit log --pretty=oneline # 以简略模式显示日志git log --pretty=format:"%h - %an, %ar : %s"git log origin/master # 查看远程master分支日志git log remotes/origin/master # 上面的完整写法git log refs/remotes/origin/master # 最完整的写法git refloggit blame filename # 显示文件的修改信息git help <命令> # 查看帮助信息git <命令> --help # 查看帮助信息man git <命令> # 查看帮助信息
4. 全局配置
git config --global core.editor vim # 修改当前用户的默认编辑器为vim# 创建别名git config --global alias.br branch # 对branch增加别名brgit config --global alias.co checkout # 对checkout增加别名cogit config --global alias.unstage "reset HEAD" # 对reset HEAD增加别名unstagegit config --global alias.s status # 对status增加别名sgit config --global alias. '!gitk' # 运行外部命令gitkgit config --global alias.logf "log --pretty=format:\"%h - %an, %ar : %s\""git config --global alias.logo "log --abbrev-commit --pretty=oneline"git config --global alias.logn "log -n"# 配置用户信息git config --local user.name "张三"git config --local user.email "test@test.com"git config --unset user.name # 删除user.name
user.name与user.email有3个地方可以设置:
- /etc/gitconfig:整个计算机的name和email,实际开发几乎不会用
git config --system- ~/.gitconfig:指定用户的name和email,很常用
git config --global- .git/config:特定项目的name和email
git config --local
5. 忽略文件
echo "要忽略的文件" > .gitignoregit add .git commit -m "提交.gitignore文件"
.gitignore支持正则表达式,git不会识别空文件夹
/*/.a:忽略一级子目录下的.a文件/**/.a:忽略所有目录(包含根目录)下的.a文件*.a:忽略所有目录中.a结尾的文件!lib.a:保留lib.a文件/TODO:仅忽略项目根目录下的TODO文件,XXX/TODO不会被忽略build/:忽略build目录下的所有文件(夹)doc/*.txt:忽略doc目录下的txt文件,但doc/XXX/*.txt不会被忽略解决idea的.gitignore有时不起作用的问题 有时候,.gitignore会对部分文件/文件夹失效,大概原因是由于新创建的文件已经出现在git本地仓库的缓存,所以.gitignore就失效了。解决办法就是清空一下git仓库的缓存,重新提交一次就好了
git rm -r --cached .git add .git commit -m 'update .gitignore'
Git分支
1. 显示当前分支
git branchgit branch -v # 显示注释信息
2. 创建新分支
git branch new_branch
3. 切换分支
git checkout new_branchgit checkout - # 切换到上一个分支git checkout -b new_branch # 创建新分支并切换# checkout高级用法git checkout commit_id # 直接切换到某一次提交状态,HEAD会处于游离状态git commit -am "注释" # 修改文件后需要提交,提交将不处于任何分支上git branch my_branch commit_id # 将该次提交绑定到新创建的分支上
4. 删除分支
不能删除当前所处分支
git branch -d new_branch # 只能删除已合并的分支git branch -D new_branch # 未合并的分支可以用此命令删除
5. 合并分支
git merge new_branch # 将分支new_branch合并到当前分支git merge --no-ff new_branch # 合并时禁用fast-forward
fast-forward模式进行分支合并时不会增加新的commit(直接用分支的commit) 如果出现冲突,需要手动修改文件
6. 分支重命名
git branch -m new_branch dev
版本回退
1. 回退到上一版本
git reset --hard HEAD^ # 回退到上一版本git reset --hard HEAD^^ # 回退到上一版本的上一版本git reset --hard HEAD~n # 回退到第n个版本
2. 进入任何版本
git reflog # 获取所有的commit_id(git log只会显示当前的commit_id)git reset --hard commit_id # 进入任一版本
3. 保存当前分支的状态
git stash # 保存当前分支的状态git stash save "注释" # 保存当前分支的状态,并添加注释git stash list # 显示所有保存的状态git stash pop # 恢复上一个状态,并删除保存的状态git stash apply # 应用上一个状态,不删除保存的状态git stash apply stash@{n} # 应用第n个状态,不删除保存的状态
标签管理
1. 创建标签
git tag v1.0 # 轻量级标签git tag -a v1.0 -m "注释" # 带有备注的标签
2. 查看标签
git taggit show v1.0
3. 查找标签
git tag -l "v1.0"git tag -l "*2"git tag -l "v*"
4. 删除标签
git tag -d v1.0
5. 标签推送到远程
git push默认不会推送标签
git push origin v1.0git push origin v2.0 v3.0 # 推送多个标签git push origin --tags # 一次性全部推送到远程
6. 标签拉取到本地
git pull会拉取标签
7. 删除远程标签
# 方式一git push origin :refs/tags/v6.0# 方式二git push origin --delete tag v5.0# 以上两种方法执行git pull操作后都不会影响本地已有标签
差异比较
1. linux内置diff
diff a b # 比较文件a、b的区别diff -u a b #
2. 暂存区与工作区之间的差别
git diff # 暂存区为原文件,工作区为目标文件
3. 版本库与工作区之间的差别
git diff HEAD # 比较最新提交与工作区之间的差别git diff commit_id # 比较指定提交与工作区之间的差别
4. 版本库与暂存区之间的差别
git diff --cached # 比较最新提交与版本库之间的差别git diff --cached commit_id # 比较指定提交与暂存区之间的差别
远程与GitHub
基于Git分支的开发模型
- develop分支:用于开发者进行开发,频繁变化
- test分支:供测试与产品人员使用的一个分支,变换不是特别频繁
- master分支:用于生产发布,变换非常不频繁
- bugfix分支:用于紧急修复bug
1. 概念
- push:推送> git push完整写法:
git push origin src:dest
- pull:拉取,同时会执行合并。pull == fetch + merge> git pull完整写法:
git pull origin src:dest
2. 注册GitHub
3. 已有仓库关联GitHub
使用HTTPS方式(不推荐)```shell git remote add origin https://github.com/LoveShes/gitlecture.git # 将origin指代远程地址 git push -u origin master # 将本地当前分支与远程master分支关联
输入GitHub的用户名和密码
```
使用SSH方式【推荐】```shell
1.首先在本地生成密钥对
ssh-keygen # 在~/.ssh/目录生成密钥对
2.将id_rsa.pub内的内容添加到GitHub中(仓库级别或者账户级别)
仓库 -> Settings -> Deploy keys -> Add deploy key,并勾选Allow write access
3.进行关联
git remote add origin git@github.com:LoveShes/gitlecture.git git push -u origin master
> 如果设置公钥后每次push还需要输入用户名和密码,可以使用下面的命令缓存账户信息:> ```shellgit config credential.helper store
4. 推送到远程分支
git push# push有两种模式git config --global push.default matching # 推送到远程同名分支git config --global push.default simple # 推送到用于更新本地分支的远程远程分支
5. 查看远程信息
git remote show origin # 查看远程仓库信息git branch -av # 查看所有分支(包括远程分支)信息,显示缩略commit_id和注释
6. 本地分支管理远程分支
远程没有同名分支时,直接push会报错
shell git push --set-upstream origin develop # 远程创建同名分支,并推送过去另一个开发者获取develop分支
shell git pull # 拉取所有分支 git checkout -b develop origin/develop # 创建本地develop分支,并关联远程分支 git checkout --track origin/develop # # 创建本地同名分支,并关联远程分支
7. 删除远程分支
# 第一种方法git push origin :develop # 删除远程develop分支# 第二种方法git push origin --delete develop
8. 本地分支与远程分支不同名
git push --set-upstream origin HEAD:develop2 # 远程创建develop2分支,并将当前分支推送过去
远程协作
1. 克隆仓库
# 将远程仓库所有分支拉取到本地,默认进入master分支,以远程仓库名作为本地仓库名git clone git@github.com:LoveShes/gitlecture.git# 克隆仓库,以mygit2作为本地仓库名git clone git@github.com:LoveShes/gitlecture.git mygit2# 修改user.name和user.email为当前用户git config --local user.name "vMayuyu"git config --local user.email "vMayuyu@qq.com"
2. 推送仓库
git remote show origin # 显示远程仓库信息git pull # push之前需要先pull远程仓库# --------- pull == fetch + merge --------- #git fetchgit merge origin/master# ----------------------------------------- #git push # 推送到远程# 如果发生冲突# 1.手动修改冲突文件# 2.提示系统解决了冲突git add filename# 3.提交git commit -m "注释"
Git图形界面
1. gitk
apt install gitk # 安装gitkgitk # 启动gitk
2. git gui
apt install git-gui # 安装git guigit gui # 启动git gui
3. GitHub Desktop
官网下载安装,不包含Linux版本
Git 高级应用
1. Git refspec
.git/refs/下的文件里面都对应着commit ID,refs目录结构如下:
refs/├─ heads│ ├── master (内容为commit ID)│ └── ...├─ remotes│ ├──master (内容为commit ID)│ └── ...└─ tags├── v1.0 (内容为commit ID)└── ...
2. Git gc
执行git gc后,refs文件夹下的内容会被压缩到packed-refs文件夹下。
object/pack目录:idx文件、pack文件、压缩之后的索引。
实际开发用的较少
3. Git 裸库
不包含工作区的库,在文件夹内使用命令git init --bare创建。
4. Git submodule
4.1 创建项目
用于在一个项目内引用另一个项目,仅能将子模块中的更改同步到父模块,不支持双向更改。
先在GitHub上创建2个项目,git_parent与git_child,再在本地执行如下操作:
# git_parent项目mkdir git_parent && cd git_parentgit initgit config --local user.name '张三'git config --local user.email 'zhang@qq.com'echo 'parent' >> parent.txtgit add .git commit -m 'initial commmit'git remote add origin git@github.com:LoveShes/git_parent.gitgit remote show origin # 显示远程分支信息git push --set-upstream origin master
# git_child项目mkdir git_child && cd git_childgit initgit config --local user.name '李四'git config --local user.email 'li@qq.com'echo 'child' >> child.txtgit add .git commit -m 'initial commmit'git remote add origin git@github.com:LoveShes/git_child.gitgit remote show origin # 显示远程分支信息git push --set-upstream origin masterecho 'hello' >> hello.txtgit add hello.txtgit commit -m 'add hello.txt'git push
再在git_parent项目中执行submodule操作
git submodule add git@github.com:LoveShes/git_child.git mymodule # mymodule之前不能存在git add .git commit -m 'add submodule'git push
4.2 更新单个子模块
cd mymodule # 进入子模块目录git pull
4.3 更新所有子模块
# 需在父模块中执行git submodule foreach git pull
4.4 克隆包含子模块的父模块
# 手动克隆子模块git clone git@github.com:LoveShes/git_parent.git git_parent2git submodule initgit submodule update --recursive# 自动克隆子模块git clone git@github.com:LoveShes/git_parent.git git_parent3 --recursive
4.5 删除子模块
git rm --cached mymodulerm -rf mymodulerm .gitmodulesgit add .git commit -m 'remove submodule'git push
4. Git subtree
在父项目中可以双向修改子项目的内容,推荐使用
4.1 创建项目
先在GitHub上创建2个项目,git_subtree_parent与git_subtree_child,再在本地执行如下操作:
# git_subtree_parent项目mkdir git_subtree_parent && cd git_subtree_parentgit initgit config --local user.name '张三'git config --local user.email 'zhang@qq.com'echo 'parent' >> parent.txtgit add .git commit -m 'initial commmit'git remote add origin git@github.com:LoveShes/git_subtree_parent.gitgit remote show origin # 显示远程分支信息git push --set-upstream origin master
# git_subtree_child项目mkdir git_subtree_child && cd git_subtree_childgit initgit config --local user.name '李四'git config --local user.email 'li@qq.com'echo 'child' >> child.txtgit add .git commit -m 'initial commmit'git remote add origin git@github.com:LoveShes/git_subtree_child.gitgit remote show origin # 显示远程分支信息git push --set-upstream origin master
再在git_subtree_parent项目中执行subtree操作:
# 关联远程子项目
git remote add subtree-origin git@github.com:LoveShes/git_subtree_child.git
# 添加远程子项目
git subtree add --prefix=subtree subtree-origin master --squash
# 注意,squash参数会合并远程提交历史成一次再拉取到本地
# squash参数要么不使用,要么一直使用
git push
4.2 更新单个子模块
git subtree pull --prefix=subtree subtree-origin master --squash
git push
4.3 在父项目中更改子模块并推送到子模块
git subtree push --prefix=subtree subtree-origin master --squash
git submodule与git subtree
- git submodule会在当前目录下建立一个指向子项目的指针,可以更新所有子模块。
- git subtree会在当前目录下建立一个包含完整子项目的文件夹,只能一个一个更新。
但是,两者在本地都会建立一个完整的文件夹。
5. Git cherry-pick
5.1 将当前分支上的修改复制到其它分支上
# 之前在其它分支上开发,先切换到master分支上
git checkout master
git cherry-pick <commitID>
# 注意,跳过中间的提交需要手动解决冲突
5.2 删除当前分支上的一些修改
git checkout <commitID>
git branch -D develop # 强制删除develop分支
git checkout -b develop # 基于当前commitID创建新的develop分支
6. Git rebase
用于改变分支的根基,功能与merge相似,但工作方式不同
6.1 变基
git checkout develop # 切换到develop分支
git rebase master # 将develop分支分支的基础变为master
执行之后会修改提交历史,整个commit会变成一条直线
6.2 解决冲突
出现冲突后,手动解决冲突,使用git add添加后,执行
git rebase --continue
6.3 终止rebase
git rebase --abort # 会恢复到rebase开始前的状态
注意,不要对master分支进行rebase操作,并且执行rebase操作的分支都应该是没有推送到远程的本地分支。
