Git 基础学习


参考廖雪峰-git教程
Git GitHub GitLab使用教程

版本控制

版本控制(Revision control)是一种在开发的过程中用于管理我们对文件、目录或工程等内容的修改历史,方便查看更改历史记录,备份以便恢复以前的版本的软件工程技术,简单说就是用于管理多人协同开发项目的技术。
如果你用Microsoft Word写过长篇大论,那你一定有这样的经历:想删除一个段落,又怕将来想恢复找不回来怎么办?有办法,先把当前文件“另存为……”一个新的Word文件,再接着改,改到一定程度,再“另存为……”一个新文件,这样一直改下去,最后你的Word文档变成了这样:
在这里插入图片描述
多人开发就必须要使用版本控制!

常见的版本控制工具

  • Git
  • SVN(Subversion)
  • CVS(Concurrent Versions System)
  • VSS(Micorosoft Visual SourceSafe)
  • TFS(Team Foundation Server)
  • Visual Studio Online

版本控制分类

本地式版本控制

相当于每个版本一个快照,多人开发每个人电脑上一个版本,不适合多人开发,适合个人使用
在这里插入图片描述

集中式版本控制

版本库是集中存放在中央服务器的,而干活的时候,用的都是自己的电脑,所以要先从中央服务器取得最新的版本,然后开始干活,干完活了,再把自己的活推送给中央服务器。中央服务器就好比是一个图书馆,你要改一本书,必须先从图书馆借出来,然后回到家自己改,改完了,再放回图书馆。

  • 所有的版本数据都保存在服务器上,协同开发者从服务器上同步更新或上传自己的修改
  • 不同用户和云盘(服务器)进行交互,服务器中存储不同版本,用户的本地只有自己以前所同步的版本
  • 如果不连网的话,用户就看不到历史版本,也无法切换版本验证问题,或在不同分支工作
  • 所有数据都保存在单一的服务器上,有很大的风险这个服务器会损坏,这样就会丢失所有的数据,当然可以定期备份。代表产品:SVN、CVS、VSS
    在这里插入图片描述

分布式版本控制

在实际使用分布式版本控制系统的时候,其实很少在两人之间的电脑上推送版本库的修改,因为可能你们俩不在一个局域网内,两台电脑互相访问不了,也可能今天你的同事病了,他的电脑压根没有开机。因此,分布式版本控制系统通常也有一台充当“中央服务器”的电脑,但这个服务器的作用仅仅是用来方便“交换”大家的修改,没有它大家也一样干活,只是交换修改不方便而已。

  • 集中式版本控制只能从服务器拿到一个版本,分布式版本控制每个用户可以拿到服务器的所有版本,由于每个用户那里保存的都是所有的版本数据,只要有一个用户的设备没有问题就可以恢复所有的数据,但这增加了本地存储空间的占用
  • 可以离线在本地提交,只需在连网时push到相应的服务器或其他用户那里
  • 用户提交版本先提交到本地,再提交到服务器中心
  • 不会因为服务器损坏或者网络问题,造成不能工作的情况
    在这里插入图片描述

Git与SVN的主要区别

  • SVN是集中式版本控制系统,版本库是集中放在中央服务器的,而工作的时候,用的都是自己的电脑,所以首先要从中央服务器得到最新的版本,然后工作,完成工作后,需要把自己的代码推送到中央服务器。集中式版本控制系统是必须联网才能工作,对网络带宽要求较高。
  • Git是分布式版本控制系统,没有中央服务器,每个人的电脑就是一个完整的版本库,工作的时候不需要联网了,因为版本都在自己电脑上。协同的方法是这样的:比如说自己在电脑上改了文件A,其他人也在电脑上改了文件A,这时,你们两之间只需把各自的修改推送给对方,就可以互相看到对方的修改了。Git可以直接看到更新了哪些代码和文件!

Git

git工作空间的三个区域

在这里插入图片描述

  • 工作目录(Working Directory):正在操作的文件夹,工作区的文件分为,已管理文件和新文件/正在修改的文件,我们看到的目录文件夹就是一个工作区
    在这里插入图片描述

  • 暂存区(Stage/Index):git add . 之后的文件,git管理的文件暂时放到这里,可以提交可以回滚,事实上它只是一个文件,保存即将提交到文件列表信息

  • 版本库(Repository或Git Directory):git commit 之后保存的版本,就是安全存放数据的位置,这里面有你提交到所有版本的数据
    工作区的 .git 文件夹就是版本库,创建Git版本库时,Git自动为我们创建了唯一一个master分支

  • 如果在加上远程的git仓库(Remote Directory):远程仓库,托管代码的服务器,可以简单的认为是你项目组中的一台电脑用于远程数据交

项目修改流向:

  • 使用两次命令git add,把readme.txt和LICENSE都添加后
    在这里插入图片描述

  • 执行git commit就可以一次性把暂存区的所有修改提交到分支
    在这里插入图片描述

在这里插入图片描述

版本控制(git管理文件夹)的基本步骤

  • 创建项目文件夹,并进入,在工作目录中添加、修改文件
	mkdir 项目名
  • git初始化,让git帮助管理当前文件夹
	git init	进入要管理的文件夹执行
	git init demo		创建demo文件夹,并管理这个文件夹中的内容
	取消项目版本控制:进入项目目录  ——>  find . -name ".git" | xargs rm -Rf
	
	mac中所有 . 开头的文件都是隐藏文件,可以通过 ls -la 查看隐藏文件
  • 管理目录下文件状态
	git status
	新增的文件和修改后的文件都是红色
		以下表示没有需要提交的修改
			On branch master
			nothing to commit, working tree clean
  • 查看修改内容,查看文件不同 (difference),只要明确修改文件是在工作区修改的,add之后,暂存区就有了修改后的文件,commit之后,分支(版本库)中就有了修改后的文件
	$ git diff		查看工作区(work dict)和暂存区(stage)的区别
	$ git diff <file>		查看文件做了什么修改                
	$ git diff --cached		查看暂存区(stage)和分支(master)的区别
	$ git diff HEAD -- <file>	查看工作区和版本库里面最新版本的区别		

	如果文件已经add了,暂存区和工作区内容就一样了,git diff是什么都不显示的
	已经commit了,工作区,暂存区,版本库(分支)中就都一样了,以上命令都没显示
  • 管理指定文件
   	git add 文件名		实际是将文件从工作区add到暂存区
   	git add .	管理所有文件
   	添加许多同种类型的文件,可以使用通配符 * (记得加引号)  如: git add "*.txt"  命令就是添加所有 .txt 文件
   	-
    git rm -r --cached App.class
   	git rm -r --cached .		将所有文件从暂存区踢出
	fatal: pathspec 'readme.txt' did not match any files
	添加某个文件时,该文件必须在当前目录下存在,用ls或者dir命令查看当前目录的文件,看看文件是否存在,或者是否写错了文件名
  • 个人信息配置:用户名,邮箱(仅需第一次使用git时配置)
	查看当前git的用户名和邮箱
   	git config --global user.name	
   	git config --global user.email
   	
   	设置git用户名和邮箱
   	git config --global user.name [username]
   	git config --global user.email [email]
   	
   	# Git 是分布式版本控制系统,所以,每个机器都必须自报家门:你的名字和Email地址
   	#git config 命令的 --global 参数,用了这个参数,表示你这台机器上所有的 Git 仓库都会使用这个配置,当然也可以对某个仓库指定不同的用户名和Email地址(不加 --global)。
	项目配置文件:项目/.git/config
	git config --local user.name 'name'
	git config --local user.email 'email'

	全局配置文件:~/.gitconfig
	git config --global user.name 'name'
	git config --global user.email 'email'

	系统配置文件:/etc/.gitconfig		需要root权限
	git config --system user.name 'name'
	git config --system user.email 'email'
  • 生成版本
    你不断对文件进行修改,然后不断提交修改到版本库里,就好比玩RPG游戏时,每通过一关就会自动把游戏状态存盘,如果某一关没过去,你还可以选择读取前一关的状态。有些时候,在打Boss之前,你会手动存盘,以便万一打Boss失败了,可以从最近的地方重新开始。Git也是一样,每当你觉得文件修改到一定程度的时候,就可以“保存一个快照”,这个快照在Git中被称为commit。一旦你把文件改乱了,或者误删了文件,还可以从最近的一个commit恢复,然后继续工作,而不是把几个月的工作成果全部丢失。
   	git commit -m '描述信息'
   		1 file changed:1个文件被改动(我们新添加的readme.txt文件)
   		2 insertions:插入了两行内容(readme.txt有两行内容)
  • 查看版本记录
    git log命令显示从最近到最远的提交日志,我们可以看到3次提交,最近的一次是append GPL,上一次是add distributed,最早的一次是wrote a readme file
    	git lg	会展示简短的版本号,提交时间,提交人
       		bogon:项目 didi$ git lg
       		* 版本号 - (HEAD -> lhf-dev, origin/lhf-dev, origin/dev, dev) 提交名 (13 days ago) <提交人>
    
       	git log
       	git log --oneline     #美化输出信息,每个记录显示为一行,显示 commit_id 前几位数
       	git log --oneline --graph			当前分支的版本线图
       	git log --oneline --graph --all		所有分支的版本线图
       	git log --pretty=oneline     #美化输出信息,每个记录显示为一行,显示完整的 commit_id
       	git log --graph		图像化显示提交记录
       	git log --graph --pretty=format:"%h %s"		显示格式化,h 表示哈希值,s 表示提交记录	
       	
        如果嫌输出信息太多,看得眼花缭乱的,可以试试加上--pretty=oneline参数
        	$ git log --pretty=oneline
       		版本号 (HEAD -> master) append GPL
       		版本号 add distributed
       		版本号 wrote a readme file
    

在这里插入图片描述

git日常命令

接上面 【版本控制(git管理文件夹)的基本步骤】

	拓展新功能
	git add
	git commit -m '新功能'	
	git commit -am '新功能'		相当于执行了 add 和 commit,但是只能针对【被 add 过的,修改了的文件】
	
	修改后,add之前,恢复到没有修改之前的状态
	git checkout -- index.html			恢复index.html到上一个版本
	git checkout b52ed7d -- index.html		恢复index.html到id为b52ed7d的提交版本,但其他文件不能恢复
	git checkout b52ed7d -- .			恢复所有文件到b52ed7d版本
	
	修改后,add之后,回滚到之前的版本
	git log
	git reset --hard 要回滚到的版本号		版本号只需要写不重复的前几位即可,git会自动去匹配
	git reset --hard HEAD^			回滚到上一个版本	HEAD~3 往上第三个版本
	git reset --hard ORIG_HEAD		回滚到最开始的版本
	
	你从21世纪坐时光穿梭机来到了19世纪,想再回去已经回不去了,肿么办?
	只要上面的命令行窗口还没有被关掉,你就可以顺着往上找未来版本的版本号,就可以指定回到未来的某个版本
	
	回滚到之后的版本
	git reflog
	git reset --hard 要回滚到的版本号

HEAD指向的版本是当前版本,git允许我们在版本的历史 git log 和未来 git reflog 穿梭
在这里插入图片描述

其他指令

	git rm <file>
		相当于执行
		rm <file>			单独的 rm 只是删除了工作区的文件,git status 会显示出 暂存区、版本库的这个文件并没有被删除
		git add <file>		删除暂存区的这个文件
		
	git commit -m 'remove test.txt'	删除版本库中这个文件
	git checkout -- test.txt		删错了,从版本库恢复到工作区
	open ~/.ssh  Mac 打开存放 ssh 文件夹
	
	git clone -b dev 项目远程http或者ssh链接		clone项目的某个分支到本地,这里我们clone dev分支
	git remote		检查一下仓库名称,查看当前配置有哪些远程仓库,在克隆完某个项目后,命令行进到该项目文件夹 git remote,至少可以看到一个名为 origin 的远程库,Git 默认使用这个名字来标识你所克隆的原始仓库
	git remote remove origin	删除本地与远程仓库origin的关联
	git push origin lhf_dev		本地分支推上去,远程会自动生成同名新分支 lhf_dev
	git branch --set-upstream-to=origin/lhf_dev		将当前分支与远程某分支关联
	git branch -vv	查看关联情况
	
	git pull origin dev 相当于以下两句
		git fetch origin dev	代码拉到本地版本库
		git merge origin/dev	把本地版本库代码合并到工作区

撤销修改

让这个文件回到最近一次 git commit 或 git add 时的状态

  1. 当你改乱了工作区某个文件的内容,该文件没有放到暂存区,想直接丢弃工作区的修改时
	git checkout -- filename	撤销修改就回到和版本库一模一样的状态
  1. 当你不但改乱了工作区某个文件的内容,还添加到了暂存区时,想丢弃修改,分两步
	git reset HEAD <file>	回到场景一,将文件移出了暂存区
	git checkout -- filename
  1. 已经提交了不合适的修改到版本库时,想要撤销本次提交,参考版本回退一节,不过前提是没有推送到远程库。

Git 分支

文章详情:廖雪峰-分支管理

  • 每次提交,Git都把它们串成一条时间线,这条时间线就是一个分支。截止到目前,只有一条时间线,在Git里,这个分支叫主分支,即master分支。
  • HEAD严格来说不是指向提交,而是指向master,master才是指向提交的,所以,HEAD指向的就是当前分支。不过,在某个时间点,两个平行宇宙合并了,我们就需要处理一些问题了。
  • 下图中,每个 C 是一个版本,C2是在C1基础上修改的版本,C4、C5是在C3基础上修改的,C6是C4、C5合并后的版本。
  • master:主分支,dev:应用分支,bug:bug分支,v3.0:不同版本的分支
    在这里插入图片描述
    在这里插入图片描述

分支的常用指令

	# 列出所有本地分支
	git branch
	
	# 列出所有远程分支
	git branch -r
	git branch -a	其中红色是远程分支,黑色是本地分支,绿色是本地当前分支
	
注意:不要 git checkout origin/new1 切换到远程分支,会造成重大错误,远程分支只用来追踪
     只需要 git branch 远程分支名字,git 就会创建对应远程分支的本地分支

	git branch --merged		查看已经合并的分支
	git branch --no-merged	查看没有合并的分支
	
	# 新建一个分支,但依然停留在当前分支
	git branch [branch-name]	相当于基于所在分支创建了新的分支
	
	# 切换到分支
	git checkout [branch]
	git master	仅主分支可以git master
	
		实际上,切换分支这个动作,用switch更科学
		git switch master	切换到master
		
		Git还会自动提示我们当前master分支比远程的master分支要超前1个提交。
		Your branch is ahead of 'origin/master' by 1 commit.
		  (use "git push" to publish your local commits)
	
	# 新建一个分支,并切换到该分支
	git checkout -b [branch]
	git switch -c dev
	
	# 合并指定分支到当前分支
	$ git merge [branch]
	$ git merge [branch] --no-ff	不使用快转机制
	
	# 删除分支
	$ git branch -d [branch-name]
	注意:不能删除现在所在的分支lhf-dev,必须切换到其他分支dev,才能删除lhf-dev分支
	
	# 强制删除分支,要删除没有合并的分支 not fully merged
	$ git branch -D [branch-name]
	针对 The branch 'v3' is not fully merged ,if you are sure you want to delete it ,run 'git branch -D v3'
	
	# 删除远程分支
	$ git push origin --delete [branch-name]
	$ git branch -dr [remote/branch]
	
	# 推送代码和拉取代码
	git push 	将本地当前分支 推送到 与本地当前分支同名的远程分支上
	git pull 	将与本地当前分支同名的远程分支 拉取到 本地当前分支上
	git push --all 		推送本地所有分支到远程同名分支
	git pull --all 		拉取与本地分支同名的所有远程分支
	git push origin dev		将本地 所在分支 推送到远程 dev 分支
	git pull origin dev		将远程 dev 分支拉取到本地 所在分支 
	git push origin <本地分支名>:<远程分支名>		本地指定分支推送到远程指定分支
	git pull origin <远程分支名>:<本地分支名>		远程指定分支拉取到本地指定分支

快转机制:
下图中,676d89e和6d065f6版本实际上是相同的,只是将分支做了合并,使用快转机制合并分支时,会出现第一个红色框中的现象;merge 不加参数时,不使用快转机制,就会默认把这两个相同的版本合并,(HEAD ——> master, develop )表示 master 和 develop 分支目前的版本都是 676d89e

在这里插入图片描述

分支冲突

  • dev分支的新功能代码在合并到master分支时,以master代码为基础,增加dev的新代码
  • 当dev分支中,master的基础代码部分,和master分支中代码不一致时,会产生分支冲突
  • 手动创建冲突:不同分支修改相同部分(不管修改还是新增),add,commit,切换到要被合并的分支,merge 合并的分支
CONFLICT (content): Merge conflict in test.html
Automatic merge failed; fix conflicts and then commit the result.
dev分支
<ul>
	<li>亚洲</li>
	<li>欧美</li>
	<li>日韩</li>
	<li>直播</li>		冲突代码
	<li>商城100%</li>
</ul>

master分支
<ul>
	<li>亚洲</li>
	<li>欧美</li>
	<li>日韩</li>
	<li>直播(修复完毕)</li>		冲突代码
</ul>

git master
git merge dev	合并分支后
<ul>
	<li>亚洲</li>
	<li>欧美</li>
	<li>日韩</li>
<<<<<<< HEAD
	<li>直播(修复完毕)</li>
=======
	<li>直播</li>
	<li>商城100%</li>
>>>>>>> dev
</ul>

分支冲突解决方法:

	1. 手动修改,删除需要删除的部分
	2. git merge --abort		取消合并

分支管理策略

合并分支时如果可能,Git会用Fast forward模式,但这种模式下,删除分支后,会丢掉分支信息。如果要强制禁用Fast forward模式,Git就会在merge时生成一个新的commit,这样,从分支历史上就可以看出分支信息。

	git merge --no-ff -m "merge with no-ff" dev		--no-ff参数,表示禁用Fast forward
	
	$ git log --graph --pretty=oneline --abbrev-commit
	*   e1e9c68 (HEAD -> master) merge with no-ff
	|\  
	| * f52c633 (dev) add merge
	|/  
	*   cf810e4 conflict fixed
	...

不使用快速合并 fast forward,–no-ff 使用普通模式合并
在这里插入图片描述
实际工作中,你和你的小伙伴们每个人都在dev分支上干活,每个人都有自己的分支,时不时地往dev分支上合并就可以了
在这里插入图片描述

Bug 分支

每个bug都可以通过一个新的临时分支来修复,修复后,合并分支,然后将临时分支删除
当你接到一个修复一个代号101的bug的任务时,很自然地,你想创建一个分支issue-101来修复它,但是,等等,当前正在dev上进行的工作还没有提交:

	$ git status
	On branch dev
	Changes to be committed:
	  (use "git reset HEAD <file>..." to unstage)
	
		new file:   hello.py
	
	Changes not staged for commit:
	  (use "git add <file>..." to update what will be committed)
	  (use "git checkout -- <file>..." to discard changes in working directory)
	
		modified:   readme.txt

并不是你不想提交,而是工作只进行到一半,还没法提交,预计完成还需1天时间。但是,必须在两个小时内修复该bug,怎么办?

	$ git stash		可以把当前工作现场“储藏”起来,等以后恢复现场后继续工作
	Saved working directory and index state WIP on dev: f52c633 add merge
	
	用git status查看工作区,就是干净的(除非有没有被Git管理的文件),因此可以放心地创建分支来修复bug。

首先确定要在哪个分支上修复bug,假定需要在master分支上修复,就从master创建临时分支

	$ git checkout master
	Switched to branch 'master'
	Your branch is ahead of 'origin/master' by 6 commits.
	  (use "git push" to publish your local commits)
	
	$ git checkout -b issue-101
	Switched to a new branch 'issue-101'

修复完成后,提交

	$ git add readme.txt 
	$ git commit -m "fix bug 101"
	[issue-101 4c805e2] fix bug 101
	 1 file changed, 1 insertion(+), 1 deletion(-)

切换到master分支,合并,删除bug分支

	$ 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 status
	On branch dev
	nothing to commit, working tree clean
	
工作区是干净的,工作现场还在,Git把stash内容存在某个地方了,但是需要恢复一下,使用 git stash pop 恢复工作区,同时删除 stash
$ git stash pop
	On branch dev
	Changes to be committed:
	  (use "git reset HEAD <file>..." to unstage)
	
		new file:   hello.py
	
	Changes not staged for commit:
	  (use "git add <file>..." to update what will be committed)
	  (use "git checkout -- <file>..." to discard changes in working directory)
	
		modified:   readme.txt
	
	Dropped refs/stash@{0} (5d677e2ee266f39ea296182fb2354265b91b3b2a)
	
$ git stash list	查看工作区的 stash list
$ git stash apply stash@{0}	恢复到指定 stash

当master分支上修复了bug后,我们要想一想,dev分支是早期从master分支分出来的,所以,这个bug其实在当前dev分支上也存在

同样的bug,要在dev上修复
我们只需要把4c805e2 fix bug 101这个提交所做的修改“复制”到dev分支
注意:我们只想复制4c805e2 fix bug 101这个提交所做的修改,并不是把整个master分支merge过来

$ git cherry-pick 4c805e2
	[master 1d4b803] fix bug 101
	1 file changed, 1 insertion(+), 1 deletion(-)
	
Git自动给dev分支做了一次提交,注意这次提交的commit是1d4b803
它并不同于master的4c805e2,因为这两个commit只是改动相同,但确实是两个不同的commit

