目录

Git 笔记

install

server

1
2
3
4
# download and install 
yum install -y git
# create a git user
sudo adduser git

client

1
2
3
4
5
# download and install 
yum install -y git
# 国内替换 github 镜像
# 使用国内镜像,目前已知Github国内镜像网站有github.com.cnpmjs.org和git.sdut.me
git config --global url."https://github.com.cnpmjs.org/".insteadOf https://github.com/

config

git config 配置级别

级别 参数 对应文件
system 级别, 所有用户生效 –system [Mac] /usr/local/etc/gitconfig
[linux] /etc/gitconfig
对单个用户生效 –global ~/.gitconfig

相关命令

1
2
3
4
# 查看 git 用户配置, 当 pwd 为 git 目录时,额外显示 pwd 的 git 信息
git config --list
# 编辑文件
git config --global --edit

remote url 使用 HTTP 时,记录密码

1
git config --global credential.helper store

显示中文

1
git config --global core.quotepath false

URL 替换

1
2
# 使用 https://github.com.cnpmjs.org/ 替换 https://github.com/
git config --global url."https://github.com.cnpmjs.org/".insteadOf https://github.com/

概念解释

  • git URL

    1
    2
    
    git clone git@host:/*/*.git
    git clone ssh://git@host:port/*/*.git
    
  • 工作区(Working Directory):文件结构目录

  • 版本库(Repository):隐藏目录.git,包含暂存区 state和分支 master

  • 暂存区(state/index):

  • HEAD:当前版本

常用流程

搭建 git 服务器
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
adduser git
# 禁止 git 用户使用 shell 登录
vim /etc/passwd
git:x:1000:1000::/home/git:/bin/git-shell
# 初始化 git 的 ssh
su git
cd /home/git
mkdir .ssh
cd /home/git/.ssh
touch authorized_keys
chmod 700 /home/git/.ssh/
chmod 600 /home/git/.ssh/authorized_keys
添加授权用户至 git 服务器
1
2
3
4
5
# 本地生成ssh-key, 默认情况下生成256位的 ssh-key 至本机的~/.ssh 目录下,其中id_rsa 为秘钥,id_rsa.pub 为公钥
ssh-keygen
# 添加公钥 id_rsa.pub 的内容追加到服务器下
pbcopy < ~/.ssh/id_rsa.pub
echo '$'>> /home/git/.ssh/authorized_keys
本地仓库初始化
1
2
3
4
5
6
git init & vim .gitignore
git add ./ & git status -s
git commit -m "init"
git remote add origin ssh://[user]@[ip]/usr/local/git/[].git
git push --set-upstream origin master
git checkout -b [new branch]
远程仓库初始化流程
1
2
3
4
su git 
mkdir project.git
cd ./project.git
git init --bare
提交至romote
1
2
3
4
git push
# 在初始提交时可设置追踪
git checkout $local_branch
git push --set-upstream origin $remote_branch
忽略已经被 track 的文件或者目录
1
2
3
4
5
6
7
8
# 修改.gitignore,添加要忽略的 pattern
vim .gitignore
# 将所有的文件 unstage
git rm --cached -r ./
# 将所有的文件 stage,符合 .gitignore 的文件不被 stage 或者 在 stage Del
git add ./
# 只有被commit 后才不会反复,否则修改只能保留在本次的 stage 区域
git commit
撤销上次 megre/rebase
1
2
3
# 将分支 reset 到 合并前的commit,commit 一般为HEAD~
# !!!注意:--hard 会覆盖工作目录以及 index
git reset --hard $commit
撤销上次提交!!!仅可在未 push 的情况下使用
1
git reset --soft HEAD~
撤销 git reset –mixed commit1
1
2
3
4
# 查看想要恢复到的 $commit2
git reflog
# 将 HEAD,index,workDir 与 commit2 保持一致
git reset --hard $commit2
重写 commit message
1
git commit -m 'commit message' --amend
基于历史提交检出新分支
1
2
3
4
# 分离 HEAD 到 $commit 
git checkout $commit
# 检出新分支,新分支的 index, workDir 与 commit 同步
git checkout -b $branch_name
文件在工作区,暂存区的添加或回退
1
2
3
4
5
6
7
8
# 文件从工作区到暂存区
git add ./file
# 文件到暂存区到仓库
git commit
# 文件从工作区到暂存区
git reset HEAD
# 丢弃工作区的修改(用版本库里的版本替换工作区的版本)
git checkout -- file
基于远程分支检出本地分支
1
2
3
4
# 方法 1:可以直接 clone 远程分支
git clone git_url -b $remote_branch
# 方法 2:基于远程分支检出本地分支
git checkout -b $local_branch $origin/$remote_branch
删除远程分支
1
git push origin -d $branch
以 rebase 的方式 pull
1
git pull --rebase
查看当前版本的 commitID
git rev-parse HEAD
查看指定 commit log
1
2
3
4
5
6
7
8
# format 可查看 git log --help 搜索PRETTY
# %h short commit hash
# %H full commit hash
# %C(*) * color
# %Creset reset color 
# %d ref names, like the --decorate option of git-log(1)
# %s commit msg
git log --pretty='%C(red)%H%Creset - %C(yellow)%d%Creset %s'|grep $commit
将仓库打包为 zip
1
git archive --format=zip -o latest.zip HEAD
clone 时不下载之前的 git 历史

