使用git畅游代码的海洋

如果把互联网上的纷繁代码比作一片海洋,那么git就是在这片海洋上航行的船只,正所谓“水可载舟,亦可覆舟”,git使用恰当可以远征星辰,不然可能会坠入无穷无尽的代码海洋无法自拔。书回正传,我们的征途是星辰大海!

扬帆起航

git的下载安装暂且不表,可参考网站https://git-scm.com/downloads

git的安装只是个入门条件,下面如何使用git命令控制代码才是远征的基础。那么从何开始呢?让我们一步步说起。

要想扬帆起航,首先得有艘帆船吧。我们要在本地建立一个项目,之后将本地项目初始化为git仓库,可以使用

git init [--bare]

初始化本地项目,执行后会在当前执行目录下生成.git文件夹,这也就是我们的帆船了。[--bare]可选参数,可初始化裸仓库,裸仓库可以与源码项目分离,此时在当前目录下不会生成.git文件夹,而是直接生成.git文件夹下的包括hooks、info、objects、refs共四个文件夹和config、description、HEAD三个文件。

在初始化裸仓库后若想关联源码,只需进入hooks目录新建post-receive.sample文件,并添加如下内容:

git --work-tree=<project-dir> --git-dir=<local-url> checkout -f

其中<project-dir>为本地项目文件路径,<local-url>为本地git仓库路径。

 

对于当前目录下的.git文件夹所代表的本地仓库,不同的帆船有不同的配置,我们使用

git config –list

显示当前git配置。如果内容过多可以使用上下键翻页,查看结束按q退出即可。同时使用

git config –e [--global]

以vim形式编辑修改git配置文件。

git config [--global] user.name “name”

形式修改指定配置,其中[--global]可选,为全局配置,name为用户名配置。

 

 

git仪表盘

 

 

 

 

 

 

 

图 1 Git指令关系图

 

建立git仓库作为帆船后,就可以在当前目录下任意使用git指令遨游了。我们需要先认识下git控制的命令仪表盘。

如图1所示,git整艘船主要分为四大区域,包括Remote远程仓库,Repository本地仓库,Index/Stage暂存区,Workspace工作区,不同区域之间可以使用相关指令进行代码操作。在上节使用git init创建的文件夹下,会生成名为.git的隐藏文件夹,四大区域的配置都储存在该文件夹下。其中在远程仓库和本地仓库中,储存有不同的branch分支,工作区和暂存区的文件只能针对某一分支进行修改提交操作,当然也可以使用分支操作指令对不同的分支进行增删合并等操作。

针对一些仓库的操作指令,使用前请务必保持头脑清醒,不然你的一个蝴蝶煽动翅膀似的操作,可能会引发仓库里的一场代码风暴,造成不可挽回的结果。

根据不同命令操作区域,可以将git命令大致分为全局显示信息、工作区与远程仓库交互、工作区与本地仓库交互、工作区与暂存区交互、暂存区与本地仓库交互、本地仓库与远程仓库交互、以及仓库内部分支操作。下面对这些命令进行了粗略的统计介绍,详细使用方式可参考git官方文档介绍,如有不足还请补充。

显示信息

git help [command]

获取命令的帮助信息。

 

git status

显示所有变更文件

 

git log [--stat] [--graph]

显示当前分支的版本信息。[--stat]参数指定显示commit发生变更的文件。[--graph]参数以数据图形式查看合并分支记录。

 

git blame <file>

显示文件的每一行最后修改的版本和作者

 

git show [commit][:filename]

显示某次提交的变更内容。其中[commit]为某次提交版本,也可在:后边加参数[filename]指定查看某个文件内容。

 

git diff [HEAD] [first-branch] [second-branch]

显示文件差异。无参时比较缓存区和上一次commit的差异;[HEAD]为工作区与当前分支最新commit的差异;或者两个分支之间的差异。

 

git reflog

显示已执行过的所有git动作日志。

 

工作区与远程仓库

git pull <remote> <branch>

拉取远程仓库的变化,并与本地分支合并。<remote>为远程仓库名,<branch>为远程仓库中的某一分支名。

工作区与本地仓库

git checkout [–b] <branch> [tag]

