目录
- git
- GitHub
- Gitlab
- 创建仓库
-
- [git init](#git init)
- [git clone](#git clone)
- 配置
- 基本操作
-
- 创建仓库命令
- 提交与修改
-
- [git commit](#git commit)
- [git status](#git status)
- 提交日志
- 远程操作
-
- [git remote 命令用于用于管理 Git 仓库中的远程仓库。](#git remote 命令用于用于管理 Git 仓库中的远程仓库。)
- [git push 命令用于从将本地的分支版本上传到远程并合并。](#git push 命令用于从将本地的分支版本上传到远程并合并。)
- 本地已有文件上传远程仓库
- 分支管理
- 查看提交历史
-
- [git log](#git log)
- [git blame](#git blame)
- [Git 标签](#Git 标签)
- SSH密钥
git
Git 是一个开源的分布式版本控制系统,用于敏捷高效地处理任何或小或大的项目。
Git 与常用的版本控制工具 CVS, Subversion 等不同,它采用了分布式版本库的方式,不必服务器端软件支持。
分布式版本控制系统(如Git)和集中式版本控制系统(如SVN)之间有几个重要的区别:
-
存储方式:
- 分布式系统:每个开发者都拥有完整的代码仓库副本,包括完整的版本历史记录。开发者可以在本地进行提交、分支、合并等操作,然后将这些操作同步到远程仓库或其他开发者的本地仓库。
- 集中式系统:代码仓库位于中央服务器上,开发者通过客户端与中央服务器进行交互。开发者在提交、分支、合并等操作时需要与中央服务器通信,本地只保存最新的代码快照而非完整的历史记录。
-
协作方式:
- 分布式系统:开发者可以在本地独立工作,无需始终连接到中央服务器。每个开发者都可以通过本地操作进行版本控制,然后按需将更改同步到其他开发者或中央仓库。
- 集中式系统:开发者需要始终连接到中央服务器才能进行版本控制操作,例如提交、分支、合并等。协作过程依赖于中央服务器的可用性和稳定性。
-
安全性和容错性:
- 分布式系统:因为每个开发者都有完整的代码仓库备份,即使中央服务器发生故障或网络中断,开发者仍然可以继续本地工作。此外,分布式系统通常具有更好的分支管理和合并功能,支持更复杂的开发工作流程。
- 集中式系统:所有操作依赖于中央服务器,如果服务器发生故障或网络中断,开发者无法提交、更新或查看历史记录,影响开发流程和团队协作。
-
分支和合并:
- 分布式系统:分支和合并操作更加灵活和高效,开发者可以在本地创建、切换和合并分支,然后再决定是否将更改推送到远程仓库。
- 集中式系统:分支和合并通常需要与中央服务器进行交互,较为受限,可能需要频繁的网络通信。
总体而言,分布式系统更加灵活、安全且具备更好的容错性,使得开发者可以更独立地工作和协作,而集中式系统则更侧重于中央控制和管理,需要始终保持与中央服务器的连接。
工作流程
使用 Git 的流程:
-
克隆 Git 资源作为工作目录:
-
在克隆的资源上添加或修改文件:
-
如果其他人修改了,你可以更新资源:
-
在提交前查看修改:
-
提交修改:
-
在修改完成后,如果发现错误,可以撤回提交并再次修改并提交 :
工作区、暂存区和版本库
- 工作区:就是你在电脑里能看到的目录。
- 暂存区:英文叫 stage 或 index。一般存放在
.git
目录下的 index 文件(.git/index)中,所以我们把暂存区有时也叫作索引(index)。 - 版本库:工作区有一个隐藏目录
.git
,这个不算工作区,而是 Git 的版本库
工作区、版本库中的暂存区和版本库之间的关系:
-
图中左侧为工作区,右侧为版本库。在版本库中标记为 "
index
" 的区域是暂存区
(stage/index),标记为 "master
" 的是master
分支所代表的目录树。 -
图中我们可以看出此时 "HEAD" 实际是指向 master 分支的一个"游标"。所以图示的命令中出现 HEAD 的地方可以用 master 来替换。
-
图中的
objects
标识的区域为 Git 的对象库
,实际位于 ".git/objects
" 目录下,里面包含了创建的各种对象及内容。 -
当执行对工作区修改(或新增)的文件执行
git add
命令时,暂存区的目录树被更新,同时工作区修改(或新增)的文件内容被写入到对象库中的一个新的对象中,而该对象的ID被记录在暂存区的文件索引中。 -
当执行提交操作(
git commit
)时,暂存区的目录树写到版本库(对象库)中,master
分支会做相应的更新。即master
指向的目录树就是提交时暂存区的目录树。 -
当执行
git reset HEAD
命令时,暂存区的目录树会被重写,被master
分支指向的目录树所替换,但是工作区不受影响。 -
当执行
git rm --cached <file>
命令时,会直接从暂存区删除文件,工作区则不做出改变。 -
当执行
git checkout .
或者git checkout -- <file>
命令时,会用暂存区全部或指定的文件替换工作区的文件。这个操作很危险,会清除工作区中未添加到暂存区中的改动。 -
当执行
git checkout HEAD .
或者git checkout HEAD <file>
命令时,会用HEAD
指向的master
分支中的全部或者部分文件替换暂存区以及工作区中的文件。这个命令也是极具危险性的,因为不但会清除工作区中未提交的改动,也会清除暂存区中未提交的改动。
GitHub
GitHub是一个面向开源及私有软件项目的托管平台,因为只支持git作为唯一的版本库格式进行托管,故名GitHub。
Gitlab
GitLab 是一个用于仓库管理系统的开源项目,使用Git作为代码管理工具,并在此基础上搭建起来的web服务。安装方法是参考GitLab在GitHub上的Wiki页面。
GitLab是由GitLabInc.开发,使用MIT许可证的基于网络的Git仓库管理工具,且具有wiki和issue跟踪功能。使用Git作为代码管理工具,并在此基础上搭建起来的web服务。
关系和区别
- 关系:GitHub 和 GitLab 都是基于 Git 的代码托管平台,提供了类似的功能,包括代码存储、版本控制、团队协作等。它们都是在 Git 的基础上构建的,并为开发者提供了一种在云端存储和管理代码的方式。
- 区别:GitHub 是一个商业化的平台,提供了公共和私有仓库、协作工具、项目管理等功能,并且有一个庞大的开发者社区。GitLab 也提供了类似的功能,但除了托管服务外,还提供了强大的持续集成和持续部署功能,并且可以自行搭建和托管。GitLab 通常更适合需要更多自定义和自主控制的企业用户。
创建仓库
-
gitlab上新建一个空白项目
gitlab上点击new project按钮,新建一个项目:
-
项目名称输入和你本地项目同样的名称:
-
点击 create project 按钮创建出该空白的项目:
git init
Git 使用 git init
命令来初始化一个 Git 仓库,Git 的很多命令都需要在 Git 的仓库中运行。
在执行完成 git init 命令后,Git 仓库会生成一个 .git 目录,该目录包含了资源的所有元数据,其他的项目目录保持不变。
-
在本地创建新的项目目录 :
在你的计算机上选择一个合适的位置,使用命令行或者文件管理器创建一个新的项目目录,例如:
bashmkdir my_project
-
进入项目目录 :
使用命令行进入到你创建的项目目录中,例如:
bashcd my_project
-
初始化 Git 仓库 :
使用
git init
命令将当前目录初始化为一个 Git 仓库,这会在该目录下生成一个隐藏的.git
文件夹,其中包含 Git 仓库的相关配置和版本控制信息,例如:bashgit init
该命令执行完后会在当前目录生成一个 .git 目录。
-
使用我们指定目录作为Git仓库。
bash
git init newrepo
初始化后,会在 newrepo 目录下会出现一个名为 .git 的目录,所有 Git 需要的数据和资源都存放在这个目录中。
- 如果当前目录下有几个文件想要纳入版本控制,需要先用 git add 命令告诉 Git 开始对这些文件进行跟踪,然后提交:
bash
$ git add *.c
$ git add README
$ git commit -m '初始化项目版本'
以上命令将目录下以 .c 结尾及 README 文件提交到仓库中。
注: 在 Linux 系统中,commit 信息使用单引号 ',Windows 系统,commit 信息使用双引号 "。
所以在 git bash 中 git commit -m '提交说明' 这样是可以的,在 Windows 命令行中就要使用双引号 git commit -m "提交说明"。
git clone
我们使用 git clone
从现有 Git 仓库中拷贝项目(类似 svn checkout)。
克隆仓库的命令格式为:
bash
git clone <repo>
如果我们需要克隆到指定的目录,可以使用以下命令格式:
bash
git clone <repo> <directory>
参数说明:
- repo:Git 仓库。
- directory:本地目录。
比如,要克隆 Ruby 语言的 Git 代码仓库 Grit,可以用下面的命令:
bash
$ git clone git://github.com/schacon/grit.git
执行该命令后,会在当前目录下创建一个名为grit的目录,其中包含一个 .git 的目录,用于保存下载下来的所有版本记录。
如果要自己定义要新建的项目目录名称,可以在上面的命令末尾指定新的名字:
bash
$ git clone git://github.com/schacon/grit.git mygrit
配置
git 的设置使用 git config
命令。
显示当前的 git 配置信息:
bash
$ git config --list
credential.helper=osxkeychain
core.repositoryformatversion=0
core.filemode=true
core.bare=false
core.logallrefupdates=true
core.ignorecase=true
core.precomposeunicode=true
编辑 git 配置文件:
bash
$ git config -e # 针对当前仓库
或者:
bash
$ git config -e --global # 针对系统上所有仓库
设置提交代码时的用户信息:
bash
$ git config --global user.name "runoob"
$ git config --global user.email test@runoob.com
如果去掉 --global 参数只对当前仓库有效。
基本操作
说明:
- workspace:工作区
- staging area:暂存区/缓存区
- local repository:版本库或本地仓库
- remote repository:远程仓库
创建仓库命令
命令 | 说明 |
---|---|
git init | 初始化仓库 |
git clone [url] [new name] | 拷贝一份远程仓库,也就是下载一个项目。 [url] 是你要拷贝的项目地址。 [new name] 是你要拷贝到本地保存的文件夹名称。 |
提交与修改
命令 | 说明 |
---|---|
git add | 添加文件到暂存区 git add . 添加当前目录下的所有文件到暂存区 git add [file1] [file2] ... 添加一个或多个文件到暂存区 git add [dir] 添加指定目录到暂存区,包括子目录 |
git status | 查看仓库当前的状态,显示有变更的文件。 |
git diff | 比较文件的不同,即暂存区和工作区的差异。 |
git commit | 提交暂存区到本地仓库。 |
git reset | 回退版本。 |
git rm | 将文件从暂存区和工作区中删除。 |
git mv | 移动或重命名工作区文件。 |
git checkout | 分支切换。 |
git switch (Git 2.23 版本引入) | 更清晰地切换分支。 |
git restore (Git 2.23 版本引入) | 恢复或撤销文件的更改。 |
git commit
git commit 命令将暂存区内容添加到本地仓库中。
bash
git commit -m [message]
[message] 可以是一些备注信息。
提交暂存区的指定文件到仓库区:
bash
$ git commit [file1] [file2] ... -m [message]
-a 参数设置修改文件后不需要执行 git add 命令,直接来提交。
git commit -a
命令用于将工作区中所有已跟踪的修改一次性添加到暂存区,并提交到版本库中,相当于先执行了git add .
将所有已跟踪的文件添加到暂存区,然后再执行git commit
。这个命令可以方便地提交对已跟踪文件的修改,但不包括新增的未跟踪文件。
bash
$ git commit -a
提交后,再执行 git status
,没有输出,说明我们在最近一次提交之后,没有做任何改动,是一个 "working directory clean",翻译过来就是干净的工作目录。
此时,gitlab上是没有文件的。
git status
git status 是一个用于查看 Git 仓库当前状态的命令。
git status 命令可以查看在你上次提交之后是否有对文件进行再次修改。
通常我们使用 -s
参数来获得简短的输出结果:
??
:未跟踪的文件,即这些文件存在于工作区中,但尚未被 Git 跟踪。A
:新添加到暂存区的文件,即这些文件已经被git add
添加到了暂存区。M
:已修改的文件,即这些文件在工作区中被修改过。D
:已删除的文件,即这些文件在工作区中被删除了,但是还未提交。R
:重命名的文件,即这些文件被重命名了,在 Git 的版本历史中可以看到重命名前后的文件名。
AM
状态的意思是这个文件在我们将它添加到缓存之后又有改动。
提交日志
命令 | 说明 |
---|---|
git log | 查看历史提交记录 |
git blame | 以列表形式查看指定文件的历史修改记录 |
远程操作
命令 | 说明 |
---|---|
git remote | 远程仓库操作 |
git fetch | 从远程获取代码库 |
git pull | 下载远程代码并合并 |
git push | 上传远程代码并合并 |
git remote 命令用于用于管理 Git 仓库中的远程仓库。
git remote 命令提供了一些用于查看、添加、重命名和删除远程仓库的功能。
bash
git remote
列出当前仓库中已配置的远程仓库,并显示它们的 URL。
git remote -v
添加一个新的远程仓库。指定一个远程仓库的名称和 URL,将其添加到当前仓库中。
git remote add origin https://github.com/user/repo.git
将已配置的远程仓库重命名。
git remote rename origin new-origin
从当前仓库中删除指定的远程仓库。
git remote remove new-origin
修改指定远程仓库的 URL。
git remote set-url origin https://github.com/user/new-repo.git
显示指定远程仓库的详细信息,包括 URL 和跟踪分支。
git remote show origin
git push 命令用于从将本地的分支版本上传到远程并合并。
命令格式如下:
bash
git push <远程主机名> <本地分支名>:<远程分支名>
如果本地分支名与远程分支名相同,则可以省略冒号:
bash
git push <远程主机名> <本地分支名>
以下命令将本地的 master 分支推送到 origin 主机的 master 分支。
bash
$ git push origin master
相等于:
bash
$ git push origin master:master
如果本地版本与远程版本有差异,但又要强制推送可以使用 --force 参数:
bash
git push --force origin master
删除主机的分支可以使用 --delete 参数,以下命令表示删除 origin 主机的 master 分支:
bash
git push origin --delete master
重新回到我们的 Gitlab仓库,可以看到文件已经提交上来了:
本地已有文件上传远程仓库
本地要上传的文件夹里,创建初始仓库
建立本地仓库和远程仓库关系并推送:
python
git remote add origin https://gitlab.xx.com/xxxx.git
查看关联关系是否成功建立:
python
git remote -v
创建分支main(可选)
将本地项目的所有文件添加到暂存区:
python
git add .
先拉取一下远程仓库内容:
python
git pull --rebase origin master
执行提交、推送命令,将项目上传到GitLab项目文件夹中:
python
# "xxx"为项目名称
git commit -m "xxx"
git push -u origin master
分支管理
Git 分支实际上是指向更改快照的指针。
列出分支
创建分支命令:
bash
git branch (branchname)
切换分支命令:
bash
git checkout (branchname)
我们创建了一个分支,在该分支上移除了一些文件 test.txt,并添加了 runoob.php 文件,然后切换回我们的主分支,删除的 test.txt 文件又回来了,且新增加的 runoob.php 不存在主分支中。
使用分支将工作切分开来,从而让我们能够在不同开发环境中做事,并来回切换。
bash
$ git checkout -b newtest
Switched to a new branch 'newtest'
$ git rm test.txt
rm 'test.txt'
$ ls
README
$ touch runoob.php
$ git add .
$ git commit -am 'removed test.txt、add runoob.php'
[newtest c1501a2] removed test.txt、add runoob.php
2 files changed, 1 deletion(-)
create mode 100644 runoob.php
delete mode 100644 test.txt
$ ls
README runoob.php
$ git checkout master
Switched to branch 'master'
$ ls
README test.txt
删除分支
删除分支命令:
bash
git branch -d (branchname)
例如我们要删除 testing 分支:
bash
$ git branch
* master
testing
$ git branch -d testing
Deleted branch testing (was 85fc7e7).
$ git branch
* master
合并分支
bash
git merge
你可以多次合并到统一分支, 也可以选择在合并之后直接删除被并入的分支。
bash
$ git branch
* master
newtest
$ ls
README test.txt
$ git merge newtest
Updating 3e92c19..c1501a2
Fast-forward
runoob.php | 0
test.txt | 1 -
2 files changed, 1 deletion(-)
create mode 100644 runoob.php
delete mode 100644 test.txt
$ ls
README runoob.php
以上实例中我们将 newtest 分支合并到主分支去,test.txt 文件被删除。
合并完后就可以删除分支:
bash
$ git branch -d newtest
Deleted branch newtest (was c1501a2).
删除后, 就只剩下 master 分支了:
bash
$ git branch
* master
合并冲突
-
创建新分支newtest
-
当前master分支2.txt内容是
-
修改分支newtest中2.txt的内容:
提交到新分支
-
切换回master,修改2.txt的内容,并提交
-
合并newtest分支,产生合并冲突
-
需要手动去修改它
指令快速查询
bash
git branch --merged # 显示所有已合并到当前分支的分支
git branch --no-merged # 显示所有未合并到当前分支的分支
git branch -m master master_copy # 本地分支改名
git checkout -b master_copy # 从当前分支创建新分支master_copy并检出
git checkout -b master master_copy # 上面的完整版
git checkout features/performance # 检出已存在的features/performance分支
git checkout --track hotfixes/BJVEP933 # 检出远程分支hotfixes/BJVEP933并创建本地跟踪分支
git checkout v2.0 # 检出版本v2.0
git checkout -b devel origin/develop # 从远程分支develop创建新本地分支devel并检出
git checkout -- README # 检出head版本的README文件(可用于修改错误回退)
git merge origin/master # 合并远程master分支至当前分支
git cherry-pick ff44785404a8e # 合并提交ff44785404a8e的修改
git push origin master # 将当前分支push到远程master分支
git push origin :hotfixes/BJVEP933 # 删除远程仓库的hotfixes/BJVEP933分支
查看提交历史
git log
在使用 Git 提交了若干更新之后,又或者克隆了某个项目,想回顾下提交历史,我们可以使用 git log
命令查看。
git log
命令用于查看 Git 仓库中提交历史记录。
git log
显示了从最新提交到最早提交的所有提交信息,包括提交的哈希值、作者、提交日期和提交消息等。
git log 命令的基本语法:
bash
git log [选项] [分支名/提交哈希]
常用的选项包括:
- p:显示提交的补丁(具体更改内容)。
- oneline:以简洁的一行格式显示提交信息。
- graph:以图形化方式显示分支和合并历史。
- decorate:显示分支和标签指向的提交。
- author=<作者>:只显示特定作者的提交。
- since/before=<时间>:只显示指定时间之后的提交。
- until/after=<时间>:只显示指定时间之前的提交。
- grep=<模式>:只显示包含指定模式的提交消息。
- no-merges:不显示合并提交。
- stat:显示简略统计信息,包括修改的文件和行数。
- abbrev-commit:使用短提交哈希值。
- pretty=<格式>:使用自定义的提交信息显示格式。
- reverse 参数来逆向显示所有日志
git blame
git blame
命令用于逐行显示指定文件的每一行代码是由谁在什么时候引入或修改的。
strong>git blame 可以追踪文件中每一行的变更历史,包括作者、提交哈希、提交日期和提交消息等信息。
如果要查看指定文件的修改记录可以使用 git blame 命令,格式如下:
bash
git blame [选项] <文件路径>
常用的选项包括:
- -L <起始行号>,<结束行号>:只显示指定行号范围内的代码注释。
- -C:对于重命名或拷贝的代码行,也进行代码行溯源。
- -M:对于移动的代码行,也进行代码行溯源。
- -C :对于重命名或拷贝的代码行进行溯源
- -M :对于移动的代码行进行溯源
- --show-stats:显示包含每个作者的行数统计信息。
Git 标签
标签介绍
发布一个版本时,我们通常先在版本库中打一个标签(tag),这样就唯一确定了打标签时刻的版本。将来无论什么时候,取某个标签的版本,就是把那个打标签的时刻的历史版本取出来。
所以,标签也是版本库的一个快照。
Git 的标签虽然是版本库的快照,但其实它就是指向某个 commit 的指针(跟分支很像对不对?但是分支可以移动,标签不能移动),所以,创建和删除标签都是瞬间完成的。
Git有commit,为什么还要引入tag?
"请把上周一的那个版本打包发布,commit号是6a5819e..."
"一串乱七八糟的数字不好找!"
如果换一个办法:
"请把上周一的那个版本打包发布,版本号是v1.2"
"好的,按照tag v1.2查找commit就行!"
所以,tag就是一个让人容易记住的有意义的名字,它跟某个commit绑在一起。
同大多数 VCS 一样,Git 也可以对某一时间点上的版本打上标签。人们在发布某个软件版本(比如 v1.0 等等)的时候,经常这么做。
新建标签
Git 使用的标签有两种类型:轻量级 的(lightweight)和含附注的(annotated)。
轻量级标签就像是个不会变化的分支,实际上它就是个指向特定提交对象的引用。
而含附注标签,实际上是存储在仓库中的一个独立对象,它有自身的校验和信息,包含着标签的名字,电子邮件地址和日期,以及标签说明,标签本身也允许使用 GNU Privacy Guard (GPG) 来签署或验证。
一般我们都建议使用含附注型的标签,以便保留相关信息;
当然,如果只是临时性加注标签,或者不需要旁注额外信息,用轻量级标签也没问题。
创建标签
-a
选项意为"创建一个带注解的标签"。
这种方式会打开一个编辑器,让你输入标签的附注信息,包括标签的作者、日期和任意的注释。
$ git tag v1.0
$ git tag -a v1.0
查看已有标签
[root@Git git]# git tag
v1.0
[root@Git git]# git tag v1.1
[root@Git git]# git tag
v1.0
v1.1
删除标签
[root@Git git]# git tag -d v1.1
Deleted tag 'v1.1' (was 91388f0)
[root@Git git]# git tag
v1.0
追加标签
如果我们忘了给某个提交打标签,又将它发布了,我们可以给它追加标签。
例如,假设我们发布了提交 85fc7e7(上面实例最后一行),但是那时候忘了给它打标签。 我们现在也可以:
bash
$ git tag -a v0.9 85fc7e7
$ git log --oneline --decorate --graph
* d5e9fc2 (HEAD -> master) Merge branch 'change_site'
|\
| * 7774248 (change_site) changed the runoob.php
* | c68142b 修改代码
|/
* c1501a2 removed test.txt、add runoob.php
* 3e92c19 add test.txt
* 3b58100 (tag: v0.9) 第一次版本提交
指定标签信息命令:
bash
git tag -a <tagname> -m "runoob.com标签"
PGP签名标签命令:
bash
git tag -s <tagname> -m "runoob.com标签"
SSH密钥
- 首先用如下命令(如未特别说明,所有命令均默认在Git Bash工具下执行)检查一下用户名和邮箱是否配置(gitlab支持我们用用户名或邮箱登录):
bash
git config --global --list
如下,则说明已经配置
- 执行,
~/.ssh
检查是否生成ssh文件夹,执行命令后切换到.ssh文件夹下。如果没有则创建.ssh,如图:
bash
# 如果没有.ssh目录(No such file or directory)
# 先执行创建目录命令:mkdir ~/.ssh
cd ~/.ssh/
- 该命令用于生成SSH密钥:
xxx一般用上面的全局配置user.email
bash
ssh-keygen -t rsa -C "xxx"
-
执行完命令后,需要连续回车三次,最后会在.ssh文件目录下生成id_rsa.pub文件,该文件中存放了SSH密钥内容
-
进入文件夹可以看到
- id_rsa文件是私钥,要保存好,放在本地,私钥可以生产公钥,反之不行。
- id_rsa.pub文件是公钥,可以用于发送到其他服务器,或者git上
-
用记事本之类的软件打开id_rsa.pub文件,并且复制全部内容。
-
进入gitlab,找到setting,再找到 SSHKeys,将复制的的内容放到 key立即可,Title随便起,如图:
-
将密钥内容粘贴到GitLab中,点击Add key按钮: