版本控制--Git

一 Git是什么

Git 是一个开源的分布式版本控制软件,用以有效、高速的处理从很小到非常大的项目版本管理。官方链接:http://git-scm.com/

Git自身完全可以做到版本控制,但其所有内容以及版本记录只能保存在本机,如果想要将文件内容以及版本记录同时保存在远程,则需要结合GitHub来使用。使用场景:

  • 无GitHub:在本地 .git 文件夹内维护历史文件
  • 有GitHub:在本地 .git 文件夹内维护历史文件,同时也将历史文件托管在远程仓库

分布式版本控制与集中式版本控制的区别:

  • 分布式:远程服务器保存所有版本,用户客户端有所有版本
  • 集中式:远程服务器保存所有版本,用户客户端有某个版本

详细可以参考:廖雪峰老师关于集中式VS分布式讲解

二 Git安装

针对于Windows上使用Git,我们可以从官网直接下载安装程序,然后一步一步完成安装即可。在终端输入“git“出现以下界面,则证明安装成功。

image

三 Git的使用

3.1 基础应用

首先我们创建一个空文件夹或者一个Django项目等,然后通过终端cd到该文件夹或项目中,执行初始化命令:

image

初始化完成后,我们会发现在当前目前中自动创建了.git文件夹,该文件是Git中最重要的文件夹,因为Git相关文件以及版本都将保存在该文件夹中。

image

这时,我们可以在当前文件夹右键选择“Git Bash Here”打开一个终端,用于对该文件夹git操作。

image

image

image

image

注意:执行git commit 命令时,可能会提示进行用户和邮箱的配置,该配置用于记录当前版本由那个用户提交:

  • git config --local user.name 'xxxx’
  • git config --local user.email ‘xxxx@qq.com’

Git把管理的文件分为了两个区域、四个状态:

git1

工作区:当前开发程序所在目录称为工作区(不包括.git文件夹),即:工作开发都是在该目录,该区域的文件会有状态的变化且状态由git自动检测,如果程序中文件做任何操作(增、删、改),文件状态均会被检测到,可以使用 “git status”命令查看。

image

版本库:工作区中的隐藏目录.git即为Git的版本库。工作区检测到有文件发生变化,那么意味着较上一个版本之后对程序进行了修改,修改完成之后,可以当做下一版本进行提交,那么就是执行“git add .”, 将所有文件提交到暂存区,然后再执行”git commit -m 'xxx’”提交到版本库的分支即可,之后可以使用”git log”命令查看版本记录。

补充说明:创建Git版本库时,Git自动为我们创建了唯一一个master分支,以及指向master的一个指针HEAD。所以,现在,git commit就是往master分支上提交更改,当然我们可以自己创建分支,后面会进行说明。

image

目前已使用Git的5个命令(除去user.name&&user.email的输入):

  • git init,初始化,表示即将对当前文件夹进行版本控制
  • git status,查看Git当前状态,如:那些文件被修改过、那些文件还未提交到版本库等
  • git add 文件名,将指定文件添加到版本库的暂存状态
  • git commit -m '提交信息',将暂存区的文件提交到版本库的分支
  • git log,查看提交记录,即:历史版本记录

其他:

  • git ls-tree head  查看分支中所有文件
  • git ls-files –s 查看暂存区和分支中所有文件

3.2 回退及恢复

image

image

另外,我们还可以通过soft/mix的新型进行回退及恢复,示意图如下:

git2

 注:checkout之间无空格

3.3 新增开发过程中之前的程序出现bug解决

方案一:stash

stash用于将工作区发生变化的所有文件获取临时存储在“某个地方”,将工作区还原当前版本未操作前的状态;stash还可以将临时存储在“某个地方”的文件再次拿回到工作区。

81041@DESKTOP-63VAB5C MINGW64 /e/PythonCode/OldboyPythonCode/Gittest (master)
$ vim app01/views.py        # 开发新功能到一半

81041@DESKTOP-63VAB5C MINGW64 /e/PythonCode/OldboyPythonCode/Gittest (master)
$ git status
On branch master
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:   app01/views.py

no changes added to commit (use "git add" and/or "git commit -a")

81041@DESKTOP-63VAB5C MINGW64 /e/PythonCode/OldboyPythonCode/Gittest (master)
$ git stash                 # 将开发到一半的新功能临时存放到“某个地方”
Saved working directory and index state WIP on master: 9958ffe 第三次提交

81041@DESKTOP-63VAB5C MINGW64 /e/PythonCode/OldboyPythonCode/Gittest (master)
$ vim new1					# 修复之前的bug

