教程:Git教程-廖雪峰官方网站

Git 实际上包括两个仓库,一个是本地仓库,另一个是远程仓库。其中的 git add, git commit 等命令都是针对本地仓库的。这也就是说,你完全可以不采用 Github 以及 Gittee 之类的远程仓库来管理自己的软件。但是常用的方式还是将代码和远程仓库关联起来,这些关联需要用到 git push, git pull 之类的命令。

本地仓库管理

如果不需要和 Github 或者 Gittee 的远程仓库进行关联,那么可以按照下面的命令进行版本管理。

新建仓库

  1. # 新建程序文件夹
  2. mkdir MyProject
  3. cd MyProject
  4. # 新建本地仓库
  5. git init

添加文件到仓库

假设新建了 videoProcess.py 文件

  1. git add videoProcess.py

当然,可以同时添加多个文件:git add file1 file2 file3 ...
当然,也可以多次添加文件

提交文件到仓库

如上所示,已知 videoProcess.py 已经被添加到仓库了,如果要提交

  1. git commit -m 'some messeage'

运行上面的命令,将会把所有 add 到仓库的文件一次性提交到仓库。
-m 后面的信息可以是任意的,但是最好是一些和版本相关的信息,方便进行回溯:运行 git log 可以查看之前提交的版本,以及 commit 信息(-m 后的 messeage)
Git 简单命令 - 图1
add 命令将工作区的文件添加到暂存区(stage),commit 命令实现最终的暂存区到版本区提交。

文件状态查询

文件是否被修改,是否被新建,是否添加到了暂存区,是否被提交,是否被跟踪表示了文件的状态。

  1. git status

工作区和版本库文件差异对比

  1. git diff HEAD -- videoProcess.py

撤销修改

撤销修改

  • 用暂存区或者版本库里面的文件来替换当前工作区的文件,从而撤销对当前文件的一些修改。
  • 撤销暂存区的文件

第一种情况:

  1. git checkout -- videoProcess.py

第二种情况:

  1. git reset HEAD videoProcess.py

实现将添加到暂存区的文件,
git reset 命令既可以回退版本,也可以把暂存区的修改回退到工作区。当我们用 HEAD 时,表示最新的版本。

  • reset 就相当于一次重置操作,类似于电脑重启。它会清空暂存区的信息(貌似这里会回退到工作区)

    其中的 -- 很重要,不加就是分支操作

删除文件

本地新建文件和删除文件,都会被 git 记录,工作区新建只需要 git addgit commit 就可以实现工作区和版本库的统一了。如果本地删除文件的话,那么如果需要版本库和工作区文件统一,就需要

  1. git rm filename
  2. git commit -m "remove filename"

如果是误删文件,那么可以利用上面所说的撤销修改命令 git checkout从版本库或者暂存区进行文件的恢复

回退版本

每一次 commit 就是一次版本的更新,对于版本的倒退、前进等操作类似一个指针的操作。HEAD 表示当前版本,HEAD^ 表示上一个版本,HEAD^^ 表示上上一个版本,以此类推。当然如果回溯版本太多也可以用 HEAD~100(回退100)之类的简写

  1. git reset --hard HEAD^

reset 命令将版本指针移动实现版本的切换。调用上述的回退指令之后,再次调用 git log 将发现最近一次的 commit 记录已经消失。

hard 的作用

版本前进

git 可以实现版本的回退,当然也可以实现版本的前进,只需要 reset 版本指针即可。每一个版本,都有一个唯一的 commit id 用来作为版本的标识,例如(调用 git reflog 来查看每一次 commit 信息,即使版本回退,也可以查到之前 commit 的 id):
image.png
图中,黄色十六进制数字就是每一次 commit 的 id,借助这个 id 可以实现版本的任意跳转(不同的 id)

  1. git reset --hard a9d51c4

运行上述命令,版本将会变为最后一次 commit 的版本,也即是实现了版本的前进(相对于之前回退来说)

远程仓库关联

假设远程仓库和本地以及本地 git 的 SSH Key 公钥以及配置好。
那么在 Github 或者 Gittee 新建一个 repository,之后将本地的仓库与之关联即可。

本地和远程关联

采用 git remote add 命令

  1. git remote add origin git@github.com:yangyangtaotao/test.git

origin 是远程仓库的名称,这是默认名称

本地文件推送到远程库

  1. git push -u origin master

由于远程库是空的,我们第一次推送 master 分支时,加上了 -u 参数,Git 不但会把本地的 master 分支内容推送的远程新的 master 分支,还会把本地的 master 分支和远程的 master 分支关联起来,在以后的推送或者拉取时就可以简化命令(省略 -u)。

查看远程库信息

  1. git remote -v

image.png
远程库为 origin

删除远程库

要删除 orgin 库的话

  1. git remote rm origin

此处的“删除”其实是解除了本地和远程的绑定关系,并不是物理上删除了远程库。远程库本身并没有任何改动。要真正删除远程库,需要登录到GitHub,在后台页面找到删除按钮再删除。

远程克隆

这是应用最为广泛的一条命令之一

  1. git clone git@github.com:yangyangtaotao/test.git

分支管理

分支创建与合并

版本回退 里,你已经知道,每次提交,Git 都把它们串成一条时间线,这条时间线就是一个分支。截止到目前,只有一条时间线,在 Git 里,这个分支叫主分支,即 master 分支。HEAD 严格来说不是指向提交,而是指向master,master 才是指向提交的,所以,HEAD指向的就是当前分支。
Git 简单命令 - 图4 Git 简单命令 - 图5

