Git 关键知识点
一、输入用户名和密码
Git
安装完成后,选择要放置项目文件夹的目录,空白处右键选择 Git Bash here
,然后输入:
git config --global user.name "Your name"
git config --global user.email "email@example.com"
二、创建版本库
-
创建一个版本库
mkdir learngit # 创建一个项目文件夹 cd learngit pwd # 查看项目文件夹绝对路径 git init # 把当前目录变成 Git 可以管理的仓库
-
在当前项目文件夹里面创建一个
README.md
文件,并添加内容:Git is a version control system Git is a free software
-
把
md
文件提交到仓库git add README.md # 告诉 Git,把文件添加到仓库 git commit -m "worte a README file" # 告诉 Git,把文件提交到仓库 # 可以多次 git add 多个文件后,再 git commit
-
修改
README.md
文件Git is a distrbuted version control system Git is a free software
-
查看修改结果
git status # 查看仓库当前状态 git diff # 查看具体做了哪些修改
-
确定无误后提交修改后的文件,和之前步骤一样
git add README.md git status # 查看状态 git commit -m "add distributed" git status
-
再次修改
README.md
文件Git is a distributed version control system Git is a free software distributed under the GPL
-
尝试提交
git add README.md git commit -m "append GPL"
三、版本回退
-
回顾
README.md
文件一共有几个版本被提交到Git
仓库git log # 显示从最近到最远的提交日志 git log --pretty=oneline # 输出内容每一行前面的是 commit id,即版本号
-
把
README.md
回退到之前某一个版本的方法:-
Git
必须知道当前版本是哪个版本
HEAD # 当前版本 HEAD^ # 上一个版本 HEAD^^ # 上上一个版本 HEAD~100 # 往上100个版本
- 要让当前版本
append GPL
回退到上一个版本add distributed
git reset --hard HEAD^
- 查看
README.md
内容是否是版本add distributed
cat README.md
- 查看现在版本库的状态
git log
-
发现最新的版本
appeng GPL
没了,但是命令行窗口没关的话,往上翻看历史输入命令找到
append GPL
的commit id
,就可以回到最新的版本
git reset --hard 1094a # 版本号没必要写全,前几位就 OK
- 再次查看
README.md
内容
cat README.md
- 假如回退到了某个版本,而且电脑关机了,要恢复新版本的办法
git reflog # 记录每一次命令,然后从输出中可得知某个版本的 commit id
-
四、工作区和暂存区
-
Git
有暂存区的概念,而一开始创建的learngit
文件夹就是一个工作区另外,在该文件夹下的隐藏目录
.git
,是Git
的版本库git add # 实际上是把文件或修改过的文件添加到暂存区 git commit # 把暂存区的所有内容提交到当前分支
创建
Git
版本库时,Git
自动创建了唯一一个master
分支,所以git commit
就是往master
分支上提交更改
-
对
README.md
再次修改:Git is a distributed version control system Git is a free software distributed under the GPL Git has a mutable index called stage
然后在工作区新增一个
LICENSE
文件,内容随便写,然后查看状态git status # 看结果可知,Git 非常清楚显示 README.md 被修改了,而 LICENSE 还没被添加过,即 Untracked
把两个文件都添加到暂存区,再查看状态,最后提交到当前分支
git add README.md git add LICENSE git status git commit -m "understand how stage works" git status
五、管理修改
-
Git
跟踪管理的都是修改,而非文件—无论是增删改文件内容- 往
README.md
内添加一行内容:
Git tracks changes
- 查看该文件是否添加了以上内容,然后添加到仓库暂存区
cat README.md git add README.md git status
- 再次修改该文件,把最后一行改为:
Git tracks changes of files
- 提交到仓库中并查看状态
git commit -m "git tracks changes" git status
这时发现第二次修改没有被提交,先回顾操作过程:
第一次修改 --->
git add
---> 第二次修改 --->git commit
记住,
Git
管理的是修改,使用git add
命令后,在工作区的第一次修改被放入暂存区,准备提交但是,在工作区的第二次修改并没有放入暂存区,所以
git commit
只负责把暂存区的修改提交提交后,可以查看工作区和版本库最新版本的区别:
git diff HEAD -- README.md # 可见第二次修改没有被提交
为了能够提交第二次修改,应该这样:
第一次修改 --->
git add
---> 第二次修改 --->git add
--->git commit
- 往
六、撤销修改
-
比如在
README.md
中添加了一行:My stupid boss still prefers SVN
a. 如果是提交之前,可以手动删除,然后查看一下状态:
git status
这时
Git
会提示可以丢弃工作区的修改git checkout -- README.md # 把该文件在工作区的修改全部撤销 # 该命令的使用有两种情况: # 1. 该文件自修改后还没被放到暂存区,那么撤销修改就回到和版本库一模一样的状态 # 2. 该文件已经添加到暂存区,又做了修改,现在撤销修改就回到添加到暂存区后的状态 # 总之就是让这个文件回到最近一次 git commit 或 git add 的状态 # 再次查看该文件内容,发现文件内容果然复原了 cat README.md # 另外,这里的 -- 很重要,没有 -- ,就变成了"切换到另一个分支"的命令
b. 如果之前添加那一行后,还 git add
到暂存区了,但还没 commit
先查看状态:
git status # 显示只添加到了暂存区,还没提交
这时候可以用命令将暂存区的修改撤销,重新放回工作区:
git reset HEAD README.md
# 由此发现 git reset 既可以回退版本,也可以把暂存区修改回退到工作区
# 这里用 HEAD,表示最新的版本
git status
接着就要丢弃工作区的修改了:
git checkout -- README.md
git status
c. 如果直接提交了不合适的修改到版本库时,想要撤销本次提交,就要使用版本回退功能了
不过有个前提:没有推送到远程库!
七、删除文件
-
先新建一个
test.txt
文件到Git
并且提交一下,然后又删除它:touch test.txt git add test.txt git commit -m "add test.txt" rm test.txt git status
这个时候,
Git
知道删除了文件,但是工作区和版本库不一致了现在有两个操作选择:
- 确实要从版本库中删除该文件
git rm test.txt git commit -m "remove test.txt" git status # 当然,手动删除文件,然后使用上面的方法效果一样
- 删错了,但是在版本库里还有文件,因此可以把误删的文件恢复到最新版本:
git checkout -- test.txt # git checkout 其实是版本库里的版本替换工作区的版本,工作区的修改或删除都可以被它还原
注意:虽然
git rm
用于删除文件,只要已经提交到了版本库,不用担心误删。 但是,只能恢复文件到最新版本,会丢失最近一次提交后修改的内容
八、远程仓库
-
建立远程仓库
-
先注册
GitHub
账号,然后创建SSH key
:ssh-keygen -t rsa -C "邮箱地址" # 一直按回车键即可 C:\Users\Shawn_Huang\.ssh # 找到 id_rsa.pub 文件,打开并复制该文件的所有内容
登录
GitHub
,打开Account settings
,在SSH key
页面点击Add SSH key
然后在
Key
文本框里粘贴刚才复制的内容,点击Add key
即可到目前为止,已经在本地创建了一个
Git
仓库这时要在
GitHub
里创建一个Git
仓库,并且让这两个仓库进行远程同步这样,
GitHub
上的仓库既可以作为备份,又可以让其他人通过该仓库来协作首先,登录后,创建一个新的仓库,在右上角
+
号选择New repository
在
Repository name
输入learngit
, 然后直接点击Create repository
即可-
然后,开始将本地仓库内容推送到
GitHub
仓库:git remote add origin git@github.com:shawnhuang90s/learngit.git # 关联远程仓库 git push -u origin master # 将本地库所有内容推送到远程库中,过程中有提示,输入 yes
-
-
从远程库克隆
目前为止的所有操作,都是先有本地库,后有远程库的时候,关联远程库的方法
其实最好的方式是先创建远程库,然后从远程库克隆
创建一个新的仓库,命名
gitskills
,同时勾选Initialize this repository with a README
-
远程库已经建立,用命令克隆一个本地库:
git clone git@github.com:shawnhuang90s/gitskills.git # 也可以使用 https 开头的网址,但速度慢,而且每次推送都必须输入口令 cd gitskills ls
九、分支管理
-
创建分支的作用:
- 在分支上工作,别人看不到,想提交就提交,直到开发完毕,再一次性合并到原来的分支上
- 这样做的好处是既安全,又不影响别人工作
创建与合并分支
前面所学 版本回退 时,每次提交,
Git
都把它们串成一条时间线,这条时间线就是分支目前为止,这个分支其实就是
master
分支,也是主分支严格来说,
HEAD
不是指向提交,是指向master
,而master
才是指向提交的-
创建分支的具体命令:
git checkout -b dev # 表示创建并切换到某个分支,相当于以下两条命令的合并 # git branch dev # git checkout dev git branch # 查看当前分支,会列出所有分支,当前分支前面标一个 * 号
- 对
README.md
做个修改,加一行:
Creating a new branch is quick # 这里注意是项目 gitskills 内的 README.md
- 将该文件提交:
git add README.md git commit -m "branch test"
- 现在,
dev
分支的工作完成,切换到master
分支:
git checkout master cat README.md # 发现在该文件中添加的内容并没有显示出来,因为提交是发生在 dev 分支上
- 把
dev
分支合并到master
分支上:
git merge dev # 注意显示结果中的 Fast-forward,表示这次合并是快进模式,速度非常快 cat README.md # 这时在 master 分支上查看这个文件就能看到添加的内容了 git branch -d dev # 合并后就可以把 dev 这个分支删除了 git branch # 查看所有分支,发现只有 master 分支了 # 创建、合并和删除分支速度都很快,Git 鼓励使用分支完成某个任务,合并后再删掉分支 # 这和直接在 master 分支上工作效果一样,但是过程更安全
- 对
-
解决冲突
合并分支有时候会有冲突,比如:
-
创建一个新的分支
feature1
:git checkout -b feature1
-
把
README.md
的内容改为:Creating a new branch is quick AND simple
-
在
feature1
分支上提交:git add README.md
-
切换到
master
分支:git checkout master # 提示当前 master 分支会比远程分支 origin/master 超前一个提交
-
再次把
README.md
文件修改:Creating a new branch is quick & simple
-
提交到
master
上:git add README.md git commit -m "& simple"
-
现在的情况是
feature1
分支和master
分支上都对README.md
文件进行了修改这样
Git
无法执行快速合并,一合并就很有可能发生冲突:git merge feature1 # 提示该文件存在冲突,必须手动解决冲突后再提交 git status # 这个命令也会提示该文件有冲突 cat README.md # 查看该文件
Git用
<<<<<<<
,=======
,>>>>>>>
标记出不同分支的内容,如下修改该文件后保存 :Creating a new branch is quick and simple
-
再次提交:
git add README.md git commit -m "conflict fixed" git log --graph --pretty=oneline --abbrev-commit # 查看分支合并情况
-
删除
feature1
分支:git branch -d feature1 git branch
-
-
分支管理策略
通常合并分支时,
Git
会用Fast forward
模式,但是删除分支后,会丢掉分支信息当强制禁用
Fast forward
模式,Git
会在merge
时生成一个新的commit
,这样从分支历史上可以看出分支信息。示例如下:-
创建并切换
dev
分支:git checkout -b dev
-
修改
README.md
文件,然后提交一个新的commit
:git add README.md git commit -m "add merge"
-
切回
master
并合并两个分支,然后查看分支历史:git checkout master git merge --no-ff -m "merge with no-ff" dev # 本次合并要创建一个新的 commit,因此加了 -m 参数 git log --graph --pretty=oneline --abbrev-commit
-
实际开发中,
master
分支应该是非常稳定的,仅用来发布新版本而分支
dev
不稳定,因为一般工作都在dev
上,到某个版本发布的时候,才把dev
分支合并到master
上一般团队在每个人都有自己的分支,时不时往
dev
分支上合并内容
-
Bug 分支
假设在
dev
分支进行的工作还没提交,这时候又要修复一个代号 101 的bug
任务-
这时可以先把当前工作内容储存起来:
git stash git status
-
然后确定在哪个分支上修复
bug
,比如要在master
上修复,就在该分支创建分支:git checkout master git checkout -b issue-101
-
比如这个
bug
是要修改README.md
文件某行内容,修改好后,提交:git add README.md git commit -m "fix bug 101"
-
切换到
master
分支,完成合并,然后删除该临时分支:git checkout master git merge --no-ff -m "merged bug fix 101" issue-101
-
接着回到
dev
分支上工作,先找到之前保存点,然后恢复过来:git checkout dev # 切换到 dev 分支 git status # 查看状态 git stash list # 查看之前保存的内容在哪 # 恢复方法一 git stash apply git stash drop # 恢复方法二 git stash pop git stash list # 查看 stash 内容有没有清掉 # 可以多次 stash,恢复时先查看,再恢复指定的 stash git stash list git stash apply stash@{0}
-
Feature 分支
软件开发中,要添加一个新的功能,新建一个
feature
分支,开发完成后合并再删除分支-
比如开发代号为
Vulcan
的新功能,可以这样做:git checkout -b feature-vulcan git add vulcan.py git status git commit -m "add feature vulcan" git checkout dev
-
这时如果又要取消该功能,那么包含这个功能的分支就必须销毁:
git branch -d feature-vulcan # 提示 feature-vulcan 分支还没合并,如果删除,将丢失掉修改 # 如果要强行删除,需要使用大写的 -D 参数 git branch -D feature-vulcan
-
多人协作
当从远程仓库克隆时,
Git
自动把本地的master
分支和远程的master
分支对应-
远程仓库的默认名称是
origin
:git remote # origin git remote -v # 显示更详细的信息 # origin git@github.com:shawnhuang90s/learngit.git (fetch) # origin git@github.com:shawnhuang90s/learngit.git (push) # 如果没有推送权限,就看不到 push 地址
-
推送分支—即把该分支上的所有本地提交推送到远程库
推送时,要指定本地分支,
Git
会把该分支推送到远程库对应的远程分支git push origin master # 注意,origin 是远程库名,master 是本地分支名 git push origin dev # 如果要推送 dev 分支,就改一下
-
并不是要把本地所有分支都推送到远程库,看具体情况:
-
master
分支是主分支,因此需要时刻与远程同步 -
dev
分支是开发分支,团队所有成员都需要在上面工作,所以也需要与远程同步 -
bug
分支只用于在本地修复bug
,没必要推送到远程库,除非上级要看修复了多少 -
feature
分支是否推送,取决于是否和团队成员合作在上面开发
-
-
抓取分支
多人协作时,团队成员都会往
master
和dev
分支上推送各自的修改现在模拟一下:
# 模拟团队成员,在自己电脑另一个目录下克隆: git init # 这个命令不能丢 git clone git@github.com:shawnhuang90s/learngit.git git branch # 默认情况,别人克隆后只能看到本地的 master 分支 git checkout -b dev origin/dev # 要在 dev 分支开发,就必须这样 touch test.md # 创建一个文件并添加一些内容 git add test.md git commit -m "add test" git push origin dev # 现在如果自己也对同样的文件做了修改,并视图推送: cat test.md git add test.txt git commit -m "add new test" git push origin dev # 提示推送失败,有冲突,按照提示进行下一步 git pull git branch --set-upstream-to=origin/dev dev git pull # 合并成功,但是又有冲突,解决方法和分支管理的解决冲突一样 git commit -m "fix env conflict" git push origin dev
-
总结—多人协作的工作模式处理流程:
首先,用
git push origin <branch-name>
推送自己的修改如果推送失败,是因为远程分支比自己的本地更新,需要先用
git pull
合并如果合并后有冲突,则先解决冲突,并在本地提交
解决之后,再用
git push origin <branch-name>
推送就能成功-
PS:如果
git pull
提示no tracking information
,说明本地分支和远程分支没关联 用命令
git branch --set-upstream-to <branch-name> origin/<branch-name>
-
rebase 操作
git rebase git log
-
rebase
可以把本地未push
的分叉提交历史整理成直线 - ·
rebase
的目的是在查看历史提交的变化时更容易,因为分叉的提交需要三方对比
-
十、标签管理
-
发布一个版本时,通常先在版本库中打一个标签,唯一确定了打标签时刻的版本
将来随时取某个标签的版本,就能把对应的历史版本取出来,因此标签也是版本库的一个快照
实际上标签是指向某个
commit
的指针,跟某个commit
绑定在一起注意标签跟分支不一样,分支可以移动,标签不能,标签的创建和删除都是瞬间完成的
-
创建标签
git branch # 查看所有分支 git checkout master # 切换到需要打标签的分支 git tag v0.7 # 打标签 git tag # 查看所有标签
- 默认标签是打在最新提交的
commit
上,如果在某个commit
忘了打标签,方法如下:
git log --pretty=oneline --abbrev-commit # 先找到历史提交的 commit id git tag v0.2 5010255 # 给对应的 commit 打标签 git tag
- 标签不是按时间顺序列出的,而是按字母排序的
git show v0.7
- 创建带有说明的标签,
-a
指定标签名,-m
指定说明文字
git tag -a v0.3 -m "version 0.3 released" eb48d19 # 前提是标签第一次打,已有的不行 git tag git show v0.3
- 注意:标签总是和某个
commit
挂钩,如果这个commit
既出现在master
分支,又出现在dev
分支,那么在这两个分支上都能看到这个标签
- 默认标签是打在最新提交的
-
操作标签
-
如果标签打错了,可以删除,因为创建的标签只存储在本地,不会自动推送到远程库
git tag -d v0.1
-
推送某个标签到远程
git push origin v1.0 git push origin --tags # 一次性推送全部尚未推送到远程的本地标签
-
删除已经推送到远程库的标签
git tag -d v0.9 # 先删除本地标签 git push origin:refs/tags/v0.9 # 再删除远程标签
-
十一、自定义 Git
-
让
Git
显示颜色git config --global color.ui true
-
忽略特殊文件
有时必须把某些文件放到
Git
工作目录中,但不能提交,比如保存了数据库密码的配置文件-
解决办法:在
Git
工作区的根目录下创建一个特殊的.gitignore
文件然后把要忽略的文件名填进去,
Git
就会自动忽略这些文件不需要从头写
.gitignore
文件,GitHub
已有各种配置文件,只需组合一下就行访问 配置文件
-
忽略文件的原则:
- 忽略操作系统自动生成的文件,比如缩略图等
- 忽略编译生成的中间文件、可执行文件等,也就是如果一个文件是通过另一个文件自动生成的,那自动生成的文件就没必要放进版本库,比如Java编译产生的
.class
文件 - 忽略你自己的带有敏感信息的配置文件,比如存放口令的配置文件
-
举例说明哪些要忽略:
# 在Windows下进行Python开发,Windows会自动在有图片的目录下生成隐藏的缩略图文件 # 如果有自定义目录,目录下就会有Desktop.ini文件 # 因此需要忽略Windows自动生成的垃圾文件: # Windows: Thumbs.db ehthumbs.db Desktop.ini # 忽略Python编译产生的.pyc、.pyo、dist等文件或目录 # Python: *.py[cod] *.so *.egg *.egg-info dist build # 忽略自定义的文件 # My configurations: db.ini deploy_key_rsa
-
提交
.gitignore
文件:git add .gitignore git commit -m "add .gitignore file" git status # 如果显示 working directory clean 表示提交成功
使用
Windows
开发时,如果在资源管理器中新建一个.gitignore
文件,会提示必须输入文件名,但是在文本编辑器里点击保存或者另存为,就可把文件保存为.gitignore
了-
有时候添加一个文件到
Git
时发现添加不了,因为被.gitignore
忽略了,可以强制添加:git add -f App.class # 或者找出在该文件到底哪个规则写错了,然后修订该规则 git check-ignore -v App.class
-
配置别名:
git config --global alias.st status # st 表示 status git config --global alias.co checkout # co 表示 checkout git config --global alias.ci commit # ci 表示 commit git config --global alias.br branch # br 表示 branch # 因为 --global 参数是全局参数,所以这些命令在这台电脑的所有 Git 仓库下都有用 git reset HEAD file # 表示把暂存区的修改撤销 git config --global alias.unstage 'reset HEAD' # unstage 表示 'reset HEAD' git unstage test.py # 使用别名示例 git reset HEAD test.py # 实际执行的语句 git config --global alias.last 'log -l' # 显示最后一次提交信息的别名 git last git config --global alias.lg "log --color --graph --pretty=format:'%Cred%h%Creset -%C(yellow)%d%Creset %s %Cgreen(%cr) %C(bold blue)<%an>%Creset' --abbrev-commit" # 显示 log 配置及历史信息
-
配置文件:
配置
Git
时,加上--global
是针对当前用户起作用,如果不加,只针对当前仓库起作用-
每个仓库的
Git
配置文件都放在.git/config
文件中:cat .git/config # 别名信息就在 [alias] 后面,要删除别名,直接把对应的行删掉即可
-
当前用户的
Git
配置文件放在用户主目录下的一个隐藏文件.gitconfig
中:cat .gitconfig # 配置别名也可以直接修改这个文件,如果改错了,可以删掉文件重新通过命令配置