将暂存区切换到分支名。其中[-b]参数可选,当分支不存在时则创建,<branch >必须,为本地仓库分支,[tag]可选,指定切换到仓库分支中的某条标签,不标注则默认为切换分支的最近一次提交。

工作区与暂存区

git add <dir>

添加指定目录到暂存区,<dir>为添加路径,允许多个,包括子目录都会添加到暂存区中等待提交。

 

git rm [--cached] <file>

删除暂存区中的文件,<file>为暂存区中要删除的文件全路径,[--cache]可选参数,只会停止继续追踪指定文件,但该文件目前仍然保留在暂存区。

 

git mv <file-old> <file-new>

修改暂存区中的文件名,<file-old>为原文件全路径,<file-new>为修改后的文件全路径。

 

 

git tag

查看暂存区中的所有标签信息。

 

git tag –a <tag> [commit]

新建一个标签。[tag]为标签名;[commit]为指定的一次从暂存区到本地仓库的提交中,默认为最新一次提交。

 

git tag –d [tag]

删除本地标签。

暂存区与本地仓库

git commit [--amend] [–m <message>] [file] [-a] [-v]

从暂存区提交到本地仓库。其中[--amend]重做上次从本地项目到暂存区的commit,当代码与上次提交相比无变化时使用,只修改上次commit的<message>内容;[-m]参数为提交信息,<message>必写且详写,以区别提交代码的修改内容;[file]为指定暂存区中的文件;[-a]可直接提交项目中的变化到本地仓库,在没有新增文件时不需每次先git add提交到暂存区再提交到本地仓库;[-v]可以在提交时显示所有变化文件的diff信息。

 

git cherry-pick [commit]

选择一个commit版本合并到当前分支,[commit]为暂存区中的commit版本。

 

本地仓库与远程仓库

git remote [-v]

查看关联的远程仓库信息。[-v]可以查看详细信息。

 

git remote add <remote-name> <remote-url>

本地路径关联远程仓库。

<remote-name>必要参数,为远程仓库的名字,默认是origin。

<remote-url>必要参数,为远程仓库的地址,git服务器通常都是以.git结尾。

 

git remote remove <remote-name>

删除关联的远程仓库。其中<remote-name>为远程仓库的名字。

 

git push [remote] [branch] [--force]

推送本地指定分支到远程仓库。[remote]为远程仓库名,[branch]为本地分支名,[--force]为强制推送本地到远程,如有冲突则覆盖。

 

git fetch <remote>

将远程仓库拉到本地仓库。<remote>为远程仓库名。

 

git clone <url> [name]

创建一个本地仓库。<url>必须,可以是远程git服务器上的仓库,也可以是本地仓库。[name]选填是创建的新仓库名,默认与原仓库名一致。

 

分支指令

git branch [-r] [-a]

查看分支信息,无参只会查看本地仓库所有分支,[-r]是远程仓库所有分支,[-a]则是包括本地和远程仓库所有的所有分支。

git branch [branch-name] [commit]

在本地仓库新建分支,但暂存区仍然指向当前分支。其中[branch-name]为新建的本地仓库分支;[commit]可将分支指向指定commit版本。

 

git branch –track [local-branch-name] [remote-branch]

新建一个分支,并连接指定的远程分支。其中[local-branch-name]为本地仓库新建分支,[remote-branch]为远程仓库分支。

 

git branch –set-upstream [local-branch] [remote-branch]

连接本地仓库分支与远程仓库分支,其中[local-branch]为本地仓库已有分支,[remote-branch]为远程仓库分支。

 

git branch –d [branch]

删除本地仓库分支,[branch]为本地仓库中的已有分支。

 

git branch -m [branch-old] [branch-new]

修改本地仓库分支,其中[branch-old]为原分支,[branch-new]为改名后的分支。

 

git branch –dr [remote-branch]

删除远程仓库分支,[remote-branch]为远程仓库中的分支。不推荐使用,如果远程仓库未更新,可能会执行失败,推荐使用git push origin-delete [remote-branch]。

 

git merge <local-branch>

合并指定分支到当前分支,<local-branch>为本地仓库中的已有分支。

 

git rebase <remote-branch>

将当前分支的提交复制到指定的远程分支上,<remote-branch>为指定远程仓库中的已有分支。

 

git reset [--mixed|--soft|--hard] [commit]