81041@DESKTOP-63VAB5C MINGW64 /e/PythonCode/OldboyPythonCode/Gittest (master)
$ git status
On branch master
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:   new1

no changes added to commit (use "git add" and/or "git commit -a")

81041@DESKTOP-63VAB5C MINGW64 /e/PythonCode/OldboyPythonCode/Gittest (master)
$ git add .					# 添加到修改bug的代码到暂存状态

81041@DESKTOP-63VAB5C MINGW64 /e/PythonCode/OldboyPythonCode/Gittest (master)
$ git commit -m "第四次提交--修复bug"		# 提交修复Bug的代码到分支
[master d48f017] 第四次提交--修复bug
 1 file changed, 2 insertions(+)

81041@DESKTOP-63VAB5C MINGW64 /e/PythonCode/OldboyPythonCode/Gittest (master)
$ git stash pop				# 将开发到一半新功能从“某个地方”再次拿会工作区继续开发
On branch master
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:   app01/views.py

no changes added to commit (use "git add" and/or "git commit -a")
Dropped refs/stash@{0} (35b1ea9487e9a23bae9ddc79c3c1d7b0678f7c03)

81041@DESKTOP-63VAB5C MINGW64 /e/PythonCode/OldboyPythonCode/Gittest (master)

特别的:执行 git stash pop 命令时,可能会遇到冲突,因为在紧急修复bug的代码和通过stash存储在“某个地方”的代码会有重合部分,所以执行 git stash pop 时候就会出现冲突,有冲突解决冲突即可。

image

1.之前的内容
def func1():
    print('func1')

def fun2():
    print('存在bug')

2.开发新功能到一半
def func1():
    print('func1')

def fun2():
    print('存在bug')

def func3():
	print('开发新功能到一半')

3. 执行git stash,回到当前版本未修改状态
def func1():
    print('func1')

def fun2():
    print('存在bug')

4. 修复bug并提交
def func1():
    print('func1')

def fun2():
    print('修复bug')

5. 继续开发新功能 git stash pop,此时会出现冲突:
def func1():
    print('func1')

def fun2():
<<<<<<< Updated upstream
    print('修复bug')
=======
    print('存在bug')

def func3():
    print('开发新功能到一半')
>>>>>>> Stashed changes

此时,需要我自行解决冲突,然后继续开发
def func1():
    print('func1')

def fun2():
    print('修复bug')

def func3():
    print('开发新功能到一半')
实例

stash相关常用命令:

  • git stash                 将当前工作区所有修改过的内容存储到“某个地方”,将工作区还原到当前版本未修改过的状态
  • git stash list           查看“某个地方”存储的所有记录
  • git stash clear       清空“某个地方”
  • git stash pop         将第一个记录从“某个地方”重新拿到工作区(可能有冲突)
  • git stash apply      编号, 将指定编号记录从“某个地方”重新拿到工作区(可能有冲突)
  • git stash drop       编号,删除指定编号的记录

方案二:branch

branch称为分支,默认仅有一个名为master的分支。一般开发新功能流程为:开发新功能时会在分支dev上进行,开发完毕后再合并到master分支。简易示例图如下:

git3

# 以下81041@DESKTOP-63VAB5C MINGW64 /e/PythonCode/OldboyPythonCode/Gittest (master)全部删除
$ git branch dev      				# 创建新分支,即:拷贝一份当前所在分支代码到新分支

$ git checkout dev					# 切换到dev分支
Switched to branch 'dev'
M       .idea/workspace.xml

$ vim app01/views.py				# 开发新功能

$ git status						# 查看状态,即:在dev分支修改了app01/views.py文件
On branch dev
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:   .idea/workspace.xml
        modified:   app01/views.py

no changes added to commit (use "git add" and/or "git commit -a")

$ git add .							# 将修改文件添加到版本库的暂存区

$ git commit -m '第八次提交--新功能开发完成'		# 将暂存区的内容提交到当前所在分支,即:dev分支
[dev 401a11e] 第八次提交--新功能开发完成
 2 files changed, 25 insertions(+), 14 deletions(-)

$ git checkout master				# 切换回master分支
Switched to branch 'master'

$ git merge dev						 # 将dev分支内容合并到master分支
Updating 98cc13d..401a11e
Fast-forward
 .idea/workspace.xml | 36 ++++++++++++++++++++++--------------
 app01/views.py      |  3 +++
 2 files changed, 25 insertions(+), 14 deletions(-)
对应操作实例

学习参考上图,如果遇到上文开发到一半需要临时修复Bug的情况,可以按照下图的流程进行:

git4