下载之后使用 git commit 只会输出一条记录

1
git clone --depth=1 $git_url
以压缩包的形式 clone

并非真正的 clone, 仅下载源文件, 没有 .git 文件夹

1
git archive --format=zip -o=test.zip --remote=$git_url

submodule

参考 https://devconnected.com/how-to-add-and-update-git-submodules

添加子模块
1
2
3
4
5
6
# 方法一(推荐)
git submodule add $(remote_url) $(destination_folder)
# 方法二, 使用 .gitmodules
[submodule "$(destination_folder)"]
	path = $(destination_folder)
	url = $(remote_url)
pull/update 子模块
1
2
3
4
# pull Git submodule 
git submodule update --init --recursive
# update existing Git submodule
git submodule update --remote --merge
移除子模块
1
2
3
4
# delete the local submodule configuration;the line referencing the submodule will be deleted from your .git/config file.
git submodule deinit $(submodule) 
#delete submodules files
git rm $(submodule) 

合并commit

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
# 在合并前可以 checkout 一个分支用来备份 log
# 指定合并区间[$(commit),HEAD]
# commit 可以为 HEAD~x,commit_id 
# HEAD~x, x为合并的 commit 数量, 例如 HEAD~6
# 使用 git log 查询 $(commit) 的 id, 例如 3a4226
git rebase -i $(commit)
# 在弹出的 vim 中,修改合并方式
# 例如:除第一个 commit 保留为 pick,其他的 commit 改为 s 或 squash
:wq
# 查看合并结果
git log
# !!!!!! 合并远程分支(会强制覆盖代码,极度危险操作)
git push -f

处理冲突

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
# 如果要取消本次合并,使用该命令.会重置 stage,workDir
git merge --abort
# 查看冲突的文件,前缀为 UU
git status -s
# 修改冲突文件
vim $file
# 将冲突文件标记为正常,添加文件
git add $file
# 完成全部冲突文件的修改
git commit

git diff

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
git diff                                       #比较 工作目录,暂存区                           
git diff HEAD                                  #比较 工作区, HEAD                                  
git diff $commit_id                            #比较 工作区, commit_id                             
                                               
git diff --cached                              #比较 暂存区,上次提交                           
git diff --cached $commit_id                   #比较 暂存区, commit_id                             
                                               
git diff $branch1 $branch2                     #比较 分支1,分支2 所有差异文件的详细差异
git diff $branch1 $branch2 $file               #比较 分支1,分支2 指定文件的详细差异      
git diff $branch1 $branch2 --stat              #比较 分支1,分支2 所有差异文件的列表      
git diff $commit_id1 $commit_id2 -- name-only  #比较 提交1,提交2 所有差异文件的列表

Q&A

WARNING: POSSIBLE DNS SPOOFING DETECTED!

.ssh/known_hosts 存在冲突,解决办法

1
ssh-keygen -f "/root/.ssh/known_hosts" -R "$host"

我们在ssh时,openssh会把访问过计算机的公钥(public key)都记录在~/.ssh/known_hosts。当下次访问相同计算机时,openssh会核对公钥。如果公钥不同,openssh会发出警告,避免你受到DNS Hijack之类的攻击。因此我们现在只需要删除knows_hosts文件中所对应的IP节点的公钥,然后再ssh IP地址就可以了。此处使用git操作远程代码库时,使用的是ssh协议,所以出现了这样的问题

祖先提交与父提交

~ 祖先提交 ^ 父提交

~ 表示纵深位置 ^ 表示横向位置

^0,~0 等价 无该参数
~ 等价 ~1
^ 等价 ^1
^^ 等价 ^2
~~ 等价 ~2

例如

$ git log --graph --oneline

* f44239d D
*   7a3fb3d C
|\
| * 07b920c B
|/
* 71bd2cf A

$ git rev-parse HEAD~
7a3fb3d (C)

$ git rev-parse HEAD~^
71bd2cf (A)

$ git rev-parse HEAD~^0
7a3fb3d (C)

$ git rev-parse HEAD~^2
07b920c (B)

$ git rev-parse HEAD~^3
fatal: ambiguous argument 'HEAD~^3': unknown revision or path not in the working tree.

$ git rev-parse HEAD^2
fatal: ambiguous argument 'HEAD^2': unknown revision or path not in the working tree.