Skip to content

git 相关

环境准备

  1. 生成密钥 ssh-keygen -t rsa -C "youremail@example.com"
  2. 配置用户
bash
git config --global user.name "iijx"
git config --global user.email iijx@qq.com
// 上述配置
// 当然,也可以重置
git config --unset --global user.name
git config --unset --global user.email

// 查看所有配置信息
git config --list

// 也可以单独某个环境变量的值
git config user.name

2 .创建工作目录

other
mkdir work_directory
cd work_director\
git init  //该操作将在当前目录下创建一个隐藏文件夹.git作为版本库,同时也意味着以当前目录为工作目录

这里的.git文件夹即为仓库文件夹。

向仓库增加文件

other
echo "Hello" > test.txt // 先生成一个测试文件
git add test.txt // 先加入暂存区
git commit -m "add a file" // 将暂存区一次性全部提交至仓库。 -m 后接提交说明[必需]

当Git提交时,如果不在命令行提供提交说明(使用-m参数),Git会自动打开一个编辑器,要求您在其中输入提交说明,输入完毕后保存并退出

当在Git工作区的某个子目录下执行操作的时候,会在工作区目录中依次向上递归查找.git目录,找到的.git目录就是工作区对应的版本库,.git所在的目录就是工作区的根目录,文件.git/index记录了工作区文件的状态(实际上是暂存区的状态)。

  • git status 查看当前的状态(含工作区,暂存区,仓库)

暂存区

图中的index部分就是我们常说的暂存区。

  • 当对工作区的修改的文件执行git add 命令时,暂存区的目录树就会被更新,同时工作区修改的文件内容会被写入对象库中的一个新对象中,而且该对象的ID被记录在暂存区的文件索引中。
  • 要从暂存区的目录树写到版本库中,用git commit命令,也即master最新的指向的目录树就是暂存区的目录树
  • 要从master分支指向的目录树写入暂存区目录树,用git reset HEAD命令

删除暂存区文件用 git rm --cached 命令

git checkout 或 git checkout 命令,会用暂存区的全部文件或指定的文件替换工作区的文件

git checkout HEAD 或 git checkout 命令,会用HEAD指向的master分支的全部文件或指定文件替换暂存区和工作区的文件

  • 有了暂存区的概念,对于一个文件,很可能在这三个区就有三个不同的版本,因此对于这三个区之间直接的比较:
  1. 工作区与暂存区的比较: git diff
  2. 暂存区与HEAD的比较: git diff --cached
  3. 工作区和HEAD比较: git diff HEAD
  • 删除文件

rm // 删除工作区的文件,这个和git没关系,所有目录下删除文件都是这个命令

git rm --cached // 仅从暂存区中删除文件(即工作区依然存在,意义是不跟踪该文件)

git rm // 删除工作区和暂存区的下的这个文件

从其他仓库中克隆

other
git clone git://github.com/schacon/grit.git
// 上述操作会在当前目录下创建一个grit的目录,并且其中包含一个.git目录,用于保存下载下来的仓库,并取出最新版本于工作区中

// 当然也可以自定义文件名
git clone git://github.com/schacon/grit.git  mygrit

上面例子用的是git://协议,当然git也支持许多其他数据传输协议

打标签(里程碑)

Git 也可以对某一重要版本打上标签。人们在发布某个软件版本(比如 v1.0 等等)的时候,经常这么做。

other
git tag // 列出现有标签
git tag -l 'v1.4.1.*' // 以搜索模式搜索标签
git show <tagname> // 展示某一标签的详细信息

// 创建标签, -a 指定标签名, -m 指定提交说明, -s 指定私钥签名
// [<commit>] 表示提交ID, <tagname>表示标签名
用法1: git tag <tagname [<commit>]
用法2: git tag -a <tagname> [<commit>]
用法3: git tag -m <msg><tagname> [<commit>]
用法4: git tag -s <tagname> [<commit>]
用法5: git tag -u <key-id> <tagname> [<commit>]

分支

HEAD指向当前分支(即当前分支的别名),初始时git使用master作为分支的默认名。

other
git branch testing // 新建"testing"分支
git checkout testing // 切换至testing分支,即HEAD现在指向testing

git checkout -b testing // 一次性完成新建分支并切换至该分支

git branch -d testing // 删除testing分支


git branch -r // 查看所有远程分支
git branch // 查看所有本地分支(其中当前分支会有特殊标记 如*或颜色区分等)

服务器上的git

一个更好的合作方式是应该有一个大家都可以访问的共享仓库,从那里推送和拉取数据。这个共享仓库称之为git服务器。

远程仓库通常只是一个裸仓库( bare repository ), 即一个没有当前工作目录的仓库(也没必要有,因为只是一个合作媒介),也就是你工作目录中的.git目录里面的内容。

将现有仓库导出为裸仓库,只需:

other
git clone -bare  ./myproject  bare_git
// 将 ./myproject 下的.git文件 "复制" 到bare_git(自动新建)目录下,这个bare_git就可以看作是裸仓库

协议

git服务器通常使用四种协议来传输数据:

  • 本地传输
  • SSH传输
  • Git协议
  • HTTP协议

除HTTP协议外,其他协议都要求在服务器端安装并运行Git.

本地协议

指远程仓库就在本地,这时要克隆,推送,获取等,只需:

other
git clone /opt/git/.git  
或者
git clone file:///opt/git/.git

要添加一个本地仓库作为现有git项目的远程仓库,可以这样:

other
git remote add local_proj  /opt/git/.git

SSH协议

唯一一个同时支持读写操作的网络协议,另外两个(http & git)通常只是只读的。通过SSH克隆一个仓库,只需:

other
git clone ssh://user@server/project/.git
或者
git clone user@server:project/.git

// 如果不指明协议:默认协议SSH
// 如果不指明用户:默认以当前用户名连接服务器

git协议

git协议是一个包含在git软件包中的特殊守护进程,监听一个类似于ssh服务的特定接口(9418).打算支持 Git 协议的仓库,需要先创建 git-export-daemon-ok 文件, 它是协议进程提供仓库服务的必要条件 — 但除此之外该服务没有什么安全措施。要么所有人都能克隆 Git 仓库,要么谁也不能。你可以允许推送操作;然而由于没有授权机制,一旦允许该操作,网络上任何一个知道项目 URL 的人将都有推送权限。

因此一般git都设置为只读权限,供其他人查看,同时提供几个ssh接口,然开发者具有推送(写)权限

远程操作

基础设施:

  • 远程仓库(这里用github)
  • 本地git

假设已经在github上创建了一个仓库,叫做learn_git,ssh地址为 git@github.com:iijx/learn_git.git

note: 地址以.git结尾,因为仓库指的就是这个.git文件目录

当远程操作时, 本地git要知道操作哪一个远程仓库,就要求每个远程仓库都必须在本地指定一个名字(很明显,不能重复)

other
git remote // 查看所有远程仓库在本地对应的名字

git remote -v // -v参数,列出远程仓库的网址

git remote add <远程库名称> <地址>  // 向本地添加远程库
git remote add learn_git git@github.com:iijx/learn_git.git

git remote rm <远程库名称> // 在本地删除远程库

git remote rename <原远程库名> <新远程库名> // 更名


git clone -o name <地址> // 克隆一个仓库到本地来, 顺道也会将这个仓库添加到本地,其中-o指定这个仓库名,如果不指定,默认名为origin

git push <远程库名> <本地分支名>:<远程分支名> // 将本地分支推送至远程库
// 如果省略远程分支名,表示将本地分支推送与之存在"追踪关系"的远程分支(通常两者同名),如果该远程分支不存在,则会被新建。