Future 分支

开发一个新feature,最好新建一个分支;

如果要丢弃一个没有被合并过的分支,可以通过git branch -D 强行删除。

$ git branch -d feature-vulcan
	error: The branch 'feature-vulcan' is not fully merged.
	If you are sure you want to delete it, run 'git branch -D feature-vulcan'.
使用强行删除
$ git branch -D feature-vulcan
	Deleted branch feature-vulcan (was 287773e).

多人协作

  • master分支是主分支,因此要时刻与远程同步
  • dev分支是开发分支,团队所有成员都需要在上面工作,所以也需要与远程同步
  • bug分支只用于在本地修复bug,就没必要推到远程了,除非老板要看看你每周到底修复了几个bug
  • feature分支是否推到远程,取决于你是否和你的小伙伴合作在上面开发
	git remote	查看远程仓库的信息
	git remote -v	查看远程仓库的详细信息
	
	git push origin master		推送分支,将分支上所有本地提交推送到远程仓库
	从远程库clone时,默认情况下,你的小伙伴只能看到本地的master分支
	要在dev分支上开发,就必须创建远程origin的dev分支到本地
	git checkout -b dev origin/dev	

工作模式

  1. 首先,可以试图用git push origin 推送自己的修改;
	$ git push origin dev
		To github.com:michaelliao/learngit.git
		 ! [rejected]        dev -> dev (non-fast-forward)
		error: failed to push some refs to 'git@github.com:michaelliao/learngit.git'
		hint: Updates were rejected because the tip of your current branch is behind
		hint: its remote counterpart. Integrate the remote changes (e.g.
		hint: 'git pull ...') before pushing again.
		hint: See the 'Note about fast-forwards' in 'git push --help' for details.
  1. 如果推送失败,则因为远程分支比你的本地更新,需要先用git pull试图合并;
	$ 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
  1. 如果合并有冲突,则解决冲突,并在本地提交;
	CONFLICT (add/add): Merge conflict in env.txt
	Automatic merge failed; fix conflicts and then commit the result.
  1. 没有冲突或者解决掉冲突后,再用git push origin 推送就能成功!
	$ 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
  1. 如果git pull提示no tracking information,则说明本地分支和远程分支的链接关系没有创建
	$ git branch --set-upstream-to=origin/dev dev
		Branch 'dev' set up to track remote branch 'dev' from 'origin'.

tags 标签管理

发布一个版本时,我们通常先在版本库中打一个标签(tag),这样,就唯一确定了打标签时刻的版本。将来无论什么时候,取某个标签的版本,就是把那个打标签的时刻的历史版本取出来。所以,标签也是版本库的一个快照。其实它就是指向某个commit的指针(跟分支很像对不对?但是分支可以移动,标签不能移动),相当于对commit之后的hash值做的简写
“请把上周一的那个版本打包发布,commit号是6a5819e…”
“请把上周一的那个版本打包发布,版本号是v1.2,按照tag v1.2查找commit”

新建标签

	1. checkout 到需要打标签的分支上
	2. 打标签
		git tag v1.0		相当于为HEAD打标签
		git tag -a v1 -m "第一版"			-a:接版本名称    -m:描述
		git tag v0.9 要打的标签的版本id		周一提交的内容忘记打标签了,周五 git log 找到周一提交的commit id 然后
	git tag		查看所有标签	
	git show v0.9		查看标签信息

操作标签

	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
	
	将本地标签提交到github
	git push origin --tags

Github

Github 准备:SSH配置

  1. 创建SSH Key。在用户主目录下,看看有没有.ssh目录,如果有,再看看这个目录下有没有id_rsa和id_rsa.pub这两个文件,如果已经有了,可直接跳到下一步。如果没有,打开Shell(Windows下打开Git Bash),创建SSH Key:
	ssh-keygen -t rsa -C "youremail@example.com"
	一路回车,使用默认值即可,由于这个Key也不是用于军事目的,所以也无需设置密码
	如果一切顺利的话,用户主目录里找到.ssh目录,里面有id_rsa和id_rsa.pub两个文件,这两个就是SSH Key的秘钥对,id_rsa是私钥,不能泄露出去,id_rsa.pub是公钥,可以放心地告诉任何人
  1. 登陆GitHub,点击头像,Settings,SSH and GPG keys,New SSH key
    在这里插入图片描述

为什么GitHub需要SSH Key呢?
因为GitHub需要识别出你推送的提交确实是你推送的,而不是别人冒充的,而Git支持SSH协议,所以,GitHub只要知道了你的公钥,就可以确认只有你自己才能推送。

当然,GitHub允许你添加多个Key。假定你有若干电脑,你一会儿在公司提交,一会儿在家里提交,只要把每台电脑的Key都添加到GitHub,就可以在每台电脑上往GitHub推送了。

Github 创建仓库

  1. 根据GitHub的提示,在本地的learngit仓库下运行命令
	git remote add origin https://github.com/dddmmiao/winwork.git
	关联一个远程库时必须给远程库指定一个名字,origin是默认习惯命名
  1. 添加后,远程库的名字就是origin,这是Git默认的叫法,也可以改成别的,但是origin这个名字一看就知道是远程库。下一步,就可以把本地库的所有内容 git push 到远程库上
	git push -u origin master	实际上是把当前分支master推送到远程
	我们第一次推送master分支时,加上了-u参数,Git不但会把本地的master分支内容推送的远程新的master分支,还会把本地的master分支和远程的master分支关联起来,在以后的推送或者拉取时就可以简化命令
	之后只要本地作了提交,就可以通过以下命令push
	git push origin master