# 以下81041@DESKTOP-63VAB5C MINGW64 /e/PythonCode/OldboyPythonCode/Gittest (master)删除
$ git branch			 	 # 查看所有分支
* master

$ git branch dev		 	 # 创建dev分支用于开发新功能

$ git checkout dev		 	 # 切换到dev分支
Switched to branch 'dev'

$ vim app01/views.py		 # 开发新功能到一半,需要紧急修复Bug

$ git add .

$ git commit -m '新功能2开发到一半'    # 新功能上传到dev分支
[dev fceb7c0] 新功能2开发到一半
 1 file changed, 3 insertions(+)

$ git checkout master		 # 切换回master分支
Switched to branch 'master'

$ git branch bug			 # 创建bug分支

$ git checkout bug 			 # 切换到bug分支
Switched to branch 'bug'

$ vim app01/tests.py			   	 	# 修改bug

$ git add .

$ git commit -m '紧急修复bug'			# 提交bug
[bug 02e3a46] 紧急修复bug
 1 file changed, 2 deletions(-)

$ git checkout master					# 切换回master
Switched to branch 'master'

$ git merge bug							# 将bug分支内容合并到master分支,表示bug修复完毕,可以上线
Updating 401a11e..02e3a46
Fast-forward
 app01/tests.py | 2 --
 1 file changed, 2 deletions(-)

$ git checkout dev						# 切换到dev分支,继续开发新功能
Switched to branch 'dev'

$ vim app01/views.py				    # 继续开发其他一半功能

$ git add .

$ git commit -m '新功能2开发完成'		# 提交新功能
[dev 93f3d72] 新功能2开发完成
 1 file changed, 1 insertion(+), 1 deletion(-)

$ git checkout master					# 切换回master分支
Switched to branch 'master'

$ git merge dev							# 将dev分支合并到master分支
Merge made by the 'recursive' strategy.
 app01/views.py | 3 +++
 1 file changed, 3 insertions(+)
对应操作实例

注意:git merge 时也可能会出现冲突,解决冲突的方式上述stash相同,即:找到冲突文件,手动修改冲突并提交,此处不再敖述。

branch相关常用命令:

  • git branch 分支名称              创建分支
  • git checkout 分支名称          切换分支
  • git branch -m 分支名称        创建并切换到指定分支
  • git branch                                查看所有分支
  • git branch -d 分支名称         删除分支
  • git merge 分支名称               将指定分支合并到当前分支

四 GitHub的使用

GitHub,一个基于Git实现的代码托管的平台,可以将内容以及版本记录在远程也保存一份,这样就不用U盘咯(类似于云盘)。PS: 类似GitHub的产品还有许多,如:GitLab、Bitbucket、码云等。

git5

4.1 GitHub基础

基于GitHub实现代码托管,需要一下步骤:

第一步:注册GitHub

第二步:创建仓库,创建完仓库后会有一个URL代指该仓库,如:

imageimage

第三步:git 可以用该URL进行向远程推送版本信息或获取版本信息

git6

4.2 GitHub的上传与下载

1.将本地部分功能代码推送到GitHub

image

GitHub上面即存在该项目

image

2.在其他地方(公司)第一次从GitHub获取代码

为了模拟效果,在本地其他地方创建一个空的文件夹。

image

3.在本地还是之前的版本,所以我们需要从GitHub上获取最新的版本

image

image

4.在其他地方(公司)再次从GitHub获取代码

image

上文执行过程中执行 “git pull origin 分支”命令等同于“git fetch origin 分支”+ “git merge origin/分支”,并且在执行过程中可能会出现冲突,原因是由于本地代码和获取的最新代码有重合部分,那么就需要自己手动解决冲突然后再继续开发。

注意:上述方式可适用于“某一方忘记上传至GitHub;另一方先将GitHub最新的代码下载下来开发新功能,上传至GitHub;某一方从GitHub上获取先通过git fetch获取新的,再通过git merge 与本地合并”。

相关常用命令:

  • git remote –v                                               查看远程库信息
  • git romote add origin https://…               创建本地与GitHub的一种关系
  • git push origin master/dev                       将本地master/dev分支内容以及版本信息推送到GitHub
  • git clone  https://…                                    从GitHub上获取项目,默认只获取master分支
  • git branch dev origin/dev                         创建dev分支且和远程dev分支同步
  • git pull origin dev                                       从远程GitHub仓库获取dev分支最新内容,并合并到本地
  • git fetch origin dev                                    从GitHub仓库获取dev分支最新内容到版本库的分支
  • git merge origin/dev                                 将指定分支合并到当前分支

4.3 GitHub协同开发

方式一:合作者,将其他用户添加到仓库合作者中,之后该用户就具有向当前仓库提交代码的权利。

