Git的诞生,Git可以用来处理对文件的实时更新
- 结束手动管理多个"版本"的史前时代,进入到版本控制的20时代。
- 分布式版本控制系统,Github提供了Git存储,使得开源项目迁移到Github
- CVS和SVN都是集中式的版本控制系统,而Git是分布式版本控制系统
集中式和分布式管理系统
集中式管理系统:有一个中央服务器,每一次都需要从中央服务器去取版本,然后把结果返回到服务器
分布式管理系统:分布式就是每个电脑都是一个完整的版本库,每个人版本库可以进行复制,不用担心服务器停工的问题
分布式除了Git以及促进Git诞生的BitKeeper,还有类似Git的Mercurial和Bazaar
安装Git
- Git原来是在Linux上开发的
- 现在,Git可以在Linux,Unix,Mac和Windows上运行了
Window下载Git
-
1.从Git官网直接下载安装程序,然后选择默认安装即可
-
2.命令行输入
-
$git config --global user.name "Your Name" $git config --global user.email "email@example.com"
-
创建版本库
版本库可以理解为目录,这个目录的所有文件都被git管理,每个文件的修改,删除git都可以追踪,以便于追踪和还原
第一步 创建版本库
$mkdir learngit
$cd learngit
$pwd
/Users/michael/learngit
pwd命令用于当前目录。在我的Mac上,这个仓库位于/Users/michael/learngit
ps:Windows系统,确保目录名(包括父目录
)不包含中文
第二步 git init 命令把这个目录编程git可以管理的仓库
$git init
Initialized empty Git repository in /Users/michel/learngit/.git/
瞬间Git就把仓库建好了,并且多了.git文件,不要修改这个文件,否则Git仓库就被破坏了
时光机穿梭
修改操作
直接修改文件,可以通过git status来记录状态
$ git status
该指令可以让我们掌握当前状态,知道哪个被修改了
$ git diff readme.txt //这个可以看文件和之前有什么不同
丿剑来·@LAPTOP-3L4Q3T2K MINGW64 /e/tmpgit/tmpgit (master)
$ git add readme.txt
丿剑来·@LAPTOP-3L4Q3T2K MINGW64 /e/tmpgit/tmpgit (master)
$ git commit -m "add distributed"
[master (root-commit) b633e2d] add distributed
1 file changed, 1 insertion(+)
create mode 100644 readme.txt
丿剑来·@LAPTOP-3L4Q3T2K MINGW64 /e/tmpgit/tmpgit (master)
$ git status
On branch master
Commit的操作
1.$ git add readme.txt
2.$git commit -m "add contributed"
版本回退
git log
git log可以查看自己commit的操作
$ git log
commit 7d53bc0d1d14c7c57b659c742751bda3b3bed2e0 (HEAD -> master)
Author: 王浩鹏 <2682487588@qq.com>
Date: Sun May 30 10:53:55 2021 +0800
append.GPL
commit b633e2d60798e52b1e0dbbd035d7f51c7a6e8b40
Author: 王浩鹏 <2682487588@qq.com>
Date: Sun May 30 10:31:06 2021 +0800
回退到上一个版本 git reset
注意:^不能省略
$ git reset --head HEAD^
HEAD is now at 7d53bc0 append.GPL
然后查看文件 cat readme.txt
$ cat readme.txt
Git is a distributed version control system.
Git is a distributed version control system.
Git is free software distributed under the GPL.
- HEAD指向的版本就是当前版本,git reset --hard commit_id
- 穿梭前,用git log可以查看提交历史,一遍确定回退到哪个版本
- 重返未来可以用git reflog查看命令版本
工作区和暂存区
工作区
就是你电脑上能看到的目录,比如我的.git就是工作区
版本库
工作区有隐含目录.git,这个不是igongzuoqu1,ershi1
- 1.git add 把文件添加进去,实际上就是吧文件修改添加到暂存区
- 2.git commit提交更改,实际上就是把暂存区的所有内容提交到当前分支
我们创建Git版本库时,Git自动为我么你创建唯一一个Master分支,所以现在git commit就是向分支修改
Changes not staged for commit:
(use "git add <file>..." to update what will be committed)
(use "git restore <file>..." to discard changes in working directory)
modified: readme.txt
Untracked files:
(use "git add <file>..." to include in what will be committed)
LICENSE
no changes added to commit (use "git add" and/or "git commit -a")
Git告诉我们,readme.txt被修改,LICENSE未被添加
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-uK5OMK0o-1627270669737)(C:%5CUsers%5C%E4%B8%BF%E5%89%91%E6%9D%A5%C2%B7%5CAppData%5CRoaming%5CTypora%5Ctypora-user-images%5Cimage-20210530162420740.png)]
管理修改
什么是修改
你对文件的变动包括:增加,删除,甚至是创建都叫做修改
我们如果是这样的流程
第一次修改readme.txt->git add ->第二次修改->git commit
那么第二次修改的将不会被提交
因为第一次修改会通过add添加到暂存区里面
撤销修改 git checkout --file
$git checkout --readme.txt
这个命令是值吧readme.txt在工作区的文件全部撤销
两种情况:
1.readme.txt没有放在暂存区,现在,撤销修改就回到和版本库一模一样的状态
2.readme.txt已经添加到暂存区,又做了修改,现在撤销修改就回到添加到暂存区后的状态
点睛之笔:
总之,就是让这个文件回到最近一次git commit
或git add
时的状态。
删除文件
我们测试将新文件test.txt弄到Git并提交
然后$rm test.txt
删除之后用git status
$ git status
On branch master
Changes not staged for commit:
(use "git add/rm <file>..." to update what will be committed)
(use "git restore <file>..." to discard changes in working directory)
modified: readme.txt
deleted: test.txt
Untracked files:
(use "git add <file>..." to include in what will be committed)
LICENSE
no changes added to commit (use "git add" and/or "git commit -a")
远程仓库
实际情况:找一个电脑充当服务器的角色,每天24小时开机,其他每个人都从这个“服务器”仓库克隆一份到自己电脑上,并且各自把各自推送到服务器仓库,可以提交自己的推送,也可以拉别人的推送
Github提供git托管服务,只需注册一个GitHub账号,就可以免费获得Git远程仓库
注册SSH:
1.创建ssh key
$ ssh-keygen -t rsa -C "youremail@examlple.com"
如果顺利你可以在用户主目录找到.ssh ,里面有id_rsa和id_rsa.pub
2.登录Github,打开“Account settings”,“SSH Keys”页面:
然后,点“Add SSH Key”,填上任意Title,在Key文本框里粘贴id_rsa.pub
文件的内容:
点“Add Key”,你就应该看到已经添加的Key:
需要ssh key的原因,因为要确定你的提交时你推送的,
添加远程仓库
点击右上角new repository
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-UbhpVpo3-1627270669745)(C:%5CUsers%5C%E4%B8%BF%E5%89%91%E6%9D%A5%C2%B7%5CAppData%5CRoaming%5CTypora%5Ctypora-user-images%5Cimage-20210531155300317.png)]
填入名字,然后点create
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-vM8mCg1q-1627270669747)(C:%5CUsers%5C%E4%B8%BF%E5%89%91%E6%9D%A5%C2%B7%5CAppData%5CRoaming%5CTypora%5Ctypora-user-images%5Cimage-20210530180555269.png)]
目前这个仓库还是空的,Github告诉我们,可以从这个仓库克隆出新的仓库,也可以将本地仓库与之相关联
$ git remote add origin git@github.com:2682487588/tmpgit.git
千万注意2682487588一定要换成自己的GitHub的账号名,因为这和你SSH的公钥配置有关
下一步,就可以把版本库的所有内容推送到远程库上
这里推送的2682487588是你的github账号
fyyzy.git是你的github仓库
丿剑来·@LAPTOP-3L4Q3T2K MINGW64 /e/mygit/tmpgit (master)
$ git remote rm origin
丿剑来·@LAPTOP-3L4Q3T2K MINGW64 /e/mygit/tmpgit (master)
$ git remote add origin git@github.com:2682487588/fyyzy.git
丿剑来·@LAPTOP-3L4Q3T2K MINGW64 /e/mygit/tmpgit (master)
$ git push -u origin master
Enumerating objects: 12, done.
Counting objects: 100% (12/12), done.
Delta compression using up to 8 threads
Compressing objects: 100% (7/7), done.
Writing objects: 100% (12/12), 1.03 KiB | 352.00 KiB/s, done.
Total 12 (delta 1), reused 0 (delta 0), pack-reused 0
remote: Resolving deltas: 100% (1/1), done.
To github.com:2682487588/fyyzy.git
* [new branch] master -> master
Branch 'master' set up to track remote branch 'master' from 'origin'.
推送用git push指令,实际是吧当前分支master推送到远程仓库
从远程库克隆
上次我们讲了先有本地库,后有远程库的时候,如何关联远程库。
现在,假设我们从零开发,那么最好的方式是先创建远程库,然后,从远程库克隆。
首先,登陆GitHub,创建一个新的仓库,名字叫gitskills
:
我们勾选Initialize this repository with a README
,这样GitHub会自动为我们创建一个README.md
文件。创建完毕后,可以看到README.md
文件:
现在,远程库已经准备好了,下一步是用命令git clone
克隆一个本地库:
$ git clone git@github.com:2682487588/gitskill.git
Cloning into 'gitskill'...
remote: Enumerating objects: 3, done.
remote: Counting objects: 100% (3/3), done.
remote: Total 3 (delta 0), reused 0 (delta 0), pack-reused 0
Receiving objects: 100% (3/3), done.
注意把Git库的地址换成你自己的,然后进入gitskills
目录看看,已经有README.md
文件了:
丿剑来·@LAPTOP-3L4Q3T2K MINGW64 /e/mygit/tmpgit (master)
$ cd gitskill
丿剑来·@LAPTOP-3L4Q3T2K MINGW64 /e/mygit/tmpgit/gitskill (main)
$ ls
README.md
分支管理
分支:
分支可以解决代码未写完时,提交给正在写的同事带来的不便或者是自己未提交,面临的极大风险
Head指向的是当前分支,只有Master才指向主分支
原来的情况是提交一次Master指针前移,Git中新创建了dev指针.当新提交一次,dev指针前移
那Git怎么合并呢,就是直接把master
指向dev
的当前提交,就完成了合并
合并完分支后,甚至可以删除dev
分支。删除dev
分支就是把dev
指针给删掉,删掉后,我们就剩下了一条master
分支:
实战:
首先,我们创建dev
分支,然后切换到dev
分支:
$ git checkout -b dev
Switched to a new branch 'dev'
git checkout 命令加上-b参数表示创建并切换
$ git branch dev
$ git checkout dev
Switched to branch 'dev'
然后,用git branch命令查看当前分支
$ git branch
*dev
master
然后修改readme.txt
Creating a new branch is quick.
然后提交:
$ git add readme.txt
$ git commit -m "branch.test"
[dev 76f4e06] branch.test
1 file changed, 1 insertion(+), 3 deletions(-)
然后切换到master分支
$ git checkout master
Switched to branch 'master'
D test.txt
切换回master
分支后,再查看一个readme.txt
文件,刚才添加的内容不见了!因为那个提交是在dev
分支上,而master
分支此刻的提交点并没有变:
接下来我们把dev分支的工作合并到master分支上
$ git merge dev
Updating 5af4d8e..76f4e06
Fast-forward
readme.txt | 4 +---
1 file changed, 1 insertion(+), 3 deletions(-)
这时候就可以删除dev
$ git branch -d dev
解决冲突
1.git 切换到feature分支
$ git switch -c feature
Switched to a new branch 'feature'
2.查看分支
$ git branch
* feature
master
3.先修改txt文件然后添加到暂存区
$ git add readme.txt
4.提交分支
$ git commit -m "simple"
[feature 668c81c] simple
1 file changed, 3 insertions(+), 1 deletion(-)
5.切换到master
$ git switch master
Switched to branch 'master'
D test.txt
Your branch is ahead of 'origin/master' by 1 commit.
(use "git push" to publish your local commits)
6.再次修改文件添加到暂存区
$ git add readme.txt
7.提交
$ git commit -m "newmaster"
[master 6ad8c06] newmaster
1 file changed, 4 insertions(+), 1 deletion(-)
8.两个分支都有修改,这个时候就起了冲突
$ git merge feature
Auto-merging readme.txt
CONFLICT (content): Merge conflict in readme.txt
Automatic merge failed; fix conflicts and then commit the result.
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
Changes not staged for commit:
(use "git add/rm <file>..." to update what will be committed)
(use "git restore <file>..." to discard changes in working directory)
deleted: test.txt
Untracked files:
(use "git add <file>..." to include in what will be committed)
LICENSE
gitskill/
no changes added to commit (use "git add" and/or "git commit -a")
此时readme.txt内容
Git is a distributed version control system.
Git is best language.
Ai ya wang zhe xiong kou pai yi pai ya yong gan zhan qi lai
<<<<<<< HEAD
zhe shi master fenzhi
=======
This branch fenzhi
>>>>>>> feature
现在如果我们再master的基础上再修改readme.txt
$ git add readme.txt
$ git commit -m "conflict fixed"
[master cf810e4] conflict fixed
现在分支变成了如下图
git log也可以查看到分支的状况
* b58d576 (HEAD -> master) conflict fixed
|\
| * 668c81c (feature) simple
* | 6ad8c06 newmaster
|/
* 76f4e06 branch.test
* 5af4d8e (origin/master) mytest
* 73eacdb sanshisui
* 6485209 woshifw
* b633e2d add distributed
最后,删除feature分支
$ git branch -d feature
Deleted branch feature (was 668c81c).
当Git无法自动合并分支时,就必须首先解决冲突。解决冲突后,再提交,合并完成。
解决冲突就是把Git合并失败的文件手动编辑为我们希望的内容,再提交。
用git log --graph
命令可以看到分支合并图。
分支管理策略
通常情况,Git会用Fast forward模式,但是这种模式,删掉分支后,会丢掉分支信息
如果要强制禁用Fast forward .Git 就会生成一个新的commit
下面是 --no-ff方式的git merge:
和上面相同,当我们切换回master
$ git switch master
Switched to branch 'master'
D test.txt
Your branch is ahead of 'origin/master' by 4 commits.
(use "git push" to publish your local commits)
然后进行合并
$ git merge --no-ff -m "xingzou" dev
Merge made by the 'recursive' strategy.
readme.txt | 9 +--------
1 file changed, 1 insertion(+), 8 deletions(-)
使用git log 可以查看状态
$ git log --graph --pretty=oneline --abbrev-commit
* 0bc8baf (HEAD -> master) xingzou
|\
| * 3d7e2ab (dev) qianli
|/
* b58d576 conflict fixed
|\
| * 668c81c simple
* | 6ad8c06 newmaster
|/
* 76f4e06 branch.test
* 5af4d8e (origin/master) mytest
* 73eacdb sanshisui
* 6485209 woshifw
* b633e2d add distributed
不用Fast Forward之后 merge就像这样
分支策略
master分支应该是稳定的,没人在上面干活
dev分支应该是不稳定的
Bug分支
你如果想创建一个分支修复bug,但是dev分支还没有提交,你可以通过git stash 来修复
$ git stash
现在修复bug,需要把“Git is free software …”改为“Git is a free software …”,然后提交:
$ git add readme.txt
$ git commit -m "fix bug 101"
[issue-101 4c805e2] fix bug 101
1 file changed, 1 insertion(+), 1 deletion(-)
修复完成后,切换到master
分支,并完成合并,最后删除issue-101
分支:
$ git switch master
Switched to branch 'master'
Your branch is ahead of 'origin/master' by 6 commits.
(use "git push" to publish your local commits)
$ git merge --no-ff -m "merged bug fix 101" issue-101
Merge made by the 'recursive' strategy.
readme.txt | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
现在回到dev 去干活了 但是现在现在工作区是干净的
$ git switch dev
Switched to branch 'dev'
$ git status
On branch dev
nothing to commit, working tree clean
我们需要使用 $ git stash list查看
$ git stash list
stash@{0}: WIP on dev: f52c633 add merge
-
我们可以通过 git stash apply恢复,但是stash不会被删除 我们需要 git stash drop 删除
-
另一种方式是git stash pop ,恢复的同时把stash内容也删除了
恢复的时候
$ git stash apply stash@{0}
Feature分支
功能分支创建在feature上
基本上和销毁类似
但是在删除的时候如果在为合并的时候强行删除要使用-D
$ git branch -D feature-vulcan
多人协作
当你从远程仓库克隆,实际上是Git 自动把本地的master分支和远程的master分支对应起来。
要查看远程库的信息,用git remote
$ git remote
origin
git remote -v可以显示更详细的信息
origin git@github.com:2682487588/fyyzy.git (fetch)
origin git@github.com:2682487588/fyyzy.git (push)
推送分支
推送分支就是吧该分支上的所有本地提交推送到远程数据库上
需要制定推送哪个
比如
$ git push origin master
Enumerating objects: 22, done.
Counting objects: 100% (22/22), done.
Delta compression using up to 8 threads
Compressing objects: 100% (20/20), done.
Writing objects: 100% (20/20), 1.88 KiB | 384.00 KiB/s, done.
Total 20 (delta 8), reused 0 (delta 0), pack-reused 0
remote: Resolving deltas: 100% (8/8), done.
To github.com:2682487588/fyyzy.git
5af4d8e..ab8f56e master -> master
master
分支是主分支,因此要时刻与远程同步;dev
分支是开发分支,团队所有成员都需要在上面工作,所以也需要与远程同步;- bug分支只用于在本地修复bug,就没必要推到远程了,除非老板要看看你每周到底修复了几个bug;
- feature分支是否推到远程,取决于你是否和你的小伙伴合作在上面开发。
抓取分支
多人协作,大家都会往master和dev分支上推送各自的修改
正常情况下 ,从远程库拉取是这样的
$ git clone git@github.com:2682487588/fyyzy.git
Cloning into 'learngit'...
remote: Counting objects: 40, done.
remote: Compressing objects: 100% (21/21), done.
remote: Total 40 (delta 14), reused 40 (delta 14), pack-reused 0
Receiving objects: 100% (40/40), done.
Resolving deltas: 100% (14/14), done.
但是拉取的只有master ,如果想要拉取dev我们需要进一步找到远程的dev
$ git checkout -b dev origin/dev
Switched to a new branch 'dev'
D test.txt
Branch 'dev' set up to track remote branch 'dev' from 'origin'.
这样就可以在dev修改,是不是把dev分支push到远程
$ git add env.txt
$ git commit -m "add env"
[dev 7a5e5dd] add env
1 file changed, 1 insertion(+)
create mode 100644 env.txt
$ git push origin dev
Counting objects: 3, done.
Delta compression using up to 4 threads.
Compressing objects: 100% (2/2), done.
Writing objects: 100% (3/3), 308 bytes | 308.00 KiB/s, done.
Total 3 (delta 0), reused 0 (delta 0)
To github.com:michaelliao/learngit.git
f52c633..7a5e5dd dev -> dev
这时候如果git 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的链接
$ git branch --set-upstream-to=origin/dev dev
Branch 'dev' set up to track remote branch 'dev' from 'origin'.
再pull
$ git pull
Auto-merging env.txt
CONFLICT (add/add): Merge conflict in env.txt
Automatic merge failed; fix conflicts and then commit the result.
然后git commit
$ git commit -m "fix env conflict"
[dev 57c53ab] fix env conflict
$ git push origin dev
Counting objects: 6, done.
Delta compression using up to 4 threads.
Compressing objects: 100% (4/4), done.
Writing objects: 100% (6/6), 621 bytes | 621.00 KiB/s, done.
Total 6 (delta 0), reused 0 (delta 0)
To github.com:michaelliao/learngit.git
7a5e5dd..57c53ab dev -> dev
小结
因此,多人协作的工作模式通常是这样:
- 首先,可以试图用
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 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
,如果有冲突,要先处理冲突。
Rebase
上节我们看到了,多人再同一个分支协作时,很容易出现冲突,即使没有冲突,之后push必须先pull,在本地合并才会成功
标签管理
tag配合commit来使用
- commit号太复杂了
- 我们用tag来绑定
创建标签
创建标签只需要在要创建分支加上tag就行了
丿剑来·@LAPTOP-3L4Q3T2K MINGW64 /e/mygit/tmpgit/fyyzy (dev)
$ git checkout master
Switched to branch 'master'
Your branch is up to date with 'origin/master'.
丿剑来·@LAPTOP-3L4Q3T2K MINGW64 /e/mygit/tmpgit/fyyzy (master)
$ git tag v1.0
丿剑来·@LAPTOP-3L4Q3T2K MINGW64 /e/mygit/tmpgit/fyyzy (master)
$ git tag
v1.0
$ git log --pretty=oneline --abbrev-commit
找到之前版本并打上标签
方法是找到例是提交的commit id 打上就可以了
可以通过 git log --pretty=oneline --abbrev-commit来查看提交
git show tagname可以查看版本
tag v0,1
Tagger: 王浩鹏 <2682487588@qq.com>
Date: Tue Jun 1 10:13:38 2021 +0800
version 0.1
commit 0bc8bafb7c2a320a4d103afc0c2fe8987c238d5c (HEAD -> dev, tag: v0,1, origin/dev)
Merge: b58d576 3d7e2ab
Author: 王浩鹏 <2682487588@qq.com>
Date: Mon May 31 19:24:57 2021 +0800
xingzou
还可以创建带有说明的标签,用-a指定标签名,-m指定说明文字
$ git tag -a v0,1 -m "version 0.1" 0bc8baf
操作标签
删除
$ git tag v0.1
推送远程
$ git push origin v1.0
一次性推送所有标签
$ git push origin --tags
如果标签推送到远程想要删除
1.先删除芬迪的
$ git tag -d v0.9
2.然后删除远程的
$ git push origin :refs/tags/v0.9
小结:
- 推送标签 git push origin
- 推送未推送的标签 git push origin --tags
- 删除本地标签 git tag -d
- 删除远程标签 git push origin :refs/tags/