开发基本流程

第一个开发者上传代码到仓库

1. 给远程仓库起别名:		git remote add  别名origin 远程仓库地址
2. 向远程仓库推送代码:	git push -u origin 分支master/dev	-u表示指定 origin 默认提交到 master 分支
   向远程仓库推送代码:	git push origin dev	手动将 origin 提交到 dev 分支

员工A第一次获取仓库代码

1. 克隆远程仓库代码:		git clone 远程仓库地址	(内部已经实现了git remote add origin 远程仓库地址)

	git clone 和 直接下载项目zip的区别:
	直接下载项目zip只会把项目下载下来,分支,提交记录,.git文件都不会被下载,项目需要重新git init,重新初始化再push到远程仓库就会导致项目所有内容提交人变成你
	git clone 得到的项目是包含.git文件的,分支等提交记录都会存在
	
2. git status 查看文件,有必要的话,设置 .gitignore 忽略上传内容
3. 查看分支,切换到dev分支(要基于谁创建分支就先切换到哪个分支)
4. 基于dev分支新建并切换到自己的分支:	git checkout -b 分支		(clone 时会把所有的分支clone,git branch只能看到master分支,git branch -a 查看本地和远程所有分支)
5. 开发功能
6. git status 查看修改的文件,add,commit 提交本地版本
7. git log 查看提交记录
8. 测试通过后,切换到基于开发的分支,比如dev,merge 自己的分支
9. 推送本地dev分支到远程dev分支,推送自己本地分支到自己远程分支

员工A下班了,员工B开发了功能并push,员工A第二天继续开发

1. 切换到 dev 分支,git status 查看一下提交记录,将远程最新的dev分支拉取到本地dev分支
2. 切换到自己分支
3. git pull origin dev 	将员工B已经合并到的远程dev分支拉到自己的分支
4. 如果自己的本地分支超前自己的远程分支,先在自己分支 git push 或者 git push origin lhf-dev ,更新自己的远程分支
5. 开发功能 
6. git status 查看修改的文件,add,commit 提交本地版本
7. git log 查看提交记录
8. 测试通过后,切换到基于开发的分支,比如dev,merge 自己的分支
9. 推送本地dev分支到远程dev分支,推送自己本地分支到自己远程分支

开发完毕,上线

1. 将dev分支合并到master,推送到仓库,进行上线
	git checkout master
	git merge dev
	git push origin master
2. 把dev分支也推送到仓库
	git checkout dev
	git merge master
	git push origin dev 

主仓库作为服务器

  1. github 上创建一个远程仓库,作为服务器的仓库名字要求:owner名字.github.io
    在这里插入图片描述
  2. 直接clone 或者创建本地仓库,关联远程仓库
	git remote add origin 远程仓库链接
	git push -u origin master
  1. 复制远程仓库名字 owner名字.github.io 到浏览器,可以直接访问项目
    在这里插入图片描述

仓库迁移

新建一个远程仓库,将旧仓库内容迁移到新仓库
在这里插入图片描述
在这里插入图片描述

忽略提交

  • clone 拿到一个项目,或者本地项目要push到远程仓库了,先 git status 检查项目中有没有不该提交的内容,比如下图中 .DS_Store 和 .vscode/ 不需要提交到远程
  • 编辑 .gitignore 文件,忽略它们的提交
  • 再次 git status 检查设置忽略的内容,是否不再出现在待提交区

在这里插入图片描述

	有些时候,你必须把某些文件放到Git工作目录中,但又不能提交它们
	在Git工作区的根目录下创建一个特殊的.gitignore文件,然后把要忽略的文件名填进去,Git就会自动忽略这些文件
	Github 提供了一些配置文件	https://github.com/github/gitignore
	
	有些时候,你想添加一个文件到Git,但发现添加不了,原因是这个文件被.gitignore忽略了
	git add App.class
		The following paths are ignored by one of your .gitignore files:
		App.class
		Use -f if you really want to add them.
	git add -f App.class	强制添加文件到Git

	git check-ignore -v App.class	检查忽略规则
		.gitignore:3:*.class	App.class	表示.gitignore的第3行规则忽略了该文件
		
	此时我们这样写.gitignore
		.*					# 排除所有.开头的隐藏文件
		*.class				# 排除所有.class文件
		/node_moudles		#忽略node_moudles文件夹
		App.class			#忽略App.class文件
		
		# 不排除.gitignore和App.class:
		!.gitignore
		!App.class
		
	如果已commit了App.class文件,再在.gitignore文件中设置忽略是不会生效的,首先要执行以下命令将App.class从缓存中踢出来
		git rm -r --cached App.class
		git rm -r --cached .		将所有文件从暂存区踢出		

补充

在这里插入图片描述

本地仓库关联多个远程仓库

本地仓库要关联到远程仓库才可以实现,本地仓库的 pull 和 push

	git remote add  别名origin 远程仓库地址	此后就可以使用pull和push了
	
	如果报错:fatal: remote origin already exists,说明本地仓库已经关联了一个远程仓库
	git remote -v	先查看关联
	git remote rm origin	删除已有的远程仓库联接
	重新关联

