概述
Git 是一个开源的分布式版本控制系统,用于敏捷高效地处理从很小到非常大的项目版本管理。支持克隆/下载。 Git 是 Linus Torvalds 为了帮助管理 Linux 内核开发而开发的一个开放源码的版本控制软件。 Git 与常用的版本控制工具 CVS, Subversion 等不同,它采用了分布式版本库的方式,不必服务器端软件支持。
安装
下载 git OSX 版
下载 git Windows 版
下载 git Linux 版
安装验证
代码语言:javascript复制git -version
原理
你的本地仓库由 git 维护的三棵“树”组成。 第一个是你的
工作目录
,它持有实际文件; 第二个是暂存区(Index)
,它像个缓存区域,临时保存你的改动; 最后是HEAD
,它指向你最后一次提交的结果。工作区:沙箱环境 git 不会管理 随便更改操作
暂存区:记录文件的操作
版本库:最终的代码实现提交到这里 .git 目录就是版本库
配置
Git 操作配置的命令:
代码语言:javascript复制git config
- –system :系统中对所有用户都普遍适用的配置。使用 git config –system 命令会修改/etc/gitconfig 文件。
- –global :用户目录下的配置文件只适用于该用户。使用 git config –global 读写的是~/.gitconfig
- 文件不写参数,表示堆当前项目的 git 目录进行配置,使用 git config 可以直接针对当前项目配置,即工作目录下的.git/config 文件
优先级别以就近原则为准。
代码语言:javascript复制.git/config` > `~/.gitconfig` > `/etc/gitconfig
初始化配置
安装完成后初始化配置用户名和邮件地址:
代码语言:javascript复制git config --_global user.name "ialoe"
git config --_global user.email "ialoe@qq.com"
查看已有配置:
代码语言:javascript复制git config --list
文件大小写问题
现象:文件或文件夹大小写导致找不到文件
git 默认是大小写不敏感的。 如果你大写的文件上次,有可能自己就变小写了。然后访问有可能找不到文件。
查询自己的配置:
代码语言:javascript复制git config --get core.ignorecase
配置开启大小写敏感:
(1)全局开启大小写敏感
代码语言:javascript复制git config --_global core.ignorecase false
(2)单个项目开启大小写敏感
代码语言:javascript复制git config core.ignorecase false
仓库
创建仓库
创建新文件夹,打开,然后执行
git init
以创建新的 Git 仓库。
目录结构
初始化之后,有一个.git
隐藏文件,里面的目录结构大概如下:
文件夹、文件 | 作用 |
---|---|
hooks/ | 目录包含服务端或客户端钩子脚本 |
info/ | 包含一个全局性排除文件 |
logs/ | 保存日志信息 |
objects/ | 目录存储所有数据内容,重要 |
refs/ | 目录存储指向数据提交对象的指针,分支,重要 |
config | 文件包含项目特有的配置选项,重要 |
description | 用来显示对仓库的描述信息 |
HEAD | 文件指示目前被检出的分支,重要 |
index | 文件保存暂缓区信息,重要 |
检出仓库
执行如下命令以创建一个本地仓库的克隆版本:
git clone /path/to/repository
# 将E盘下的Repository克隆到D盘
git clone E:/SourceRepository D:/DestinationRepository
如果是远端服务器上的仓库,你的命令会是这个样子:
git clone username@host:/path/to/repository
已配置账户
git clone git@host:/path/to/repository
# 以我的GitHub的BlogCode仓库为例
git clone git@github.com:ialoe/BlogCode.git
未配置账户
git clone 用户名@github.com:ialoe/BlogCode.git
然后按回车键执行 git clone
命令, Git 会提示你输入密码。
# 以我的GitHub的BlogCode仓库为例
git clone ialoe @ https://github.com/ialoe/BlogCode.git
指定分支
我们可以通过-b 来指定要克隆的分支名
git clone -b <name> git@host:/path/to/repository
添加提交
你可以提出更改(把它们添加到暂存区),使用如下命令:
git add <filename>
或者 git add *
这是 git 基本工作流程的第一步;使用如下命令以实际提交改动:
git commit -m "代码提交信息"
现在,你的改动已经提交到了 HEAD,但是还没到你的远端仓库。
推送改动
你的改动现在已经在本地仓库的 HEAD 中了。执行如下命令以将这些改动提交到远端仓库:
git push origin master
or git push
可以把 master 换成你想要推送的任何分支。
如果你还没有克隆现有仓库,并欲将你的仓库连接到某个远程服务器,你可以使用如下命令添加:
git remote add origin <server>
如此你就能够将你的改动推送到所添加的服务器上去了。
若需强制推送 git push -f
《不建议》
Git 基础命令
git init
初始化工作空间
初始化工作目录命令格式:
代码语言:javascript复制git init
生成 .git
目录,所有 git 需要的数据和资源都存在在这个目录。
git add
跟踪已修改文件到暂存区:
跟踪一个已修改文件到暂存区的命令格式:
代码语言:javascript复制git add ./
git add 命令将修改的文件生成 git 对象,加入暂存区。
过程:将将修改的文件生成成 git 对象,放入版本库,再将 Git 对象加入到暂存区,只是没有生成树对象。在这个过程中,生成 Git 对象是增量式的。
相当于执行了 N 次(N 个文件):
代码语言:javascript复制git hash-object -w
git update-index
git status
跟踪文件状态:
代码语言:javascript复制git status [指定的文件]
status :
untracked
:未跟踪,红色tracked
:已跟踪。unmodified
:未修改,已提交,一般不列出显示。
modified
:已修改,红色staged
: 已暂存,绿色
跟踪新文件:
git add
命令执行之后使用 git status
查看,出现changes to be committed
表示已经暂存。
暂存已修改文件:
已经暂存的文件进行再次修改,使用 git status
查看,此时会出现
changes to be committed
表示该文件之前暂存区有一份,表示已暂存;同时也会出现
changes not staged for commit
表示改文件又有了新的修改。此时已修改文件的状态为modified
;修改之后的 git 对象还没有生成。如果git add
重新暂存,在暂存区则会进行覆盖操作,并重新生成 git 对象的 hash。
git diff
查看已暂存和未暂存的更新:
git status
仅仅列出修改过的文件。
- 判断当前做的哪些更新还没有做暂存:
git diff
- 判断哪些更新已经暂存准备好了下次提交
git diff --cached
# 1.6 以上
git diff --staged
示例:查看哪些暂存还没提交的数据,这是之前操作的数据。
代码语言:javascript复制git diff --cached
diff --git a/bak/xctest.txt b/bak/xctest.txt
new file mode 100644
index 0000000..83baae6
--- /dev/null
b/bak/xctest.txt
@@ -0,0 1 @@
version 1
diff --git a/new.txt b/new.txt
new file mode 100644
index 0000000..eae6142
--- /dev/null
b/new.txt
@@ -0,0 1 @@
new v1
diff --git a/xctest.txt b/xctest.txt
new file mode 100644
index 0000000..0b6ca5d
--- /dev/null
b/xctest.txt
@@ -0,0 1,2 @@
version 1
xiaocai v2
git commit
提交文件:
代码语言:javascript复制git commit
没有参数会进入一个注释文件可以写大段注释。
代码语言:javascript复制git commit -m " messgae info"
-m
一般写短小文字较少的注释。注释建议,带上关键信息,如完成进度,fix bug
2 条命令都是提交项目版本到本地库,生成树对象和提交对象。
相当于执行:
代码语言:javascript复制git write-tree
git commit-tree
跳过使用暂存区域:
代码语言:javascript复制git commit -a -m "xiaocai test"
通过-a
参数,git 可以自动把所有已经跟踪过的文件暂存起来一并提交,从而跳过git add
步骤。
注意:使用 -a 的前提是文件状态要已经被跟踪。
git rm
移除文件:
从 Git 中移除文件,就必须要从已跟踪文件清单中注册删除,其实就是从暂存区注册删除,然后提交。可以使用以下命令完成:
代码语言:javascript复制git rm
该命令将把文件从暂存区注册删除,并且同时从工作目录删除对应的文件,这样文件就不会出现在未跟踪文件清单中。
需要注意的是,删除之后进行git add
和 git commit
操作,对应的 Git 对象永远不会删除,暂存区删除之后,版本库里进行的是新增操作,新增的是一个没有内容的 git 对象和一个树对象。如果要找回,可以找到对应的提交对象 hash,回退即可。
如果我们先手工删除了文件,可以执行git rm
即可,相当于执行了git add ./
和 git commit
也可以手工执行
git add ./
git commit`
其实就是删除工作目录中对应的文件,再将修改添加到暂存区。git rm
git mv
文件改名:
git 文件修改文件名称命令
代码语言:javascript复制# 重命名操作
git mv oldfile.suffix1 newfile.suffix2
使用,新建一个文件然后提交:
代码语言:javascript复制# 新建xiaocai.txt
echo "xiaocai de wen jian" > xiaocai.txt
#git add
git commit -a -m "new a file test"
# 再执行重命名操作
git mv xiaocai.txt xc.txt
git rm
在旧的版本中类似相当于执行了三条命令:
mv xiaocai.txt xc.txt
git rm xiaocai.txt
git add xiaocai.txt
我的 git 版本比较新,新的版本 status 显示的是 renamed,暂时没注意过程,后续清楚了再补上。**TODO**
查看状态,此时是 renamed 状态,属于修改操作,
代码语言:javascript复制git status
On branch master
Changes to be committed:
(use "git reset HEAD <file>..." to unstage)
renamed: xiaocai.txt -> xc.txt
**git mv file1 file2**
其实就是将工作目录中的文件进行重命名,再将修改添加到暂存区。
git log
查看历史记录:
在提交很多更新之后,想回顾查看提交历史,或者回退历史版本时,使用该命令。
代码语言:javascript复制git log
没有参数会按提交时间列出所有更新,最近在上面,倒序排列。
示例:
代码语言:javascript复制$ git log
commit c32a601099e6ca73b910829856bc4b1ba88c014e (HEAD -> master)
Author: small-rose <small-rose@qq.com>
Date: Mon Nov 16 19:57:12 2020 0800
rename xiaocai.txt to xc.txt
commit d57678e00b1dea5ce92817f5ca495c2dc852496c
Author: small-rose <small-rose@qq.com>
Date: Mon Nov 16 19:54:07 2020 0800
new a file test
commit 4e84326e84545905f106975a4ce32eb520b4bc98
Author: small-rose <small-rose@qq.com>
Date: Mon Nov 16 19:46:44 2020 0800
first commit
按下箭头翻页, 按 q
退出。如果要回退,利用提交对象的 hash 即可。
不方便看还可以进行格式化显示:
代码语言:javascript复制git log --pretty=oneline
git log --oneline
效果:
代码语言:javascript复制$ git log --pretty=oneline
c32a601099e6ca73b910829856bc4b1ba88c014e (HEAD -> master) rename xiaocai.txt to xc.txt
d57678e00b1dea5ce92817f5ca495c2dc852496c new a file test
4e84326e84545905f106975a4ce32eb520b4bc98 first commit
$ git log --oneline
c32a601 (HEAD -> master) rename xiaocai.txt to xc.txt
d57678e new a file test
4e84326 first commit
分支
Git 分支模型高效轻量。Git 亮点技能。 分支就是一个提交对象前面的指针,每次提交完成,指针就在提交对象的前面指向最新提交 分支是用来将特性开发绝缘开来的。 在你创建仓库的时候,
master
是“默认的”分支。在其他分支上进行开发,完成后再将它们合并到主分支上。GitHub 已将默认分支 master 更改为 main
创建分支
基础命令
代码语言:javascript复制git branch
没有参数时,显示分支列表。
后面带参数时,表示创建分支命令:
代码语言:javascript复制git branch dev
执行之后,查看日志
代码语言:javascript复制git log --oneline
新建新的分支并切换到该分支上(一步到位式)
代码语言:javascript复制git checkout -b dev_test
# 执行结果
Switched to a new branch 'dev_test'
查看分支
代码语言:javascript复制$ git log --oneline --decorate --graph --all
切换分支
代码语言:javascript复制git checkout dev
切换成功后 Git 的路径会有变化
执行之后,查看日志
代码语言:javascript复制git log --oneline
在新的dev
分支进行操作开发
在文件夹处右键==》Git Bash Here
代码语言:javascript复制git add ./
git commit -m "add dev code "
执行后查看日志
代码语言:javascript复制git log --oneline
37c967e (HEAD -> dev) add dev code
注意事项
- 每次切换分支前,当前分支一定是干净的(所有文件都是已提交状态)。所以在切换分支前使用 git status 命令验证状态。
- 问题发生于在切换分支时,如果当前分支上有未暂存的修改(一般是第一次)或者有未提交的暂存(一般是第一次),分支可以切换成功,但是会对其他分支造成污染。
删除分支
删除之前一定要先切换分支
代码语言:javascript复制git checkout master
切换成功后,显示 master 分支
代码语言:javascript复制git log --oneline
删除分支命令:
代码语言:javascript复制git branch -d name
其他分支相关
查看每个分支最后一次提交
代码语言:javascript复制git branch -v
新建一个分支并且使分支指向对应的提交对象
代码语言:javascript复制git branch name commitHash
代码语言:javascript复制示例 现在创建一个分支想回第一次提交的时候看看代码怎么写的 此时新的 first 分支语句出现了,可以切换过去看看:
# 当前是master分支
git log --oneline
c32a601 (HEAD -> master) rename blog.txt to xc.txt
d57678e new a file test
4e84326 first commit
代码语言:javascript复制git branch first 4e84326
# 新的分支出现了
git log --oneline
c32a601 (HEAD -> master) rename xiaocai.txt to xc.txt
d57678e new a file test
4e84326 (first) first commit
代码语言:javascript复制# 切换分支
git checkout first
Switched to branch 'first'
# 现在进入了 first分支
git log --oneline
4e84326 (HEAD -> first) first commit
查看哪些分支已经合并到当前分支
代码语言:javascript复制git branch -merged
在这个列表中分支名字前面没有*
号的分支通常可以使用git branch -d
删除掉。
查看所有包含未合并工作的分支
代码语言:javascript复制git branch --no-merged
尝试使用git branch -d
删除在这个列表中的分支时会失败。
如果真的确定要删除分支,可以使用git branch -D
进行强制删除。
分支的本质是一个提交对象,HEAD 是一个指针,它默认指向 master,切换分支时,其实就是让 HEAD 指向不同的分支。每次有新的提交时,HEAD 都会带着当前指向的分支一起往前移动。
撤销重置
撤销命令
代码语言:javascript复制git commit -amend
该命令将暂存区的文件提起,如果上次提交以来你还未做任何修改,在你提交后马上执行此命令,那么快照会保持不变,而你所修改的只是提交信息。
如果提交后发现忘记了暂存某些需要的修改,可以像下面这样操作:
代码语言:javascript复制git commit -m 'some desc'
git add forgeotten_file
git commit -amend
最终只会有一个提交,第二次提交将代替第一次提交的结果。
重置命令
代码语言:javascript复制git reset HEAD 文件名
配置别名
Git 没有自动推断命令功能,有些命令比较长,不想每次输入完整的命令,可以通过git config
文件来轻松为每个命令设置一个别名。
git config --global alias.co checkout
git config --global alias.br branch
git config --global alias.cm commit
git config --global alias.st status
如果需要执行git commit
只需要输入 git cm
即可。
对于复杂命令,比如查看完整的分支图的命令:
代码语言:javascript复制git log --oneline --decorate --graph --all
执行结果:
代码语言:javascript复制git log --oneline --decorate --graph --all
* 37c967e (dev) add dev code
* c32a601 (master) rename blog.txt to i.txt
* d57678e new a file test
* 4e84326 (HEAD -> first) first commit
将该命令配置别名时需要带上双引号:
代码语言:javascript复制git config --_global alias.blog "log --oneline --decorate --graph --all"
Git 管理仓库(以 Github 为例)
创建新的仓库然后提交
代码语言:javascript复制echo "# 仓库名" >> README.md
git init
git add README.md
git commit -m "first commit"
git branch -M main
git remote add origin https://github.com/用户名/仓库名.git
git push -u origin main
提交一个已经存在的仓库
代码语言:javascript复制git remote add origin https://github.com/用户名/仓库名.git
git branch -M main
git push -u origin main
Git 的免密使用
客户端生成密钥
代码语言:javascript复制ssh-keygen -t rsa -C "这里换上你的邮箱"
然后会出现询问,大概意思如下:
代码语言:javascript复制1. 确认秘钥的保存路径(如果不需要改路径则直接回车);
2. 如果上一步置顶的保存路径下已经有秘钥文件,则需要确认是否覆盖(如果之前的秘钥不再需要则直接回车覆盖,如需要则手动拷贝到其他目录后再覆盖);
3. 创建密码(如果不需要密码则直接回车);
4. 确认密码;
要免密登录请输密码的时候回车即可。根据提示找到密钥所在文件:
代码语言:javascript复制id_rsa #私钥
id_rsa.pub #公钥
代码语言:javascript复制Github 配置 SSH 公钥登录 git 账户,Setting,SSH and GPG keys, New ssh key 把 id_rsa.pub 的内容粘贴到 key 的文本域,点击 Add SSH key 完成。后续的客户端 git 操作就不要密码了。 然后回到 Git 的命令行界面,测试一下是否与 Github 连接成功。输入下面的命令行: 点击回车,然后会出现一个询问内容,输入
yes
,回车,会出现一段内容,Hi ! You've successfully authenticated, but GitHub doesnot provide shell access.
。 说明连接成功。此处这个 `` 应该是你 Github 的用户名。
ssh -T git@github.com
服务器配置 SSH 免密
注意:这里的 Git 服务器可以是云服务器或者自己的私服务器。本次操作环境是Centos 7
。
1. 客户端生成密钥
注意:同上,如果已经配置过
Github
的 ssh 免密上面已经有了可以不用重复生成,可以直接跳到第二步。
2. 服务端导入客户端公钥
在/home/git 下已经创建.ssh 目录,然后创建 authorized_keys 文件,并将客户端生成的公钥导入进去。
代码语言:javascript复制cd /home/git/
mkdir .ssh
chmod 755 .ssh
touch .ssh/authorized_keys
chmod 644 .ssh/authorized_keys
将 id_rsa.pub
文件的内容写入authorized_keys
3. 服务端SSH
开启RSA
认证
如果没有安装 SSH 服务,请先安装 SSH 服务。
代码语言:javascript复制vim /etc/ssh/sshd_config
其中三个地方的设置要确认如下:
代码语言:javascript复制RSAAuthentication yes
PubkeyAuthentication yes
AuthorizedKeysFile .ssh/authorized_keys
git 用户不允许登录 shell
代码语言:javascript复制vim /etc/passwd
将
代码语言:javascript复制git:x:502:502::/home/git:/bin/bash
改为
代码语言:javascript复制git:x:502:502::/home/git:/usr/local/git/bin/git-shell