重置仓库索引,重置一旦清空后的内容不会在仓库历史版本中留下历史记录。[--mixed]为默认参数,重置后只在工作区保留原节点修改文件,清空暂存区和本地仓库并均恢复到指定重置节点;[--soft]为软重置,重置后在工作区和暂存区均保留原节点修改文件,清空本地仓库并恢复到指定重置节点;[--hard]为硬重置,重置后均不会保留原节点修改文件。[commit]为要重置的节点号。

 

git revert [commit]

还原文件到之前修改提交节点时,会在仓库历史版本中留下历史记录。[commit]为要还原的节点号。

常规操作

git这艘大船虽然功能繁杂,但是用起来是有章可循的。入门之后就驾驶下这艘大船来试试吧。

一般git有三种工作流程,包括Git flow,项目存在两个长期分支(主分支master和开发分支develop),适用于基于版本发布的普通项目;Github flow,只有一个长期分支(主分支master),适用于持续发布的小型项目;Gitlab flow,项目存在多个长期分支,其中主分支master是其他所有分支的上游,只有上游分支采纳的代码才能应用到其下游分支,适用于长期维护的大型项目。

图2展示了一次项目git流程演变过程,在master主分支上有Tag1-Tag4四次代码更新,其中基于Tag2对应的版本1号创建了新的branch1分支,新分支创建后自动生成了版本2号并打上了Tag2-1标签,之后master主分支和branch1分支都同时进行了代码演变,在branch1分支提交的版本4号及标签Tag2-3之后,branch1分支合并到了master主分支,合并前master主分支位于版本5号,合并后可能重新生成版本6号,并打上新的tag4标签,之后master主分支修改提交为版本7号,而branch1分支则停留在tag2-3标签的位置处。

 

 

 

 

 图 2 Git流程示意图

 

在这份项目流程中,分支创建之后,可能在不同的阶段修改提交文件,根据对文档的读取权限范围,我们可以形象地将这些阶段划分为三种身份类型,船长、水手和游客。船长身份,作为项目管理者,主要负责远程仓库和本地仓库之间的分支操作,协调分支冲突;水手身份,作为项目贡献者,主要负责某一分支的迭代更新;游客身份,作为项目使用者,只是访问使用仓库及其分支内容,不能提交任何修改。同一人在项目的不同阶段可以是其中任意一种身份,下面以这三种身份为维度简单介绍下使用到的相关git指令步骤,并辅以示意图方式直观解释git指令执行前后git项目变化。

 

 

项目使用者-游客

        作为git项目的游客,当然只能将项目从远程仓库拉取到本地使用,期间除了切换仓库分支外不会涉及其他远程操作。

 

git pull origin master

拉取远程仓库origin的master分支到本地。

 

git checkout branch1 tag1

切换到分支branch1。

 

 

项目贡献者-水手

        作为项目的水手,除了可以使用游客的功能指令外,还会涉及到修改工作区文件,并将工作区文件提交到暂存区和仓库等任务。通常水手只需要维护仓库中的某一条分支并只对该分支负责,因此水手更注重工作区的代码文件修改工作。

 

git pull origin dev:branch1

拉取远程仓库origin的dev分支到本地,并与本地branch1分支合并。工作区中文件即显示branch1分支,可在工作区做文件修改操作。

 

git add .

在工作区的文件修改之后,可先添加当前目录所有文件到暂存区,之后可继续修改工作区其他文件,也可将暂存区文件提交到本地仓库。

 

git rm –cached file

针对工作区编译生成的配置file文件,一般不需提交到仓库,可使用该命令将file文件从暂存区删除并停止后续追踪。另外一种添加忽略文件的方式,在.git文件夹的同级目录下新建.gitignore文件,在该文件中根据规则增加要忽略的文件路径,之后将该文件提交到本地仓库中。

 

git commit –m “commit message 1”

在确保工作区的所有修改文件均已提交到暂存区后,便将暂存区的修改提交到本地仓库,同时附带当次提交信息。每次提交都会在本地仓库生成一个新的提交commit版本号,由于提交的commit版本号是冗长的sha1码,所以为了方便后期溯源,通常会在主要的commit号版本上再打一个鲜明的标签以作标记。

 

 

 

git tag tag1 1

在提交的commit版本号为1的节点上打标签,打上标签后的commit号便可使用简短的标签名tag1访问,以便后期对该节点溯源。

 

 

 

