古之立大事者,不惟有超世之才,亦必有坚忍不拔之志 —— 苏轼
先说概念
Git 是目前最火的版本控制软件,在我们学习 Git 之前我们先来了解一下 软件版本控制的概念。
软件版本控制是什么
版本控制软件提供了完备的版本管理功能,用于存储、追踪目录(文件夹)和文件的修改历史,是软件开发者必备工具,是软件公司的基础设施。版本控制软件的最高目标,是支持软件公司的配置管理活动,追踪多个版本的开发和维护活动,及时发布软件。其主要功能有:
- 集中管理档案,安全授权机制:档案集中地存放在服务器上,经系统管理员授权给各个用户。用户通过
check in和check out的方式访问服务器上的文件,未经授权的用户则无法访问服务器上的文件。 - 软件版本升级管理: 每次登陆时,在服务器上都会生成新的版本,任何版本都可以随时检出编辑。
- 加锁功能:在文件更新时保护文件,避免不同的用户更改同一文件是发生冲突。
- 提供不同版本源程序的比较。
版本控制系统分为三大类:本地版本控制系统,集中式版本控制系统和分布式版本控制系统
本地版本控制系统
本地版本控制是将文件的各个版本存放在磁盘,使用这种方式在已经程度上解决了手动复制粘贴的问题,但无法解决多人协作的问题。
集中式版本控制系统
集中式版本控制系统的版本库集中放置在中央服务器中。开发人员需要先从版本控制中央服务器获取最新版的内容,开发工作完成后,需要再将本地内容提交给版本控制中央服务器。 集中式版本控制系统最大的毛病就是必须联网才能工作。如果是局域网还好,带宽够大,速度够快。可是如果是互联网的话,受到带宽的限制。分布式版本控制
分布式版本控制系统
和集中式版本控制系统相比,分布式版本控制系统的安全性要高很多,因为每个开发人员电脑里都有完整的版本库,某一个开发人员的电脑坏掉了不要紧,随便从其他开发人员那里复制一个就可以了。而集中式版本控制系统的中央服务器要是出了问题,所有开发人员都没法工作。
Git 概述
Git 是目前世界上最优秀的软件版本控制系统。Git 是一个开源的分布式版本控制系统,可以有效、高速的处理从很小到非常大的项目版本管理。
Git 是 Linus Torvalds 为了帮助管理 Linux 内核开发而开发的一个开放源码的版本控制软件。Torvalds 开始着手开发 Git 是为了作为一种过渡方案来替代 BitKeeper ,后者之前一直是 Linux 内核开发人员在全球使用的主要源代码工具。
尽管最初Git的开发是为了辅助 Linux 内核开发的过程,但是已经发现在很多其他自由软件项目中也使用了 Git。
Git官方如下
Git 的特点:
- 分支更快、更容易。
- 支持离线工作;本地提交可以稍后提交到服务器上。
- Git 提交都是原子的,且是整个项目范围的,而不像 CVS 中一样是对每个文件的。
- Git 中的每个工作树都包含一个具有完整项目历史的仓库。
- 没有哪一个 Git 仓库会天生比其他仓库更重要。
Git 配置
Git 的客户端在进行安装完之后需要进行一些配置,配置命令如下所示:
git config --global user.name "你的名字"
git config --global user.email 你的邮箱
# 例如
git config --global user.name "is_sweet"
git config --global user.email "is_sweet@163.com"
因为 Git 是分布式版本控制系统,所以每一台电脑注册用户信息(名称和 Email 地址)。
值得注意的是,git config 命令的 --global 参数,表示当前这台电脑上所有的 Git 仓库都会使用这个配置,当然也可以对某个仓库指定不同的用户名和 Email 地址。
Git 操作
工作区、暂存区和版本库
- 工作区:就是你在电脑里能看到的目录。
- 暂存区:英文叫 stage 或 index。一般存放在
.git目录下的 index 文件(.git/index)中,所以我们把暂存区有时也叫作索引(index)。 - 版本库:工作区有一个隐藏目录
.git,这个不算工作区,而是 Git 的版本库。
如下图展示三者之间的关系:
创建仓库
创建仓库分为两种方式,分别是创建一个新的仓库,另一种方式是克隆一个已有的仓库。
git init
git init 命用于在目录中创建一个新的 Git 仓库。Git 的很多命令都需要在 Git 的仓库中运行,所以 git init 是使用 Git 的第一个命令。
示例代码如下所示:
is_sweet@Sweet MINGW64 /b/Practice code
$ mkdir is_sweet # 创建文件夹
is_sweet@Sweet MINGW64 /b/Practice code
$ cd is_sweet/ # 切换目录
is_sweet@Sweet MINGW64 /b/Practice code/is_sweet
$ git init # 创建 Git 仓库
Initialized empty Git repository in B:/Practice code/is_sweet/.git/
is_sweet@Sweet MINGW64 /b/Practice code/is_sweet (master)
$ ls -a # 查看是否创建成功
. .. .git
在执行完成 git init 命令后,Git 仓库会生成一个 .git 目录,该目录包含了资源的所有元数据,其他的项目目录保持不变。
现在我们已经创建好了这个 Git 本地仓库,有了这个本地仓库,我们还需要在代码托管平台创建一个仓库,这里以 GitHub 为例,我们创建一个仓库,账号注册这里就不做赘述了,
点击 New repository 按钮会弹出如下界面
这里是创建仓库需要的信息,如下所示
点击 Create repository 创建这个仓库,创建完仓库之后我们可以得到这个仓库的地址,地址有两种方式分别是
HTTPS
https://github.com/Is-Sweet/test.git
SSH
git@github.com:Is-Sweet/test.git
我们在我们的本地新建一个 README.md 文件,写入123321
is_sweet@Sweet MINGW64 /b/Practice code/is_sweet (master)
$ touch README.md # 新建文件
is_sweet@Sweet MINGW64 /b/Practice code/is_sweet (master)
$ vi README.md # 编辑文件
现在我们就将我们新建的仓库推送到这个 GitHub 仓库上,代码如下所示:
is_sweet@Sweet MINGW64 /b/Practice code/is_sweet (master)
$ git add README.md # 1. 将文件添加的 Git 的缓冲区
warning: LF will be replaced by CRLF in README.md.
The file will have its original line endings in your working directory
is_sweet@Sweet MINGW64 /b/Practice code/is_sweet (master)
$ git commit -m "这是第一个文件" # 2. 从Git的暂存区提交版本到仓库,参数-m后为当次提交的备注信息
[master (root-commit) e1246ac] 这是第一个文件
1 file changed, 1 insertion(+)
create mode 100644 README.md
is_sweet@Sweet MINGW64 /b/Practice code/is_sweet (master)
$ git remote add test https://github.com/Is-Sweet/test.git # 3. 添加远程版本库
is_sweet@Sweet MINGW64 /b/Practice code/is_sweet (master)
$ git push -u test master # 4. 将本地的Git仓库信息推送上传到服务器 master 分支,这里可能会弹出如下界面,输入账号密码即可
Logon failed, use ctrl+c to cancel basic credential prompt.
# 5. 输入账号密码
Username for 'https://github.com': Is-Sweet
Password for 'https://Is-Sweet@github.com':
Enumerating objects: 3, done.
Counting objects: 100% (3/3), done.
Writing objects: 100% (3/3), 248 bytes | 248.00 KiB/s, done.
Total 3 (delta 0), reused 0 (delta 0), pack-reused 0
To https://github.com/Is-Sweet/test.git
* [new branch] master -> master
Branch 'master' set up to track remote branch 'master' from 'test'.
git clone
我们可以直接使用 git clone 从现有 Git 仓库中拷贝项目。
语法结构如下所示:
git clone <repo> <directory>
参数说明:
- repo**:** Git 仓库。
- directory: 本地目录。
这里我们将我们新建的那个 GitHub 仓库 克隆到本地,示例代码如下所示:
is_sweet@Sweet MINGW64 /b/Practice code
$ git clone https://github.com/Is-Sweet/test.git # 克隆 Git 仓库 这里还会让你登陆 用户
Cloning into 'test'...
Logon failed, use ctrl+c to cancel basic credential prompt.
Username for 'https://github.com': Is-Sweet
Password for 'https://Is-Sweet@github.com':
remote: Enumerating objects: 3, done.
remote: Counting objects: 100% (3/3), done.
remote: Total 3 (delta 0), reused 3 (delta 0), pack-reused 0
Unpacking objects: 100% (3/3), 228 bytes | 1024 bytes/s, done.
is_sweet@Sweet MINGW64 /b/Practice code
$ ls
is_sweet test
is_sweet@Sweet MINGW64 /b/Practice code
$ cd test
is_sweet@Sweet MINGW64 /b/Practice code/test (master)
$ ls
README.md
is_sweet@Sweet MINGW64 /b/Practice code/test (master)
$ cat README.md
# 123321
这里创建仓库的两种方式已经介绍完了。
Git 的基础操作
提交与修改
Git 的提交与修改主要通过以下几个命令来完成的,如下表所示
| 命令 | 说明 |
|---|---|
git add | 添加一个或多个文件到暂存区 |
git status | 查看仓库当前的状态,显示有变更的文件。 |
git diff | 比较文件的不同,即暂存区和工作区的差异。 |
git commit | 提交暂存区到本地仓库。 |
git reset | 回退版本。 |
git rm | 删除工作区文件。 |
git mv | 移动或重命名工作区文件。 |
示例代码如下所示:
is_sweet@Sweet MINGW64 /b/Practice code/test (master)
$ touch file{1..10}.txt # 创建文件
is_sweet@Sweet MINGW64 /b/Practice code/test (master)
$ ls # 验证是否创建成功
README.md file10.txt file3.txt file5.txt file7.txt file9.txt
file1.txt file2.txt file4.txt file6.txt file8.txt
# git add 语法结构如下所示:
# git add [file1] [file2] 或者 git add [dir]
is_sweet@Sweet MINGW64 /b/Practice code/test (master)
$ git add .
# 查看在你上次提交之后是否有对文件进行再次修改。
is_sweet@Sweet MINGW64 /b/Practice code/test (master)
$ git status
On branch master
Your branch is up to date with 'origin/master'.
Changes to be committed:
(use "git restore --staged <file>..." to unstage)
new file: file1.txt
...
# 使用 -s 参数来获得简短的输出结果:
is_sweet@Sweet MINGW64 /b/Practice code/test (master)
$ git status -s
A file1.txt
....
# 将暂存区内容添加到本地仓库中
# 语法结构 git commit [file1] [file2] ... -m [message]
# -a 参数设置修改文件后不需要执行 git add 命令,直接来提交
is_sweet@Sweet MINGW64 /b/Practice code/test (master)
$ git commit -m '提交'
远程操作
远程操作仓库的常用指令如下所示:
| 命令 | 说明 |
|---|---|
git remote | 远程仓库操作 |
git pull | 下载远程代码并合并 |
git push | 上传远程代码并合并 |
git remote 命令
git remote -v # 显示所有远程仓库:
git remote show [remote] # 显示某个远程仓库的信息:
git remote add [shortname] [url] # 添加远程版本库:
git remote rm name # 删除远程仓库
git remote rename old_name new_name # 修改仓库名
git push 命令
git push <远程主机名> <本地分支名>:<远程分支名>
# 如果本地分支名与远程分支名相同,则可以省略冒号:
git push <远程主机名> <本地分支名>
# 例如
git push origin master:master
git pull 命令
git pull <远程主机名> <远程分支名>:<本地分支名>
# 实例
is_sweet@Sweet MINGW64 /b/Practice code/is_sweet (master)
$ git pull test master # 如果远程分支是与当前分支合并,则冒号后面的部分可以省略。
Git 分支管理
几乎每一种版本控制系统都以某种形式支持分支。使用分支意味着你可以从开发主线上分离开来,然后在不影响主线的同时继续工作。
有人把 Git 的分支模型称为必杀技特性,而正是因为它,将 Git 从版本控制系统家族里区分出来。
到目前的操作,我们的 Git 仓库中只有一个分支,这个分支在 Git 中也叫主分支,也就是 master 分支。
查看、创建、切换分支和更新内容
查看分支命令
is_sweet@Sweet MINGW64 /b/Practice code/is_sweet (master)
$ git branch
* master
创建分支命令
is_sweet@Sweet MINGW64 /b/Practice code/is_sweet (master)
$ git branch myMaster # git branch (branchname)
切换分支命令
is_sweet@Sweet MINGW64 /b/Practice code/is_sweet (myMaster)
$ git checkout myMaster
Already on 'myMaster' # git checkout (branchname)
修改某个文件并推送
is_sweet@Sweet MINGW64 /b/Practice code/is_sweet (myMaster)
$ vi test1.txt
is_sweet@Sweet MINGW64 /b/Practice code/is_sweet (myMaster)
$ git add test1.txt # 提交到暂存区
warning: LF will be replaced by CRLF in test1.txt.
The file will have its original line endings in your working directory
is_sweet@Sweet MINGW64 /b/Practice code/is_sweet (myMaster)
$ git status # 查看暂存区内容
On branch myMaster
Changes to be committed:
(use "git restore --staged <file>..." to unstage)
modified: test1.txt
is_sweet@Sweet MINGW64 /b/Practice code/is_sweet (myMaster)
$ git commit -m 'test' # 提交到本地仓库
[myMaster 6bdd4fc] test
1 file changed, 1 insertion(+)
is_sweet@Sweet MINGW64 /b/Practice code/is_sweet (myMaster)
$ git push test myMaster # 推送到服务器
Logon failed, use ctrl+c to cancel basic credential prompt.
Username for 'https://github.com': Is-Sweet
Password for 'https://Is-Sweet@github.com':
Enumerating objects: 5, done.
Counting objects: 100% (5/5), done.
Delta compression using up to 12 threads
Compressing objects: 100% (2/2), done.
Writing objects: 100% (3/3), 257 bytes | 257.00 KiB/s, done.
Total 3 (delta 1), reused 0 (delta 0), pack-reused 0
remote: Resolving deltas: 100% (1/1), completed with 1 local object.
remote:
remote: Create a pull request for 'myMaster' on GitHub by visiting:
remote: https://github.com/Is-Sweet/test/pull/new/myMaster
remote:
To https://github.com/Is-Sweet/test.git
* [new branch] myMaster -> myMaster
合并分支
在 Git 中使用 git merge 命令用来合并分支,示例代码如下所示:
is_sweet@Sweet MINGW64 /b/Practice code/is_sweet (myMaster)
$ git checkout master # 切换分支
Switched to branch 'master'
Your branch is up to date with 'test/master'.
is_sweet@Sweet MINGW64 /b/Practice code/is_sweet (master)
$ git merge myMaster # 合并 myMaster 到当前分支
Updating b682387..6bdd4fc
Fast-forward
test1.txt | 1 +
1 file changed, 1 insertion(+)
is_sweet@Sweet MINGW64 /b/Practice code/is_sweet (master)
$ git branch -d myMaster # 删除分支
Deleted branch myMaster (was 6bdd4fc).
is_sweet@Sweet MINGW64 /b/Practice code/is_sweet (master)
$ git branch # 查看结果
* master
关于分支的一些命令
# 列出所有本地分支
$ git branch
# 列出所有远程分支
$ git branch -r
# 列出所有本地分支和远程分支
$ git branch -a
# 新建一个分支,但依然停留在当前分支
$ git branch [branch-name]
# 新建一个分支,并切换到该分支
$ git checkout -b [branch]
# 新建一个分支,指向指定commit
$ git branch [branch] [commit]
# 新建一个分支,与指定的远程分支建立追踪关系
$ git branch --track [branch] [remote-branch]
# 切换到指定分支,并更新工作区
$ git checkout [branch-name]
# 切换到上一个分支
$ git checkout -
# 建立追踪关系,在现有分支与指定的远程分支之间
$ git branch --set-upstream [branch] [remote-branch]
# 合并指定分支到当前分支
$ git merge [branch]
# 选择一个commit,合并进当前分支
$ git cherry-pick [commit]
# 删除分支
$ git branch -d [branch-name]
# 删除远程分支
$ git push origin --delete [branch-name]
$ git branch -dr [remote/branch]
写在最后
这篇博客介绍了 Git 的基本用法,Git 是我们在以后的开发中必备的机能,此篇博客也仅仅是 GIt 的入门。