git本身是分布式版本控制系统,可以同步到另外一个远程库,当然也可以同步到另外两个远程库。使用多个远程库时,我们要注意,git给远程库起的默认名称是origin,如果有多个远程库,我们需要用不同的名称来标识不同的远程库

	git remote add github github远程仓库地址
	git remote add gitee gitee远程仓库地址
	
	查看远程库信息,可以看到两个远程库
	git remote -v
	gitee	git@gitee.com:liaoxuefeng/learngit.git (fetch)
	gitee	git@gitee.com:liaoxuefeng/learngit.git (push)
	github	git@github.com:michaelliao/learngit.git (fetch)
	github	git@github.com:michaelliao/learngit.git (push)

	git push github master		推送到github远程仓库
	git push gitee master	推送到gitee远程仓库

rebase应用场景

rebase:使git记录变得简洁,可以把本地未push的分叉提交历史整理成直线,目的是使得我们在查看历史提交的变化时更容易,因为分叉的提交需要三方对比

多个提交记录合并成一个提交记录

注意:合并的记录尽量都是没有 push 过的记录,不要和已 push 到仓库的记录合并,否则容易产生记录冲突
提交记录如下

didideMacBook-Pro-150:rebase didi$ git log
commit a47723a609a1b1a53690935e3827ae87ba77e37f (HEAD -> master)
Author: [lvhaifeng] <[lvhaifeng_i@didiglobal.com]>
Date:   Sun Jul 11 16:50:33 2021 +0800

    v4

commit 1f8839b441c0430171f9d8b92e54deabdc6caf3d
Author: [lvhaifeng] <[lvhaifeng_i@didiglobal.com]>
Date:   Sun Jul 11 16:50:07 2021 +0800

    v3

commit c52cad893700e7ab059ba2bc8d4eb7ef38a32494
Author: [lvhaifeng] <[lvhaifeng_i@didiglobal.com]>
Date:   Sun Jul 11 16:49:46 2021 +0800

    v2

commit ebd96a682bb849350134cffb0cca4589c5670c65
Author: [lvhaifeng] <[lvhaifeng_i@didiglobal.com]>
Date:   Sun Jul 11 16:48:38 2021 +0800

    v1

第一步

git rebase -i v2的版本号		将v4,v3,v2 合并
git rebase -i HEAD~3		从当前记录开始,将最近的三条记录合并

显示信息

didideMacBook-Pro-150:rebase didi$ git rebase -i HEAD~3

pick c52cad8 v2
pick 1f8839b v3
pick a47723a v4

第二步
将 pick 改成 s ,s 表示 squash ,将当前版本合并到上一个版本

didideMacBook-Pro-150:rebase didi$ git rebase -i HEAD~3

pick c52cad8 v2
s 1f8839b v3
s a47723a v4

:wq 退出

# This is a combination of 3 commits.
# This is the 1st commit message:

v2

# This is the commit message #2:

v3

# This is the commit message #3:

v4

# Please enter the commit message for your changes. Lines starting
# with '#' will be ignored, and an empty message aborts the commit.

第三步
自定义合并的提交信息

# This is a combination of 3 commits.
# This is the 1st commit message:

v2 & v3 & v4

# Please enter the commit message for your changes. Lines starting
# with '#' will be ignored, and an empty message aborts the commit.

:wq 退出

didideMacBook-Pro-150:rebase didi$ git log
commit d09c4c545bc4aa529b82f86f394ffa44c295e8ff (HEAD -> master)
Author: [lvhaifeng] <[lvhaifeng_i@didiglobal.com]>
Date:   Sun Jul 11 16:49:46 2021 +0800

    v2 & v3 & v4

commit ebd96a682bb849350134cffb0cca4589c5670c65
Author: [lvhaifeng] <[lvhaifeng_i@didiglobal.com]>
Date:   Sun Jul 11 16:48:38 2021 +0800

    v1

dev 记录合并到 master 记录

操作步骤见:7小时学会Git 基础全套完整教程(从入门到精通)
在这里插入图片描述

合并分叉

公司提交到本地,从家开发别的功能提交到仓库,回到公司从云端拉代码,如果 dev 相对 master 的基代码不同,会产生分叉
解决办法如下

回到公司从仓库拉代码时
git pull origin dev	改为下面两行代码
	git fetch origin dev	代码拉到本地版本库
	git rebase origin/dev

合并成一条直线

$ git log --graph --pretty=oneline --abbrev-commit
	* 582d922 (HEAD -> master) add author
	* 8875536 add comment
	* d1be385 (origin/master) init hello
	*   e5e69f1 Merge branch 'dev'
	|\  
	| *   57c53ab (origin/dev, dev) fix env conflict
	| |\  
	| | * 7a5e5dd add env
	| * | 7bd91f1 add new env
	...
	
	注意到Git用(HEAD -> master)和(origin/master)标识出当前分支的HEAD和远程origin的位置分别是582d922 add author和d1be385 init hello
	本地分支比远程分支快两个提交
$ git push origin master
	To github.com:michaelliao/learngit.git
	! [rejected]        master -> master (fetch first)
	error: failed to push some refs to 'git@github.com:michaelliao/learngit.git'
	hint: Updates were rejected because the remote contains work that you do
	hint: not have locally. This is usually caused by another repository pushing
	
	尝试 git push origin dev 本地分支失败说明 本地版本不是最新的了,有人先于我们push了dev
	不是最新版本,先 git pull 获取最新版本
	
$ git pull
	remote: Counting objects: 3, done.
	remote: Compressing objects: 100% (1/1), done.
	remote: Total 3 (delta 1), reused 3 (delta 1), pack-reused 0
	Unpacking objects: 100% (3/3), done.
	From github.com:michaelliao/learngit
	   d1be385..f005ed4  master     -> origin/master
	 * [new tag]         v1.0       -> v1.0
	Auto-merging hello.py
	Merge made by the 'recursive' strategy.
	 hello.py | 1 +
	 1 file changed, 1 insertion(+)
	
	下面可以发现提交历史分叉了,push到远程后不美观