image

方式二:组织,创建一个组织,然后在该组织下可以创建多个项目,组内成员可以向组内所有项目提交代码。PS:也可以对某个项目指定合作者

image

举个例子,三人协同开发程式:

  • 创建程序
    • 用户A创建程序,提交到GitHub
    • 用户B克隆项目
    • 用户C克隆项目
  • 开发功能
    • 用户A开发功能1
    • 用户B开发功能2
    • 用户C开发功能3
  • 提交
    • 用户A提交功能1,并push(A用户手速快,先提交)
    • 用户B提交功能2,无法push,因为GitHub上已经有其他人提交的新代码。
      解决方法:从GitHub上获取最新代码并合并到本地,提交自己开发的功能2。
    • 用户C提交功能3,无法push,无法提交,因为GitHub上已经有其他人提交的新代码。
      解决方法:从GitHub上获取最新代码并合并到本地,提交自己开发的功能3。
  • 获取最新代码
    • 用户A获取最新代码
    • 用户B获取最新代码
    • 用户C获取最新代码

当出现已有用户提交,自己无法提交时有以下三种处理方式:

1. git pull origin master  -->  git push origin master

2. git fetch origin master –>  git merge origin/master –> git push origin master

3. git fetch origin master –>  git rebase origin/master –> git push origin master

前两种方式记录中会出现合并,而第三种可以保证版本记录干净整洁。

注意:实际工作中每个人创建一个分支,各自都在各自的分支上写代码,互不影响。在一段时间内会合并一次。但是这个分支不是dev,而是review分支,当boss确认后再合并到dev分支。

1.在master基础上创建一个dev分支
	git branch dev
	git checkout dev
	git push origin dev

2.再创建了一个review分支
	git branch review
	gir checkout review
	git push origin review

3.创建各自的分支
	git branch zhangsan
	git branch lisi
	git branch wangwu

	git checkout zhangsan
	...
	git pull origin review
对应操作实例

4.4 fork

当我们在GitHub上发现好的项目想自己玩玩时,可以使用fork功能:

第一步:找到想搞的项目,fork一下,然后这个项目就会出现在自己仓库中

image

第二步:在自己仓库获取代码并进行编辑、提交

第三步:创建并提交一个pull request,然后等待原作者是否同意这个pull request,如果同意那么在作者的源代码中就推出现个人提交的功能

image

五 ssh认证

在之前的操作我们都是通过http方式进行git与GitHub之间的认证,但是每次都需要输入用户名或密码,相当繁琐,我们可以通过ssh方式操作,避免每次都需要输入用户名和密码,具体操作步骤如下:

第一步:在本地创建ssh key

image

第二步:在github上,进入 Account Settings(账户配置),左边选择SSH Keys,Add SSH Key,填写title,粘贴刚刚生成的key,点击添加按钮。

imageimage

为了验证是否成功,在git bash下输入:

$ ssh -T git@github.com
如果是第一次的会提示是否continue,输入yes就会看到下面提示,则代表成功连接:
Hi xxx! You've successfully authenticated, but GitHub does not provide shell access.

六 其他

1.错误1:

fatal: remote origin already exists.

解决办法如下:

    1.先输入$ git remote rm origin

    2.再输入$ git remote add origin ‘新的url’即可

2.如果在git pull提示时“no tracking information”,则说明本地分支和远程分支的链接关系没有创建,用命令:

git branch --set-upstream branch-name origin/branch-name

3. git pull 失败 ,提示:

fatal: refusing to merge unrelated histories

在进行git pull 时,添加一个可选项:

git pull origin master --allow-unrelated-histories

4.补充

git rm和rm的区别?

git rm:同时会将这个删除操作记录下来。git rm 删除过的文件,执行 git commit -m "abc" 提交时,会自动将删除该文件的操作提交上去
rm :仅仅删除物理文件,没有将其从 git 的记录中剔除。单纯执行 git commit -m "abc" 提交时,则不会将删除该文件的操作提交上去,需要在执行commit的时候,多加一个-a参数。

怎样删除远程仓库的文件或目录

git rm -r --cached xxx/1.txt    # 删除xxx目录下的2.txt文件  -r参数用于递归删除目录
git commit -m "删除xxx目录下的1.txt文件" 
git push

5.怎样恢复本地误删文件

# 第一步
git reset HEAD 删除文件路径

# 第二步
git checkout 删除文件路径

 

 

参考:http://www.cnblogs.com/wupeiqi/articles/7295372.html

posted @ 2018-12-11 15:12  Joe1991  阅读(189)  评论(0)    收藏  举报