这是我参与「第四届青训营 」笔记创作活动的第1天
一、创建仓库repository
仓库相当于一个目录,这个目录里的所有东西都可以被git管理起来,每个文件的修改、删除,git都能追踪,可以还原。
- 创建一个空目录(相当于请求内存空间,但是还没有内容)
$ mkdir learngit //创建一个名为learngit的空目录
$ cd learngit //change direction 切换到learngit目录(仓库)
$ pwd //显示当前目录
/Users/dengjieAir/learngit
- 第二步,通过git init命令把这个目录变成Git可以管理的仓库
vi readme.txt
写入该指令后,将进入编辑器编辑readme.txt文件,需要按i键进入编辑状态,编辑文件内容
$ git add readme.txt
添加成功后,将不会有任何显示
- 第三步,用命令 git commit 告诉git,把文件提交到仓库
$ git commit -m"wrote a readme file"
-m 后面输入的内容是本次提交的说明,可以输入任何内容,方便找到改动记录
{git commit}命令执行成功后会告诉你,{1 file changed}:一个文件被改动;{2 insertions}:插入了两行内容(readme.txt有两行内容)
二、对文件管理、修改
1、对文件修改和查看
修改readme.txt文件,改成如下内容:
Git is a distributed version control system.
Git is free software.
运行命令{ git status }查看当前目录的状态,通过输出结果可以看到,readme.txt 被修改过了。但是还没有准备提交的修改。 运行{ git diff }命令查看修改内容,输出结果可以看到,具体什么地方进行了修改了什么内容 当查看清楚后,对文件进行添加和提交
git commit -m"add distributed"
提交后,用{ git status }命令查看仓库内容,看到输出为(working tree clean)可知工作目录是干净的
小结
- 要随时掌握工作区的状态,使用{ git status }命令
- 如果{ git status } 告诉你文件有被修改,用{ git diff }可以查看修改内容
2、版本回退(恢复之前的文件)
对文件再进行一次修改,修改readme.txt文件如下:
Git is a distributed version control system.
Git is free software distributed under the GPL.
然后添加提交
$ git add readme.txt
$ git commit -m"append GPL"
查看以前提交的版本
使用{ git log }命令可以查看之前提交的三个版本,通过提交说明区别
最近的一次是{ append GPL},上一次是{ add distributed }, 最早的一次是{ wrote a readme file }
可以通过{ git log --pretty=oneline}来简化输出,将只会输出commit id(版本号) 和提交说明
回到以前的版本
{HEAD}表示当前版本,上一个版本是{HEAD^},上两个版本是{HEAD^^},上100个版本是{HEAD~100}
$ git reset --hard HEAD^
- 回退之后用{ cat }命令查看readme.txt的内容是不是版本{ add distributed}
$ cat readme.txt
Git is a distributed version control system
Git is free software
- 使用{ git log }命令发现只有两个版本了,最新的版本不见了,可以通过reset命令恢复未来的某个版本,在上面找到{ append GPL }版本的版本号{ commit id }是{ 1094abc...},
$ git reset --hard 1094a //写部分版本好就可以
HEAD is now at 82b0afe applend GPL
- 在通过cat查看readme.txt 内容
$ git readme.txt
Git is distributed version control system.
Git is free software distributed under the GPL
- 如果电脑关机,想找的已经回退的版本号,通过命令{ git reflog }用来记录我的每一次命令
$ git reflog
在输出中可以通过提交说明查找已经回退的版本号
小结
-
HEAD指向的版本是当前版本,因此Git允许我们在版本历史中穿梭,使用命令{ git reset --hard commit_id}
-
穿梭前,用{ git log }可以查看提交历史,以便确定要回退到哪个版本
-
要回去未来版本,用{ git reflog} 查看命令历史,以便确定要回到未来某个版本
3、工作区和暂存区
- 工作区(Working Directory) 就是在电脑中所能看见的目录,比如learngit文件夹就是一个工作区
- 版本库(Repository)
- 工作区中有一个隐藏目录{ .git },这不算工作区,而是Git的版本库 在版本库中,最重要的东西就是称为stage(或者index)的暂存区,还有Git为我们自动创建的第一个分支master,以及指向master 的一个名叫HEAD的指针
- 文件添加提交过程
- 第一步,用{ git add }把文件添加进去,实际上是将修改的文件添加到暂存区中
- 第二步,用{ git commit }提交修改,实际上是将暂存区的所有内容提交到当前的分支 当我们创建Git版本库的时候,Git自动为我们创建了唯一一个master分支,所以{ git commit }就是向master分支上面提交修改
4、撤销修改
撤销工作区
命令{ git checkout -- readme.txt }可以撤销在工作区中的全部修改,这里有两种情况:
- 一种是readme.txt自修改后还没有存放到暂存区,撤销后直接回到了和版本库一模一样的状态
- 一种是readme.txt已经添加到暂存区中,又做了修改,只能撤销到暂存区后的状态
撤销暂存区
命令{ git reset HEAD }可以将暂存区的修改撤销掉(unstage),重新放回工作区
$ git reset HEAD readme.txt
Unstaged changed after reset:
M. readme.txt
{ git reset }命令即可以回退版本,也可以将暂存区的修改回退到工作区,当用HEAD时,表示最新版本
使用 git status 查看一下,现在暂存区是干净的,工作区有修改
小结
- 撤销工作区的内容,用命令 { git checkout -- file }
- 想要撤销暂存区的内容,需要两步,先用命令{ git reset HEAD },回到了工作区,再用checkout撤销
- 当想要撤销已经提交到版本库的内容时,git reset --hard HEAD^回到上一个版本
5、删除文件
用 git rm 命令删除文件
$git rm test.txt
$git commit -m"remove test.txt"
删错之后恢复
git checkout -- test.txt
Git checkout 实际使用 版本库里面的版本去替换工作区的版本,无论工作区是修改还是删除都可以一键还原
三、远程仓库
1、本地内容推送到远程库
- 第一步,关联一个远程仓库
$ git remote add origin git@github.com:1171276417/learngit.git
其中origin为远程仓库名,learngit为我在github接收的仓库名
- 第二步,将本地库的所有内容推送到远程库上
$ git push -u origin master //远程库不为空则不需要-u参数
{ git push }命令会把本地的master分支和远程的master分支关联起来
- 删除远程库
$ git remote rm <name>
- 查看远程库
$ git remote -v
2、从远程库克隆到本地
- 使用{ git clone }命令克隆
$ git clone git@github.com:1171276417/abc.git
- 切换目录,查看文件
$ cd abc //切换到abc目录
$ ls //查看该目录的文件
四、分支管理
1、创建与合并分支
- 每次提交是一个节点,git将它们串成一条时间线,这条时间线是一个分支。目前只有一条分支,叫做主分支,即master分支,HEAD是指向master,master指向最新的提交,所以HEAD指向目前分支
每一次提交,master多一个节点,master分支就会向前走一步,越来越长
- 创建并切换一个新分支dev,Git新建了一个叫做dev的指针,新建分支时dev指向master指向的提交,即指向最新提交,再当时切换到了dev分支,所以HEAD指向当前分支dev
- 在dev分支上面进行一场添加提交,dev分支上将生成一个新节点往前一步,但是master分支不动,HEAD仍然指向最新的提交,即dev当前指向的节点
- 当dev分支的工作完成后,将master指向dev,即完成了分支的合并,master指向dev的最新提交,切换会master分支,HEAD也指向master
- 当分支合并完成后,可以将dev指针删除,只剩下master一条分支
- 命令
- 第一步,创建dev分支,并且切换到dev分支
$ git branch -b dev //-b参数表示创建并切换
//第一行包含两个指令,等价于下面两行
$ git branch dev //创建一个名为dev的分支
$ git checkout dev //切换到dev分支
- 然后可以查看当前分支,{ get banch }命令会列出所有分支,当前分支前面会标一个*号
$ git banch
*dev
master
- 对文件进行修改,在分支上面正常提交
- dev分支的工作完成后,切换回master主分支中
$ git checkout master
//等价于git switch -c dev
- 用{ git merge }命令将指定分支合并到当前分支
$ git merge dev
- 最后将dev分支删除
$ git branch -d dev
小结
- 查看分支:
git branch - 创建分支:
git branch <name> - 切换分支:
git checkout <name>或git switch <name> - 创建+切换分支:
git checkout -b <name>或者git switch -c <name> - 合并指定分支到当前分支:
git merge <name> - 删除分支:
git branch -d <name>
2、解决冲突
在分支上面对一个文件进行修改提交,切换到master分支上对同一个文件进行修改提交,如下
对这两个分支进行合并会造成冲突,git status可告诉我们冲突的文件
命令{ cat }可以查看文件的冲突具体内容,需要手动修改文件内容,再进行提交,合并完成
用带参数的
git log也可以看到分支的合并情况
$ git log --graph --pretty=oneline --abbrev-commit
最后删除feature1分支
$ git branch -d feature1
3、分支管理策略
合并分支时,如果可能git会使用Fast forward模式,但是在这种模式下,删除分支后,将会丢掉部分分支信息。
通常会强制禁用Fast forward模式,git就会在merge时生成一个新的commit,在分支历史上也可以看出分支信息。(--no-ff方式的git merge)
- 首先创建并切换到分支,在分支上面修改提交文件
- 然后切回
master,准备合并dev分支
$ git merge --no-ff -m "merge with no-ff" dev
Merge made by the 'recursive' strategy.
readme.txt | 1 +
1 file changed, 1 insertion(+)
因为这个合并同时也要commit,所以在-m参数后要加入commit的描述
merge后如图
4、Bug分支
每个bug都可以通过一个新的临时分支来修复,修复后,合并分支,然后将临时分支删除。
当你接到一个修复一个代号101的bug的任务时,你想创建一个分支issue-101来修复它,但是当前正在dev上进行的工作还没有提交,Git还提供了一个stash功能,可以把当前工作现场“储藏”起来,等以后恢复现场后继续工作
$ git stash
Saved working directory and index state WIP on dev: f52c633 add merge
- 首先确定要在哪个分支上修复bug,就从哪个分支创建临时分支:
$ git checkout master
$ git checkout -b issue-101
- 修复bug,将修复后的文件提交
$ git add readme.txt
$ git commit -m "fix bug 101"
- 修复完成后,切换到
master分支,并完成合并,最后删除issue-101分支:
$ git switch master
$ git merge --no-ff -m "merged bug fix 101" issue-101
-
最后接着回到
dev分支干活,并且恢复stash隐藏的内容 -
工作现场还在,Git把stash内容存在某个地方了,但是需要恢复一下,有两个办法:
- 一是用
git stash apply恢复,但是恢复后,stash内容并不删除,你需要用git stash drop来删除 - 另一种方式是用
git stash pop,恢复的同时把stash内容也删了
- 一是用
$ git switch dev
$ git status //工作区为空,已经被隐藏了
$ git stash list //查看隐藏区,内容在里面
$ git stash pop
$ git stash list //再查看隐藏区内容为空
你可以多次stash,恢复的时候,先用git stash list查看,然后恢复指定的stash,用命令:
$ git stash apply stash@{0}
-
在master分支上修复了bug后,dev分支是早期从master分支分出来的,这个bug在当前dev分支上也存在。同样的bug,要在dev上修复,我们只需要把
4c805e2 fix bug 101这个提交所做的修改“复制”到dev分支 -
Git专门提供了一个
cherry-pick命令,让我们能复制一个特定的提交到当前分支:
$ git branch
* dev
master
$ git cherry-pick 4c805e2
[master 1d4b803] fix bug 1011 file changed, 1 insertion(+), 1 deletion(-)
小结
- 修复bug,通过创建新的bug分支进行修复,然后合并,最后删除分支
- 暂时不能提交目前内容时,将工作现场
git stash隐藏,修复bug后,在git stash pop,回到工作现场 - master分支上面修复bug时,想要合并到当前分支,可以用
git cherry-pick <commit>命令,把bug提交的修改“复制”到当前分支
5、Feature分支
- 开发新功能 每一个功能,最好新建一个feature分支,在上面开发完成后合并,最好删除该feature分支
- 强行删除未合并分支
正常删除分支只能合并之后删除,如果删除,将丢失掉修改,如果要强行删除,需要使用大写的
-D参数
$ git branch -D feature
Deleted branch feature (was 287773e).
6、多人协作
查看远程库的信息,用git remote -v
$ git remote -v
origin git@github.com:michaelliao/learngit.git (fetch)
origin git@github.com:michaelliao/learngit.git (push
- 推送分支 把指定分支上的所有本地提交推送到远程库
$ git push origin dev
- 抓取通知
从远程库clone时,默认情况下只能看到本地的
master分支
要在dev分支上开发,就必须创建远程origin的dev分支到本地创建:
$ git checkout -b dev origin/dev
以在dev上继续修改,然后,时不时地把dev分支push到远程
- 结局冲突
别人已经向
origin/dev分支推送了他的提交,而碰巧你也对同样的文件作了修改,并试图推送
提交有冲突,先用git pull把最新的提交从origin/dev抓下来,然后,在本地合并,解决冲突,再推送
$ git pull
There is no tracking information for the current branch.
Please specify which branch you want to merge with.
See git-pull(1) for details.
git pull <remote> <branch>
If you wish to set tracking information for this branch you can do so with:
git branch --set-upstream-to=origin/<branch> dev
git pull失败,原因是没有指定本地dev分支与远程origin/dev分支的链接,根据提示,设置dev和origin/dev的链接:
$ git branch --set-upstream-to=origin/dev dev
Branch 'dev' set up to track remote branch 'dev' from 'origin'.
再pull:
$ git pull
git pull成功,但是合并有冲突,需要手动解决后,提交,再push:
工作模式
- 1、首先用
git push origin <branch-name>推送自己的修改 - 2、如果推送失败,则因为远程分支比你的本地更新,需要先用
git pull试图合并 如果git pull提示no tracking information,则说明本地分支和远程分支的链接关系没有创建,用命令git branch --set-upstream-to <branch-name> origin/<branch-name> - 3、如果合并有冲突,则解决冲突,并在本地提交
- 4、没有冲突或者解决掉冲突后,再用
git push origin <branch-name>推送
小结
-
查看远程库信息,使用
git remote -v -
从本地推送分支,使用
git push origin branch-name,如果推送失败,先用git pull抓取远程的新提交 -
在本地创建和远程分支对应的分支,使用
git checkout -b branch-name origin/branch-name,本地和远程分支的名称最好一致 -
建立本地分支和远程分支的关联,使用
git branch --set-upstream branch-name origin/branch-name -
从远程抓取分支,使用
git pull,如果有冲突,要先处理冲突
7、Rebase
把分叉的提交历史“整理”成一条直线,看上去更直观
输入命令git rebase
五、标签管理
- 目的 tag就是一个让人容易记住的有意义的名字,它跟某个commit绑在一起,它是指向某个commit的指针
1、创建标签
- 第一步,切换到需要打标签的分支上
$ git branch
* dev
master
$ git checkout master
Switched to branch 'master'
- 第二步,命令
git tag <name>就可以打一个新标签
$ git tag v1.0
创建带有说明的标签,用-a指定标签名,-m指定说明文字:
$ git tag -a v0.1 -m "version 0.1 released" 1094adb
命令git tag查看所有标签:
$ git tag
v1.0
- 对历史的某个提交打标签(默认对最新提交标签)需要找到历史提交的commit_id
$ git log --pretty=oneline --abbrev-commit //查找历史提交id
$ git tag v0.9 f52c633 //对id为f52c633的提交打v0.9标签
- 查看标签信息
git show <tagname>
$ git show v0.9
小结
-
命令
git tag <tagname>用于新建一个标签,默认为HEAD,也可以指定一个commit id -
命令
git tag -a <tagname> -m "blablabla..."可以指定标签信息 -
命令
git tag可以查看所有标签
2、操作标签
- 推送标签到远程
- 推送某个标签
$ git push origin v1.0
- 一次性推送全部标签
$ git push origin --tags
- 删除标签
- 删除未推送到远程的标签
$ git tag -d v0.1
- 删除已经推送到远程的标签
- 首先从本地删除
$ git tag -d v0.9
Deleted tag 'v0.9' (was f52c633)
- 然后从远程删除,删除命令也是push
$ git push origin :refs/tags/v0.9
To github.com:michaelliao/learngit.git
- [deleted] v0.9