新建分支

  1. git checkout -b dev

git checkout 命令加上 -b 参数表示创建并切换,相当于以下两条命令:

  1. git branch dev
  2. git checkout dev

git checkout 都有一种从非工作区进行信息提取的感觉(?)

由于 git checkout 前面可以用于对文件的操作,所以容易混淆,可以采用下面的代码实现同样的功能

  1. git switch -c dev

-c 有 create 之意,切换已有分支 git switch dev

查看当前分支

  1. git branch

分支合并

  1. git checkout master
  2. git merge dev

将 dev 分支合并到了当前分支(master 分支)

Git 怎么合并呢?最简单的方法,就是直接把 master 指向 dev 的当前提交,就完成了合并,这就是 fast forward 模式罗?

删除分支

  1. git branch -d dev

-d 参数表示删除之意

解决冲突

Git 简单命令 - 图6
例如 master 和 feature1 分支中的相同文件存在不同之处,就会产生冲突。因为合并的时候,无法确定以哪个文件作为标准。在这种情况下需要手动修改冲突的文件(合并命令之后冲突地方将会被标注出来),然后进行提交。提交之后上面的分支将变为:
Git 简单命令 - 图7

git log --graph 可以查看分支图

分支管理

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

  1. git merge --no-ff -m "merge with no-ff" dev

禁止 Fast forward 模式:--no-ff 需要 -m 实现一次 commit

Git 简单命令 - 图8

和前面图对比?(当然不能和分支冲突解决那个图对比)

分支策略

在实际开发中,我们应该按照几个基本原则进行分支管理(多分支):

  • 首先,master 分支应该是非常稳定的,也就是仅用来发布新版本,平时不能在上面干活;
  • 干活都在dev分支上,也就是说,dev分支是不稳定的,到某个时候,比如1.0版本发布时,再把dev分支合并到master上,在master分支发布1.0版本;
  • 你和你的小伙伴们每个人都在dev分支上干活,每个人都有自己的分支,时不时地往dev分支上合并就可以了。

所以,团队合作的分支看起来就像这样:
Git 简单命令 - 图9

这些分支都是本地的版本库,团队开发肯定需要借助远程库作为中转的。那么远程库如何中转呢?

Bug 分支

处理 bug 的通常流程是:新建一个处理 bug 的分支,将当前尚未完成的工作隐藏(因为当前分支上面还有没有完成的工作,而且还没有提交,如果直接切换分支,之后切回来之后没有提交的信息将丢失),然后切换到 bug 分支完成 bug 修复,最后恢复之前没有完成的工作。

由此可见,分支切换,是从版本区进行分支的恢复(会丢失没有提交的信息,所以完成的工作需要及时提交)。文件恢复同样类似,所以二者才会采用相同的命令 git checkout

隐藏工作现场

  1. git stash

修复 bug 时,先要确定在哪个分支进行 bug 的修复。确定之后在该分支新建一个 bug 分支即可,修复完之后与原分支合并。

查看被隐藏的现场

  1. git stash list

恢复隐藏现场

  1. git stash pop
  2. # 等价于
  3. # git stash apply
  4. # git stash drop

git stash apply 不会删除 stash 内容,需要用 git stash drop 来进行删除

复制特定提交到当前分支

  1. git cherry-pick 4c805e2 # 4c805e2 是修改 bug 分支提交的 commit id

运行这个命令,会自动进行一次 commit 提交操作

多人协作

创建远程库的分支

要在 dev 分支上开发,就必须创建远程 origin 的 dev 分支到本地,于是用这个命令创建本地 dev 分支

  1. git checkout -b dev origin/dev

推送其它分支到远程库

  1. git push origin dev

这是需要首先创建远程库的分支,然后才能这样推送; 貌似我这边测试,直接新建 dev 分支之后,直接就可以推送 dev 分支到远程库

多分支 pull

如果别人更新了远程库,你如果需要更新需要首先从远程库进行 pull 抓取更新,然后在本地解决冲突合并,然后在 push 到远程库。如果存在多个分支的话,不能直接利用 git pull 进行分支的抓取,需要采用

  1. git branch --set-upstream-to=origin/dev dev
  2. # 如果是更新 master 的话:git branch --set-upstream-to=origin/master master

直接 pull 不成功原因是没有指定本地 dev 分支与远程 origin/dev 分支的链接,根据提示,采用上面大的命令设置 dev 和origin/dev 的链接。

由此观之,pull 的话不是直接将整个远程库的东西全抓取过来,它是根据分支进行抓取的。并且我们 push 的时候也是按分支进行 push。如果说远程库也具有版本的记忆能力的话,那么它记忆的最多是每次 push 的版本。

因此,多人协作的工作模式通常是这样:

  1. 首先,可以试图用 git push origin <branch-name> 推送自己的修改;
  2. 如果推送失败,则因为远程分支比你的本地更新,需要先用 git pull 试图合并;
  3. 如果合并有冲突,则解决冲突,并在本地提交;
  4. 没有冲突或者解决掉冲突后,再用 git push origin <branch-name> 推送就能成功!

如果 git pull 提示 no tracking information,则说明本地分支和远程分支的链接关系没有创建,用命令 git branch --set-upstream-to <branch-name> origin/<branch-name>
这就是多人协作的工作模式,一旦熟悉了,就非常简单。

由此观之,貌似是这样的:只有本地的版本库能够保存诸多 commit 之后的版本。远程库可以共享本地的多个分支,但是每个分支只能保存最新的版本。所以版本的控制貌似主要是针对于本地的版本库,远程的只能保存最新的???

其它