$ git log --graph --pretty=oneline --abbrev-commit
	*   e0ea545 (HEAD -> master) Merge branch 'master' of github.com:michaelliao/learngit
	|\  
	| * f005ed4 (origin/master) set exit=1
	* | 582d922 add author
	* | 8875536 add comment
	|/  
	* d1be385 init hello
	...

$ git rebase	将本地提交历史合并成一条直线
$ git log --graph --pretty=oneline --abbrev-commit
	* 7e61ed4 (HEAD -> master) add author
	* 3611cfe add comment
	* f005ed4 (origin/master) set exit=1
	* d1be385 init hello
	...	

$ git push origin master	再推送到远程分支后,远程分支也就是一条直线了
$ git log --graph --pretty=oneline --abbrev-commit
	* 7e61ed4 (HEAD -> master, origin/master) add author
	* 3611cfe add comment
	* f005ed4 set exit=1
	* d1be385 init hello
	...

快速解决冲突

使用工具 beyond compare

1. 安装beyond compare
2. 在 git 中配置
3. 执行以下指令
	git config --local merge.tool bc3		 --local 表示只对当前本地仓库项目有效
	git config --local mergetool.path '/usr/local/bin/bcomp'
	git config --local mergetool.keepBackup false
4. 输入命令打开beyond compare
	git mergetool
5. 会自动打开beyond compare ,在工具中进行冲突处理并保存	

多人协同开发

git flow工作流
git flow工作流

创建初始项目和版本

  1. github创建组织 new organization
  2. 添加成员
  3. 创建仓库 create repository

其他

免密码登录

解决每次 pull push 都要输入密码的问题

  • git 有自动管理凭证,实际上只需要输入一次,git就会把用户密码保存下来,mac系统中是在【钥匙串访问】应用中可以查到
  • url 中实现
	使用以下方式关联远程仓库
	git remote add origin https://用户名:密码@github.com/.....
	git push origin master
  • SSH实现
	1. 生成公钥和私钥(默认放在 ~/.ssh 目录下,id_rsa.pub 公钥,id_rsa 私钥)
		ssh-keygen
	2. 拷贝公钥的内容,设置到GitHub中
	3. 在git本地配置ssh地址
		git remote add origin git@github.com......
	4. 设置之后再push就可以
		git push origin master

自定义 Git

	git config --global color.ui true		设置Git显示颜色

问题

  • 在lhf-dev分支下修改了index.html,此时checkout到其他分支,比如master分支,此时 git status 查看,会发现master分支中index.html也会发生修改,lhf-dev 分支修改完,切换到master分支时,会出现以下代码。想要避免这种情况就,修改完后,先add,commit 再切换到其他分支
	M index.html
  • push或者pull时保存:Could not read from remote repository,使用 git remote -u 设置关联远程仓库
	和远程仓库的管理有问题,先查看远程仓库关联情况
	git remote -v
		origin /Users/wupeiqi/Desktop/git_project/realDemo.git (fetch)
		origin /Users/wupeiqi/Desktop/git_project/realDemo.git (push)
	表示现在关联的还是本地仓库

	git remote set-url origin 远程仓库地址
  • 不小心删除了master分支,怎么办?
强制删除master分支时,会给一个master的版本号
	$ git branch -D master
	Deleted branch master (was 8d78fc9).
	
	$ git branch
	* (HEAD detached at 8d78fc9)
	  dev
	  lhf-dev
	  
根据提供的master版本号,直接创建一个名称为master,带版本号的分支,就能恢复master分支
	$ git branch master 8d78fc9
  • commit 后忘记 push 了
    在公司开发commit到公司电脑本地忘记push到仓库了,于是在家开发了一些其他的功能之后 push ,到公司后 git pull origin dev 会出现分支冲突;手动解决分支冲突,继续开发push
CONFLICT (content): Merge conflict in test.html
Automatic merge failed; fix conflicts and then commit the result.
  • git clone 和 git clone --no-checkout
    项目内容很多,如果不想默认checkout到master分支,就可以 --no-checkout 再切换到想要的分支,相比 git clone 再切换分支,速度会快
	git clone 项目链接		clone到本地后会自动 checkout 到master分支,本地项目中的内容显示的都是master分支中的内容
	git clone --no-checkout 项目链接		不会自动切换到master分支,本地项目中没有内容,只要checkout到指定的分支,就可以拿到指定分支的内容
										实际上是切换到了一个删除的分支,git status 查看可以看到内容前面的 deleted:
  • Please supply the message using either -m or -F option

    在mac中,如果使用 git commit –amend,会出现如下错误:
    
    error: There was a problem with the editor ‘vi’.
    Please supply the message using either -m or -F option.
    
    原因是vi有问题,需要为 git 换一个默认的编辑器,比如 vim,如下进行配置即正常了。
    
    git config --global core.editor "vim"
    

注意

git commit 最新的代码后,git pull 不会把commit的代码覆盖,只会把git commit 之前的代码更新

分支名称的命名规则

在这里插入图片描述

面试题

  1. 紧急修复线上bug?
    创建一个新的分支,对bug进行修复,随后合并到主分支
    在这里插入图片描述
  2. 你们公司是怎么做多人协同开发?
    每人一个自己的分支,每个人在自己的分支上写代码
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值