git push origin branch1:dev –tags

将本地branch1分支及相关标签推送到远程仓库origin的dev分支。如果本地branch1分支已经与远程dev分支建立追踪关系,也可直接使用

git push origin branch1 --tags

指令。

 

git branch –set-upstream-to=origin/dev branch1

设置本地仓库的branch1分支与远程仓库origin的dev分支的追踪关系。通常从远程分支pull到本地的分支都已经建立了追踪关系,不需要手动修改。

 

git branch –vv

查看本地分支及追踪的远程分支信息。

 

项目管理者-船长

        作为项目的船长,自然拥有整个git这艘大船的项目所有权限,除了使用水手的操作指令外,另需完成分支增删合并等任务。通常船长是项目仓库的创建者,负责管理维护仓库的各分支关系,对项目的整个仓库负责,因此相较于水手,船长更注重仓库的分支管理相关工作。

 

git clone https://github.com/xxx.git -b dev

克隆远程仓库的dev分支到本地,默认会将文件更新到本地仓库建立的同名dev分支。

 

git checkout –b branch1 origin/dev

在本地仓库新建branch1分支,与远程仓库origin中的dev分支对应,并在本地切换到branch1分支。如果不指定远程仓库及分支信息origin/dev,则默认从本地仓库dev分支创建。至此可以切换为水手身份,从该分支更新代码,并将修改文件提交到该branch1分支。

 

git add .

git commit –m “modify file commit”

在完成对工作区文件的修改之后,使用水手身份将工作区的修改提交到本地branch1分支。

 

git checkout dev

切换到本地仓库的dev主分支,作为本地仓库与远程仓库代码合并的操作分支。

 

git fetch origin dev

拉取远程仓库origin中的dev分支到本地仓库当前dev分支

 

git pull

将本地仓库dev分支的文件修改合并到工作区。

 

git merge branch1

将本地仓库的branch1分支合并到当前dev分支。如果当前dev分支与branch1分支有冲突,需要根据冲突文件提示分别修改,之后再重新合并该分支。

 

git checkout branch1 build/files

或者只将branch1分支的build/files目录下所有文件合并到本地仓库的当前dev分支。同样需要做冲突处理。

 

git push origin dev:dev –tags

向远程仓库origin中的dev分支并推送本地仓库dev分支。推送时如果确认以本地分支覆盖远程分支,则可使用

 

git push —force origin dev:dev –tags

强制推送。最后如果想删除远程分支,有以下两条指令

 

git push origin –delete dev

git push origin :dev

这两种方式都可以删除指定的远程仓库origin中的dev分支。

 

应急预案

上面的图2Git流程图简单涉及了一次版本演变过程中的一些git信息,包括分支切换,打标签等,看上去简单易懂,而实际我们工作中驾船航行时却并不总是风平浪静。

        通常出现的紧急情况需要修改分支版本,包括变基、还原、重置等操作,针对不同场景需要选择不同的操作方式。

变基

git rebase master

变基会将当前分支的修改文件复制到master分支,同时创建新的commit版本号并修改项目的历史记录。当master分支已经更新,且确认当前分支与master分支没有冲突,那可以使用变基以便当前分支获取master分支的更新。

 

 

 

 

重置

git reset 1

将HEAD重置到历史提交版本1的状态,还原仓库和暂存区的文件与提交版本1一致,工作区维持修改文件状态。

 

 

 

 

还原

 

git revert 1

重新创建一次提交版本节点,文件状态与历史提交版本1一致,工作区、暂存区与仓库均保持一致。提交版本2相对于提交版本1新增了file.txt文件,执行该指令后,在提交版本3中将恢复到提交版本1的状态,因此提交版本3相对于提交版本2则删除了file.txt文件。

 

 

强制远程覆盖本地

git fetch –all

拉取远程所有仓库到本地仓库,工作区不会有任何合并更新。

 

git reset –hard origin/dev

把工作区HEAD指向最新的远程仓库origin中的dev版本。

待补充

除此之外在驾驭git这艘大船时肯定还会出现各种意外,届时将酌情补充。

 

 

 

posted on 2020-06-22 11:24  白少木丿  阅读(814)  评论(0编辑  收藏  举报

导航